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

Revision 6051, 14.1 kB (checked in by robert, 7 years ago)

Added osg::FrameStamp::set/getSimulationTime().

Added setting of osg_SimulationTime and osg_DeltaSimulationTime to the uniforms set by SceneView?

Added frame(double simulationTime) and advance(double simulationTime) parameters to
osgViewer::SimpleViewer?, Vewer and CompositeViewer?.

Updated various examples and Nodes to use SimulationTime? where appropriate.

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