root/OpenSceneGraph/trunk/examples/osgdepthshadow/osgdepthshadow.cpp @ 6234

Revision 6234, 17.6 kB (checked in by robert, 7 years ago)

Added option to use osgShadow::ShadowMap? technique

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