root/OpenSceneGraph/trunk/examples/osgshadow/osgshadow.cpp @ 5641

Revision 5641, 17.8 kB (checked in by robert, 8 years ago)

First cut at class interfaces and stubs for implementations for the new osgShadow NodeKit?

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osgProducer/Viewer>
2
3#include <osg/Projection>
4#include <osg/Geometry>
5#include <osg/Texture>
6#include <osg/TexGen>
7#include <osg/Geode>
8#include <osg/ShapeDrawable>
9#include <osg/PolygonOffset>
10#include <osg/Texture2D>
11#include <osg/MatrixTransform>
12#include <osg/Light>
13#include <osg/LightSource>
14#include <osg/PolygonOffset>
15#include <osg/CullFace>
16#include <osg/Material>
17#include <osg/TexEnvCombine>
18#include <osg/TexEnv>
19
20#include <osg/CameraNode>
21#include <osg/TexGenNode>
22
23#include <osgDB/ReadFile>
24
25using namespace osg;
26
27class LightTransformCallback: public osg::NodeCallback
28{
29
30public:
31
32  LightTransformCallback(float angular_velocity, float height, float radius):
33    _angular_velocity(angular_velocity),
34    _height(height),
35    _radius(radius),
36    _previous_traversal_number(-1),
37    _previous_time(-1.0f),
38    _angle(0)
39  {
40  }
41
42  void operator()(Node* node, NodeVisitor* nv);
43
44protected:
45   
46  float                                  _angular_velocity;
47  float                                  _height;
48  float                                  _radius;
49  int                                    _previous_traversal_number;
50  double                                 _previous_time;
51  float                                  _angle;
52};
53
54
55void 
56LightTransformCallback::operator()(Node* node, NodeVisitor* nv)
57{
58  MatrixTransform* transform = dynamic_cast<MatrixTransform*>(node);
59  if (nv && transform)
60    {
61      const FrameStamp* fs = nv->getFrameStamp();
62      if (!fs) return; // not frame stamp, no handle on the time so can't move.
63       
64      double new_time = fs->getReferenceTime();
65      if (nv->getTraversalNumber() != _previous_traversal_number)
66        {
67          _angle += _angular_velocity * (new_time - _previous_time);
68
69          Matrix matrix = Matrix::rotate(atan(_height / _radius), -X_AXIS) *
70            Matrix::rotate(PI_2, Y_AXIS) *
71            Matrix::translate(Vec3(_radius, 0, 0)) *
72            Matrix::rotate(_angle, Y_AXIS) *
73            Matrix::translate(Vec3(0, _height, 0));
74
75          // update the specified transform
76          transform->setMatrix(matrix);
77
78          _previous_traversal_number = nv->getTraversalNumber();
79        }
80
81      _previous_time = new_time;
82    }
83
84  // must call any nested node callbacks and continue subgraph traversal.
85  traverse(node,nv);
86
87}
88
89
90ref_ptr<MatrixTransform> _create_lights()
91{
92  ref_ptr<MatrixTransform> transform_0 = new MatrixTransform;
93
94  // create a spot light.
95  ref_ptr<Light> light_0 = new Light;
96  light_0->setLightNum(0);
97  light_0->setPosition(Vec4(0, 0, 0, 1.0f));
98  light_0->setAmbient(Vec4(0.0f, 0.0f, 0.0f, 1.0f));
99  light_0->setDiffuse(Vec4(1.0f, 0.8f, 0.8f, 1.0f));
100  light_0->setSpotCutoff(60.0f);
101  light_0->setSpotExponent(2.0f);
102
103  ref_ptr<LightSource> light_source_0 = new LightSource;   
104  light_source_0->setLight(light_0.get());
105  light_source_0->setLocalStateSetModes(StateAttribute::ON);
106  transform_0->setUpdateCallback(new LightTransformCallback(inDegrees(90.0f), 8, 5));
107  transform_0->addChild(light_source_0.get());
108
109  ref_ptr<Geode> geode = new Geode;
110
111  ref_ptr<ShapeDrawable> shape;
112  ref_ptr<TessellationHints> hints = new TessellationHints;
113  hints->setDetailRatio(0.3f);
114  shape = new ShapeDrawable(new Sphere(Vec3(0.0f, 0.0f, 0.0f), 0.15f), hints.get());
115  shape->setColor(Vec4(1.0f, 0.5f, 0.5f, 1.0f));
116  geode->addDrawable(shape.get());
117  shape = new ShapeDrawable(new Cylinder(Vec3(0.0f, 0.0f, -0.4f), 0.05f, 0.8f), hints.get());
118  shape->setColor(Vec4(1.0f, 0.5f, 0.5f, 1.0f));
119  geode->addDrawable(shape.get());
120
121
122  geode->getOrCreateStateSet()->setMode(GL_LIGHTING, StateAttribute::OFF);
123  transform_0->addChild(geode.get());
124
125  return transform_0;
126}
127
128ref_ptr<Group> _create_scene()
129{
130  ref_ptr<Group> scene = new Group;
131  ref_ptr<Geode> geode_1 = new Geode;
132  scene->addChild(geode_1.get());
133
134  ref_ptr<Geode> geode_2 = new Geode;
135  ref_ptr<MatrixTransform> transform_2 = new MatrixTransform;
136  transform_2->addChild(geode_2.get());
137  transform_2->setUpdateCallback(new osg::AnimationPathCallback(Vec3(0, 0, 0), Y_AXIS, inDegrees(45.0f)));
138  scene->addChild(transform_2.get());
139
140  ref_ptr<Geode> geode_3 = new Geode;
141  ref_ptr<MatrixTransform> transform_3 = new MatrixTransform;
142  transform_3->addChild(geode_3.get());
143  transform_3->setUpdateCallback(new osg::AnimationPathCallback(Vec3(0, 0, 0), Y_AXIS, inDegrees(-22.5f)));
144  scene->addChild(transform_3.get());
145
146  const float radius = 0.8f;
147  const float height = 1.0f;
148  ref_ptr<TessellationHints> hints = new TessellationHints;
149  hints->setDetailRatio(2.0f);
150  ref_ptr<ShapeDrawable> shape;
151
152  shape = new ShapeDrawable(new Box(Vec3(0.0f, -2.0f, 0.0f), 10, 0.1f, 10), hints.get());
153  shape->setColor(Vec4(0.5f, 0.5f, 0.7f, 1.0f));
154  geode_1->addDrawable(shape.get());
155
156  shape = new ShapeDrawable(new Sphere(Vec3(0.0f, 0.0f, 0.0f), radius * 2), hints.get());
157  shape->setColor(Vec4(0.8f, 0.8f, 0.8f, 1.0f));
158  geode_1->addDrawable(shape.get());
159
160  shape = new ShapeDrawable(new Sphere(Vec3(-3.0f, 0.0f, 0.0f), radius), hints.get());
161  shape->setColor(Vec4(0.6f, 0.8f, 0.8f, 1.0f));
162  geode_2->addDrawable(shape.get());
163
164  shape = new ShapeDrawable(new Box(Vec3(3.0f, 0.0f, 0.0f), 2 * radius), hints.get());
165  shape->setColor(Vec4(0.4f, 0.9f, 0.3f, 1.0f));
166  geode_2->addDrawable(shape.get());
167
168  shape = new ShapeDrawable(new Cone(Vec3(0.0f, 0.0f, -3.0f), radius, height), hints.get());
169  shape->setColor(Vec4(0.2f, 0.5f, 0.7f, 1.0f));
170  geode_2->addDrawable(shape.get());
171
172  shape = new ShapeDrawable(new Cylinder(Vec3(0.0f, 0.0f, 3.0f), radius, height), hints.get());
173  shape->setColor(Vec4(1.0f, 0.3f, 0.3f, 1.0f));
174  geode_2->addDrawable(shape.get());
175
176  shape = new ShapeDrawable(new Box(Vec3(0.0f, 3.0f, 0.0f), 2, 0.1f, 2), hints.get());
177  shape->setColor(Vec4(0.8f, 0.8f, 0.4f, 1.0f));
178  geode_3->addDrawable(shape.get());
179
180  // material
181  ref_ptr<Material> matirial = new Material;
182  matirial->setColorMode(Material::DIFFUSE);
183  matirial->setAmbient(Material::FRONT_AND_BACK, Vec4(0, 0, 0, 1));
184  matirial->setSpecular(Material::FRONT_AND_BACK, Vec4(1, 1, 1, 1));
185  matirial->setShininess(Material::FRONT_AND_BACK, 64.0f);
186  scene->getOrCreateStateSet()->setAttributeAndModes(matirial.get(), StateAttribute::ON);
187
188  return scene;
189}
190
191
192class UpdateCameraAndTexGenCallback : public osg::NodeCallback
193{
194    public:
195   
196        UpdateCameraAndTexGenCallback(osg::MatrixTransform* light_transform, osg::CameraNode* cameraNode, osg::TexGenNode* texgenNode):
197            _light_transform(light_transform),
198            _cameraNode(cameraNode),
199            _texgenNode(texgenNode)
200        {
201        }
202       
203        virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
204        {
205            // first update subgraph to make sure objects are all moved into postion
206            traverse(node,nv);
207           
208            // now compute the camera's view and projection matrix to point at the shadower (the camera's children)
209            osg::BoundingSphere bs;
210            for(unsigned int i=0; i<_cameraNode->getNumChildren(); ++i)
211            {
212                bs.expandBy(_cameraNode->getChild(i)->getBound());
213            }
214           
215            if (!bs.valid())
216            {
217                osg::notify(osg::WARN) << "bb invalid"<<_cameraNode.get()<<std::endl;
218                return;
219            }
220           
221            osg::Vec3 position = _light_transform->getMatrix().getTrans();
222
223            float centerDistance = (position-bs.center()).length();
224
225            float znear = centerDistance-bs.radius();
226            float zfar  = centerDistance+bs.radius();
227            float zNearRatio = 0.001f;
228            if (znear<zfar*zNearRatio) znear = zfar*zNearRatio;
229
230#if 0
231            // hack to illustrate the precision problems of excessive gap between near far range.
232            znear = 0.00001*zfar;
233#endif
234            float top   = (bs.radius()/centerDistance)*znear;
235            float right = top;
236
237            _cameraNode->setReferenceFrame(osg::CameraNode::ABSOLUTE_RF);
238            _cameraNode->setProjectionMatrixAsFrustum(-right,right,-top,top,znear,zfar);
239            _cameraNode->setViewMatrixAsLookAt(position,bs.center(),osg::Vec3(0.0f,1.0f,0.0f));
240
241            // compute the matrix which takes a vertex from local coords into tex coords
242            // will use this later to specify osg::TexGen..
243            osg::Matrix MVPT = _cameraNode->getViewMatrix() *
244                               _cameraNode->getProjectionMatrix() *
245                               osg::Matrix::translate(1.0,1.0,1.0) *
246                               osg::Matrix::scale(0.5f,0.5f,0.5f);
247                               
248            _texgenNode->getTexGen()->setMode(osg::TexGen::EYE_LINEAR);
249            _texgenNode->getTexGen()->setPlanesFromMatrix(MVPT);
250
251        }
252       
253    protected:
254   
255        virtual ~UpdateCameraAndTexGenCallback() {}
256       
257        osg::ref_ptr<osg::MatrixTransform>  _light_transform;
258        osg::ref_ptr<osg::CameraNode>       _cameraNode;
259        osg::ref_ptr<osg::TexGenNode>       _texgenNode;
260
261};
262
263//////////////////////////////////////////////////////////////////
264// fragment shader
265//
266char fragmentShaderSource_noBaseTexture[] =
267    "uniform sampler2DShadow shadowTexture; \n"
268    "uniform vec2 ambientBias; \n"
269    "\n"
270    "void main(void) \n"
271    "{ \n"
272    "    gl_FragColor = gl_Color * (ambientBias.x + shadow2DProj( shadowTexture, gl_TexCoord[0] ) * ambientBias.y); \n"
273    "}\n";
274
275//////////////////////////////////////////////////////////////////
276// fragment shader
277//
278char fragmentShaderSource_withBaseTexture[] =
279    "uniform sampler2D baseTexture; \n"
280    "uniform sampler2DShadow shadowTexture; \n"
281    "uniform vec2 ambientBias; \n"
282    "\n"
283    "void main(void) \n"
284    "{ \n"
285    "    vec4 color = gl_Color * texture2D( baseTexture, gl_TexCoord[0].xy ); \n"
286    "    gl_FragColor = color * (ambientBias.x + shadow2DProj( shadowTexture, gl_TexCoord[1] ) * ambientBias.y); \n"
287    "}\n";
288
289
290osg::Group* createShadowedScene(osg::Node* shadowed,osg::MatrixTransform* light_transform, unsigned int unit)
291{
292    osg::Group* group = new osg::Group;
293   
294    unsigned int tex_width = 1024;
295    unsigned int tex_height = 1024;
296   
297    osg::Texture2D* texture = new osg::Texture2D;
298    texture->setTextureSize(tex_width, tex_height);
299
300    texture->setInternalFormat(GL_DEPTH_COMPONENT);
301    texture->setShadowComparison(true);
302    texture->setShadowTextureMode(Texture::LUMINANCE);
303    texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
304    texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
305   
306    // set up the render to texture camera.
307    {
308
309        // create the camera
310        osg::CameraNode* camera = new osg::CameraNode;
311
312        camera->setClearMask(GL_DEPTH_BUFFER_BIT);
313        camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
314        camera->setComputeNearFarMode(osg::CameraNode::DO_NOT_COMPUTE_NEAR_FAR);
315
316        // set viewport
317        camera->setViewport(0,0,tex_width,tex_height);
318
319        osg::StateSet*  _local_stateset = camera->getOrCreateStateSet();
320
321        _local_stateset->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
322
323
324        float factor = 0.0f;
325        float units = 1.0f;
326
327        ref_ptr<PolygonOffset> polygon_offset = new PolygonOffset;
328        polygon_offset->setFactor(factor);
329        polygon_offset->setUnits(units);
330        _local_stateset->setAttribute(polygon_offset.get(), StateAttribute::ON | StateAttribute::OVERRIDE);
331        _local_stateset->setMode(GL_POLYGON_OFFSET_FILL, StateAttribute::ON | StateAttribute::OVERRIDE);
332
333        ref_ptr<CullFace> cull_face = new CullFace;
334        cull_face->setMode(CullFace::FRONT);
335        _local_stateset->setAttribute(cull_face.get(), StateAttribute::ON | StateAttribute::OVERRIDE);
336        _local_stateset->setMode(GL_CULL_FACE, StateAttribute::ON | StateAttribute::OVERRIDE);
337
338
339        // set the camera to render before the main camera.
340        camera->setRenderOrder(osg::CameraNode::PRE_RENDER);
341
342        // tell the camera to use OpenGL frame buffer object where supported.
343        camera->setRenderTargetImplementation(osg::CameraNode::FRAME_BUFFER_OBJECT);
344
345        // attach the texture and use it as the color buffer.
346        camera->attach(osg::CameraNode::DEPTH_BUFFER, texture);
347
348        // add subgraph to render
349        camera->addChild(shadowed);
350       
351        group->addChild(camera);
352       
353        // create the texgen node to project the tex coords onto the subgraph
354        osg::TexGenNode* texgenNode = new osg::TexGenNode;
355        texgenNode->setTextureUnit(unit);
356        group->addChild(texgenNode);
357
358        // set an update callback to keep moving the camera and tex gen in the right direction.
359        group->setUpdateCallback(new UpdateCameraAndTexGenCallback(light_transform, camera, texgenNode));
360    }
361   
362
363    // set the shadowed subgraph so that it uses the texture and tex gen settings.   
364    {
365        osg::Group* shadowedGroup = new osg::Group;
366        shadowedGroup->addChild(shadowed);
367        group->addChild(shadowedGroup);
368               
369        osg::StateSet* stateset = shadowedGroup->getOrCreateStateSet();
370        stateset->setTextureAttributeAndModes(unit,texture,osg::StateAttribute::ON);
371        stateset->setTextureMode(unit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
372        stateset->setTextureMode(unit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
373        stateset->setTextureMode(unit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
374
375        stateset->setTextureMode(unit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON);
376
377        osg::Program* program = new osg::Program;
378        stateset->setAttribute(program);
379
380        if (unit==0)
381        {
382            osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_noBaseTexture);
383            program->addShader(fragment_shader);
384
385            osg::Uniform* shadowTextureSampler = new osg::Uniform("shadowTexture",(int)unit);
386            stateset->addUniform(shadowTextureSampler);
387        }
388        else
389        {
390            osg::Shader* fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_withBaseTexture);
391            program->addShader(fragment_shader);
392
393            osg::Uniform* baseTextureSampler = new osg::Uniform("baseTexture",0);
394            stateset->addUniform(baseTextureSampler);
395
396            osg::Uniform* shadowTextureSampler = new osg::Uniform("shadowTexture",(int)unit);
397            stateset->addUniform(shadowTextureSampler);
398        }
399       
400        osg::Uniform* ambientBias = new osg::Uniform("ambientBias",osg::Vec2(0.3f,1.2f));
401        stateset->addUniform(ambientBias);
402
403    }
404   
405    // add the shadower and shadowed.
406    group->addChild(light_transform);
407   
408    return group;
409}
410
411
412int main(int argc, char** argv)
413{
414    // use an ArgumentParser object to manage the program arguments.
415    ArgumentParser arguments(&argc, argv);
416
417    // set up the usage document, in case we need to print out how to use this program.
418    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName() + " is the example which demonstrates using of GL_ARB_shadow extension implemented in osg::Texture class");
419    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName());
420    arguments.getApplicationUsage()->addCommandLineOption("-h or --help", "Display this information");
421    arguments.getApplicationUsage()->addCommandLineOption("--with-base-texture", "Adde base texture to shadowed model.");
422    arguments.getApplicationUsage()->addCommandLineOption("--no-base-texture", "Adde base texture to shadowed model.");
423
424    // construct the viewer.
425    osgProducer::Viewer viewer(arguments);
426
427    // set up the value with sensible default event handlers.
428    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
429
430    // get details on keyboard and mouse bindings used by the viewer.
431    viewer.getUsage(*arguments. getApplicationUsage());
432
433    bool withBaseTexture = true;
434    while(arguments.read("--with-base-texture")) { withBaseTexture = true; }
435    while(arguments.read("--no-base-texture")) { withBaseTexture = false; }
436
437    // if user request help write it out to cout.
438    if (arguments.read("-h") || arguments.read("--help"))
439    {
440        arguments.getApplicationUsage()->write(std::cout);
441        return 1;
442    }
443
444    // any option left unread are converted into errors to write out later.
445    arguments.reportRemainingOptionsAsUnrecognized();
446
447    // report any errors if they have occured when parsing the program aguments.
448    if (arguments.errors())
449    {
450      arguments.writeErrorMessages(std::cout);
451      return 1;
452    }
453
454    ref_ptr<MatrixTransform> scene = new MatrixTransform;
455    scene->setMatrix(osg::Matrix::rotate(osg::DegreesToRadians(125.0),1.0,0.0,0.0));
456
457    ref_ptr<Group> shadowed_scene = _create_scene();   
458    if (!shadowed_scene.valid()) return 1;
459
460    ref_ptr<MatrixTransform> light_transform = _create_lights();
461    if (!light_transform.valid()) return 1;
462
463    ref_ptr<Group> shadowedScene;
464   
465   
466    if (withBaseTexture)
467    {
468        shadowed_scene->getOrCreateStateSet()->setTextureAttributeAndModes( 0, new osg::Texture2D(osgDB::readImageFile("Images/lz.rgb")), osg::StateAttribute::ON);
469        shadowedScene = createShadowedScene(shadowed_scene.get(),light_transform.get(),1);
470    }
471    else
472    {
473        shadowedScene = createShadowedScene(shadowed_scene.get(),light_transform.get(),0);
474    }
475   
476    scene->addChild(shadowedScene.get());
477
478    viewer.setSceneData(scene.get());
479
480    // create the windows and run the threads.
481    viewer.realize();
482
483    while (!viewer.done())
484    {
485      // wait for all cull and draw threads to complete.
486      viewer.sync();
487
488      // update the scene by traversing it with the the update visitor which will
489      // call all node update callbacks and animations.
490      viewer.update();
491         
492      // fire off the cull and draw traversals of the scene.
493      viewer.frame();
494    }
495   
496    // wait for all cull and draw threads to complete.
497    viewer.sync();
498
499    // run a clean up frame to delete all OpenGL objects.
500    viewer.cleanup_frame();
501
502    // wait for all the clean up frame to complete.
503    viewer.sync();
504
505    return 0;
506}
Note: See TracBrowser for help on using the browser.