root/OpenSceneGraph/trunk/examples/osgshaders/GL2Scene.cpp @ 6941

Revision 6941, 14.5 kB (checked in by robert, 7 years ago)

From Martin Lavery and Robert Osfield, Updated examples to use a variation of the MIT License

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* OpenSceneGraph example, osgshaders.
2*
3*  Permission is hereby granted, free of charge, to any person obtaining a copy
4*  of this software and associated documentation files (the "Software"), to deal
5*  in the Software without restriction, including without limitation the rights
6*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*  copies of the Software, and to permit persons to whom the Software is
8*  furnished to do so, subject to the following conditions:
9*
10*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16*  THE SOFTWARE.
17*/
18
19/* file:        examples/osgshaders/GL2Scene.cpp
20 * author:        Mike Weiblen 2005-05-01
21 *
22 * Compose a scene of several instances of a model, with a different
23 * OpenGL Shading Language shader applied to each.
24 *
25 * See http://www.3dlabs.com/opengl2/ for more information regarding
26 * the OpenGL Shading Language.
27*/
28
29#include <osg/ShapeDrawable>
30#include <osg/PositionAttitudeTransform>
31#include <osg/Geode>
32#include <osg/Node>
33#include <osg/Material>
34#include <osg/Notify>
35#include <osg/Vec3>
36#include <osg/Texture1D>
37#include <osg/Texture2D>
38#include <osg/Texture3D>
39#include <osgDB/ReadFile>
40#include <osgDB/FileUtils>
41#include <osgUtil/Optimizer>
42
43#include <osg/Program>
44#include <osg/Shader>
45#include <osg/Uniform>
46
47#include <iostream>
48
49#include "GL2Scene.h"
50#include "Noise.h"
51
52///////////////////////////////////////////////////////////////////////////
53///////////////////////////////////////////////////////////////////////////
54
55static osg::Image*
56make3DNoiseImage(int texSize)
57{
58    osg::Image* image = new osg::Image;
59    image->setImage(texSize, texSize, texSize,
60            4, GL_RGBA, GL_UNSIGNED_BYTE,
61            new unsigned char[4 * texSize * texSize * texSize],
62            osg::Image::USE_NEW_DELETE);
63
64    const int startFrequency = 4;
65    const int numOctaves = 4;
66
67    int f, i, j, k, inc;
68    double ni[3];
69    double inci, incj, inck;
70    int frequency = startFrequency;
71    GLubyte *ptr;
72    double amp = 0.5;
73
74    osg::notify(osg::INFO) << "creating 3D noise texture... ";
75
76    for (f = 0, inc = 0; f < numOctaves; ++f, frequency *= 2, ++inc, amp *= 0.5)
77    {
78        SetNoiseFrequency(frequency);
79        ptr = image->data();
80        ni[0] = ni[1] = ni[2] = 0;
81
82        inci = 1.0 / (texSize / frequency);
83        for (i = 0; i < texSize; ++i, ni[0] += inci)
84        {
85            incj = 1.0 / (texSize / frequency);
86            for (j = 0; j < texSize; ++j, ni[1] += incj)
87            {
88                inck = 1.0 / (texSize / frequency);
89                for (k = 0; k < texSize; ++k, ni[2] += inck, ptr += 4)
90                {
91                    *(ptr+inc) = (GLubyte) (((noise3(ni) + 1.0) * amp) * 128.0);
92                }
93            }
94        }
95    }
96
97    osg::notify(osg::INFO) << "DONE" << std::endl;
98    return image;       
99}
100
101static osg::Texture3D*
102make3DNoiseTexture(int texSize )
103{
104    osg::Texture3D* noiseTexture = new osg::Texture3D;
105    noiseTexture->setFilter(osg::Texture3D::MIN_FILTER, osg::Texture3D::LINEAR);
106    noiseTexture->setFilter(osg::Texture3D::MAG_FILTER, osg::Texture3D::LINEAR);
107    noiseTexture->setWrap(osg::Texture3D::WRAP_S, osg::Texture3D::REPEAT);
108    noiseTexture->setWrap(osg::Texture3D::WRAP_T, osg::Texture3D::REPEAT);
109    noiseTexture->setWrap(osg::Texture3D::WRAP_R, osg::Texture3D::REPEAT);
110    noiseTexture->setImage( make3DNoiseImage(texSize) );
111    return noiseTexture;
112}
113
114///////////////////////////////////////////////////////////////////////////
115
116static osg::Image*
117make1DSineImage( int texSize )
118{
119    const float PI = 3.1415927;
120
121    osg::Image* image = new osg::Image;
122    image->setImage(texSize, 1, 1,
123            4, GL_RGBA, GL_UNSIGNED_BYTE,
124            new unsigned char[4 * texSize],
125            osg::Image::USE_NEW_DELETE);
126
127    GLubyte* ptr = image->data();
128    float inc = 2. * PI / (float)texSize;
129    for(int i = 0; i < texSize; i++)
130    {
131        *ptr++ = (GLubyte)((sinf(i * inc) * 0.5 + 0.5) * 255.);
132        *ptr++ = 0;
133        *ptr++ = 0;
134        *ptr++ = 1;
135    }
136    return image;       
137}
138
139static osg::Texture1D*
140make1DSineTexture( int texSize )
141{
142    osg::Texture1D* sineTexture = new osg::Texture1D;
143    sineTexture->setWrap(osg::Texture1D::WRAP_S, osg::Texture1D::REPEAT);
144    sineTexture->setFilter(osg::Texture1D::MIN_FILTER, osg::Texture1D::LINEAR);
145    sineTexture->setFilter(osg::Texture1D::MAG_FILTER, osg::Texture1D::LINEAR);
146    sineTexture->setImage( make1DSineImage(texSize) );
147    return sineTexture;
148}
149
150///////////////////////////////////////////////////////////////////////////
151// in-line GLSL source code for the "microshader" example
152
153static const char *microshaderVertSource = {
154    "// microshader - colors a fragment based on its position\n"
155    "varying vec4 color;\n"
156    "void main(void)\n"
157    "{\n"
158    "    color = gl_Vertex;\n"
159    "    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
160    "}\n"
161};
162
163static const char *microshaderFragSource = {
164    "varying vec4 color;\n"
165    "void main(void)\n"
166    "{\n"
167    "    gl_FragColor = clamp( color, 0.0, 1.0 );\n"
168    "}\n"
169};
170
171///////////////////////////////////////////////////////////////////////////
172
173static osg::ref_ptr<osg::Group> rootNode;
174
175// Create some geometry upon which to render GLSL shaders.
176static osg::Geode*
177CreateModel()
178{
179    osg::Geode* geode = new osg::Geode();
180    geode->addDrawable(new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0f,0.0f,0.0f),1.0f)));
181    geode->addDrawable(new osg::ShapeDrawable(new osg::Cone(osg::Vec3(2.2f,0.0f,-0.4f),0.9f,1.8f)));
182    geode->addDrawable(new osg::ShapeDrawable(new osg::Cylinder(osg::Vec3(4.4f,0.0f,0.0f),1.0f,1.4f)));
183    return geode;
184}
185
186// Add a reference to the masterModel at the specified translation, and
187// return its StateSet so we can easily attach StateAttributes.
188static osg::StateSet*
189ModelInstance()
190{
191    static float zvalue = 0.0f;
192    static osg::Node* masterModel = CreateModel();
193
194    osg::PositionAttitudeTransform* xform = new osg::PositionAttitudeTransform();
195    xform->setPosition(osg::Vec3( 0.0f, -1.0f, zvalue ));
196    zvalue = zvalue + 2.2f;
197    xform->addChild(masterModel);
198    rootNode->addChild(xform);
199    return xform->getOrCreateStateSet();
200}
201
202// load source from a file.
203static void
204LoadShaderSource( osg::Shader* shader, const std::string& fileName )
205{
206    std::string fqFileName = osgDB::findDataFile(fileName);
207    if( fqFileName.length() != 0 )
208    {
209        shader->loadShaderSourceFromFile( fqFileName.c_str() );
210    }
211    else
212    {
213        osg::notify(osg::WARN) << "File \"" << fileName << "\" not found." << std::endl;
214    }
215}
216
217
218///////////////////////////////////////////////////////////////////////////
219// rude but convenient globals
220
221static osg::Program* BlockyProgram;
222static osg::Shader*  BlockyVertObj;
223static osg::Shader*  BlockyFragObj;
224
225static osg::Program* ErodedProgram;
226static osg::Shader*  ErodedVertObj;
227static osg::Shader*  ErodedFragObj;
228
229static osg::Program* MarbleProgram;
230static osg::Shader*  MarbleVertObj;
231static osg::Shader*  MarbleFragObj;
232
233
234///////////////////////////////////////////////////////////////////////////
235// for demo simplicity, this one callback animates all the shaders, instancing
236// for each uniform but with a specific operation each time.
237
238class AnimateCallback: public osg::Uniform::Callback
239{
240    public:
241   
242        enum Operation
243        {
244            OFFSET,
245            SIN,
246            COLOR1,
247            COLOR2           
248        };
249   
250        AnimateCallback(Operation op) : _enabled(true),_operation(op) {}
251
252        virtual void operator() ( osg::Uniform* uniform, osg::NodeVisitor* nv )
253        {
254            if( _enabled )
255            {
256                float angle = 2.0 * nv->getFrameStamp()->getSimulationTime();
257                float sine = sinf( angle );        // -1 -> 1
258                float v01 = 0.5f * sine + 0.5f;        //  0 -> 1
259                float v10 = 1.0f - v01;                //  1 -> 0
260                switch(_operation)
261                {
262                    case OFFSET : uniform->set( osg::Vec3(0.505f, 0.8f*v01, 0.0f) ); break;
263                    case SIN : uniform->set( sine ); break;
264                    case COLOR1 : uniform->set( osg::Vec3(v10, 0.0f, 0.0f) ); break;
265                    case COLOR2 : uniform->set( osg::Vec3(v01, v01, v10) ); break;
266                }
267            }
268        }
269
270    private:
271        bool _enabled;
272        Operation _operation;
273};
274
275///////////////////////////////////////////////////////////////////////////
276// Compose a scenegraph with examples of GLSL shaders
277
278#define TEXUNIT_SINE        1
279#define TEXUNIT_NOISE        2
280
281osg::ref_ptr<osg::Group>
282GL2Scene::buildScene()
283{
284    osg::Texture3D* noiseTexture = make3DNoiseTexture( 32 /*128*/ );
285    osg::Texture1D* sineTexture = make1DSineTexture( 32 /*1024*/ );
286
287    // the root of our scenegraph.
288    rootNode = new osg::Group;
289
290    // attach some Uniforms to the root, to be inherited by Programs.
291    {
292        osg::Uniform* OffsetUniform = new osg::Uniform( "Offset", osg::Vec3(0.0f, 0.0f, 0.0f) );
293        osg::Uniform* SineUniform   = new osg::Uniform( "Sine", 0.0f );
294        osg::Uniform* Color1Uniform = new osg::Uniform( "Color1", osg::Vec3(0.0f, 0.0f, 0.0f) );
295        osg::Uniform* Color2Uniform = new osg::Uniform( "Color2", osg::Vec3(0.0f, 0.0f, 0.0f) );
296
297        OffsetUniform->setUpdateCallback(new AnimateCallback(AnimateCallback::OFFSET));
298        SineUniform->setUpdateCallback(new AnimateCallback(AnimateCallback::SIN));
299        Color1Uniform->setUpdateCallback(new AnimateCallback(AnimateCallback::COLOR1));
300        Color2Uniform->setUpdateCallback(new AnimateCallback(AnimateCallback::COLOR2));
301
302        osg::StateSet* ss = rootNode->getOrCreateStateSet();
303        ss->addUniform( OffsetUniform );
304        ss->addUniform( SineUniform );
305        ss->addUniform( Color1Uniform );
306        ss->addUniform( Color2Uniform );
307    }
308
309    // the simple Microshader (its source appears earlier in this file)
310    {
311        osg::StateSet* ss = ModelInstance();
312        osg::Program* program = new osg::Program;
313        program->setName( "microshader" );
314        _programList.push_back( program );
315        program->addShader( new osg::Shader( osg::Shader::VERTEX, microshaderVertSource ) );
316        program->addShader( new osg::Shader( osg::Shader::FRAGMENT, microshaderFragSource ) );
317        ss->setAttributeAndModes( program, osg::StateAttribute::ON );
318    }
319
320    // the "blocky" shader, a simple animation test
321    {
322        osg::StateSet* ss = ModelInstance();
323        BlockyProgram = new osg::Program;
324        BlockyProgram->setName( "blocky" );
325        _programList.push_back( BlockyProgram );
326        BlockyVertObj = new osg::Shader( osg::Shader::VERTEX );
327        BlockyFragObj = new osg::Shader( osg::Shader::FRAGMENT );
328        BlockyProgram->addShader( BlockyFragObj );
329        BlockyProgram->addShader( BlockyVertObj );
330        ss->setAttributeAndModes(BlockyProgram, osg::StateAttribute::ON);
331    }
332
333    // the "eroded" shader, uses a noise texture to discard fragments
334    {
335        osg::StateSet* ss = ModelInstance();
336        ss->setTextureAttribute(TEXUNIT_NOISE, noiseTexture);
337        ErodedProgram = new osg::Program;
338        ErodedProgram->setName( "eroded" );
339        _programList.push_back( ErodedProgram );
340        ErodedVertObj = new osg::Shader( osg::Shader::VERTEX );
341        ErodedFragObj = new osg::Shader( osg::Shader::FRAGMENT );
342        ErodedProgram->addShader( ErodedFragObj );
343        ErodedProgram->addShader( ErodedVertObj );
344        ss->setAttributeAndModes(ErodedProgram, osg::StateAttribute::ON);
345
346        ss->addUniform( new osg::Uniform("LightPosition", osg::Vec3(0.0f, 0.0f, 4.0f)) );
347        ss->addUniform( new osg::Uniform("Scale", 1.0f) );
348        ss->addUniform( new osg::Uniform("sampler3d", TEXUNIT_NOISE) );
349    }
350
351    // the "marble" shader, uses two textures
352    {
353        osg::StateSet* ss = ModelInstance();
354        ss->setTextureAttribute(TEXUNIT_NOISE, noiseTexture);
355        ss->setTextureAttribute(TEXUNIT_SINE, sineTexture);
356        MarbleProgram = new osg::Program;
357        MarbleProgram->setName( "marble" );
358        _programList.push_back( MarbleProgram );
359        MarbleVertObj = new osg::Shader( osg::Shader::VERTEX );
360        MarbleFragObj = new osg::Shader( osg::Shader::FRAGMENT );
361        MarbleProgram->addShader( MarbleFragObj );
362        MarbleProgram->addShader( MarbleVertObj );
363        ss->setAttributeAndModes(MarbleProgram, osg::StateAttribute::ON);
364
365        ss->addUniform( new osg::Uniform("NoiseTex", TEXUNIT_NOISE) );
366        ss->addUniform( new osg::Uniform("SineTex", TEXUNIT_SINE) );
367    }
368
369#ifdef INTERNAL_3DLABS //[
370    // regular GL 1.x texturing for comparison.
371    osg::StateSet* ss = ModelInstance();
372    osg::Texture2D* tex0 = new osg::Texture2D;
373    tex0->setImage( osgDB::readImageFile( "images/3dl-ge100.png" ) );
374    ss->setTextureAttributeAndModes(0, tex0, osg::StateAttribute::ON);
375#endif //]
376
377    reloadShaderSource();
378
379#ifdef INTERNAL_3DLABS //[
380    // add logo overlays
381    rootNode->addChild( osgDB::readNodeFile( "3dl_ogl.logo" ) );
382#endif //]
383
384    return rootNode;
385}
386
387///////////////////////////////////////////////////////////////////////////
388///////////////////////////////////////////////////////////////////////////
389
390GL2Scene::GL2Scene()
391{
392    _rootNode = buildScene();
393    _shadersEnabled = true;
394}
395
396GL2Scene::~GL2Scene()
397{
398}
399
400void
401GL2Scene::reloadShaderSource()
402{
403    osg::notify(osg::INFO) << "reloadShaderSource()" << std::endl;
404
405    LoadShaderSource( BlockyVertObj, "shaders/blocky.vert" );
406    LoadShaderSource( BlockyFragObj, "shaders/blocky.frag" );
407
408    LoadShaderSource( ErodedVertObj, "shaders/eroded.vert" );
409    LoadShaderSource( ErodedFragObj, "shaders/eroded.frag" );
410
411    LoadShaderSource( MarbleVertObj, "shaders/marble.vert" );
412    LoadShaderSource( MarbleFragObj, "shaders/marble.frag" );
413}
414
415
416// mew 2003-09-19 : TODO Need to revisit how to better control
417// osg::Program enable state in OSG core.  glProgram are
418// different enough from other GL state that StateSet::setAttributeAndModes()
419// doesn't fit well, so came up with a local implementation.
420void
421GL2Scene::toggleShaderEnable()
422{
423    _shadersEnabled = ! _shadersEnabled;
424    osg::notify(osg::WARN) << "shader enable = " <<
425            ((_shadersEnabled) ? "ON" : "OFF") << std::endl;
426    for( unsigned int i = 0; i < _programList.size(); i++ )
427    {
428        //_programList[i]->enable( _shadersEnabled );
429    }
430}
431
432/*EOF*/
Note: See TracBrowser for help on using the browser.