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

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