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

Revision 6055, 33.0 kB (checked in by robert, 8 years ago)

Further work on building the rendering back end from the intial traversal of the
scene graph

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osg/ArgumentParser>
2
3#include <osg/LightModel>
4#include <osg/Depth>
5#include <osg/BlendFunc>
6#include <osg/Camera>
7#include <osg/Stencil>
8#include <osg/StencilTwoSided>
9#include <osg/CullFace>
10#include <osg/Geometry>
11#include <osg/Switch>
12
13#include <osgGA/TrackballManipulator>
14#include <osgGA/FlightManipulator>
15#include <osgGA/DriveManipulator>
16#include <osgGA/KeySwitchMatrixManipulator>
17#include <osgGA/AnimationPathManipulator>
18#include <osgGA/TerrainManipulator>
19#include <osgGA/AnimationPathManipulator>
20#include <osgGA/StateSetManipulator>
21
22#include <osgViewer/Viewer>
23#include <osgViewer/StatsHandler>
24
25#include <osgShadow/OccluderGeometry>
26
27#include <osgDB/ReadFile>
28#include <osgDB/WriteFile>
29
30#include <iostream>
31
32class ComputeBoundingBoxVisitor : public osg::NodeVisitor
33{
34public:
35    ComputeBoundingBoxVisitor():
36        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
37    {
38    }
39   
40    virtual void reset()
41    {
42        _matrixStack.clear();
43        _bb.init();
44    }
45   
46    osg::BoundingBox& getBoundingBox() { return _bb; }
47
48    void getPolytope(osg::Polytope& polytope, float margin=0.1) const
49    {
50        float delta = _bb.radius()*margin;
51        polytope.add( osg::Plane(0.0, 0.0, 1.0, -(_bb.zMin()-delta)) );
52        polytope.add( osg::Plane(0.0, 0.0, -1.0, (_bb.zMax()+delta)) );
53
54        polytope.add( osg::Plane(1.0, 0.0, 0.0, -(_bb.xMin()-delta)) );
55        polytope.add( osg::Plane(-1.0, 0.0, 0.0, (_bb.xMax()+delta)) );
56
57        polytope.add( osg::Plane(0.0, 1.0, 0.0, -(_bb.yMin()-delta)) );
58        polytope.add( osg::Plane(0.0, -1.0, 0.0, (_bb.yMax()+delta)) );
59    }
60       
61    void getBase(osg::Polytope& polytope, float margin=0.1) const
62    {
63        float delta = _bb.radius()*margin;
64        polytope.add( osg::Plane(0.0, 0.0, 1.0, -(_bb.zMin()-delta)) );
65    }
66   
67    void apply(osg::Node& node)
68    {
69        traverse(node);
70    }
71   
72    void apply(osg::Transform& transform)
73    {
74        osg::Matrix matrix;
75        if (!_matrixStack.empty()) matrix = _matrixStack.back();
76       
77        transform.computeLocalToWorldMatrix(matrix,this);
78       
79        pushMatrix(matrix);
80       
81        traverse(transform);
82       
83        popMatrix();
84    }
85   
86    void apply(osg::Geode& geode)
87    {
88        for(unsigned int i=0; i<geode.getNumDrawables(); ++i)
89        {
90            apply(geode.getDrawable(i));
91        }
92    }
93   
94    void pushMatrix(osg::Matrix& matrix)
95    {
96        _matrixStack.push_back(matrix);
97    }
98   
99    void popMatrix()
100    {
101        _matrixStack.pop_back();
102    }
103
104    void apply(osg::Drawable* drawable)
105    {
106        if (_matrixStack.empty()) _bb.expandBy(drawable->getBound());
107        else
108        {
109            osg::Matrix& matrix = _matrixStack.back();
110            const osg::BoundingBox& dbb = drawable->getBound();
111            if (dbb.valid())
112            {
113                _bb.expandBy(dbb.corner(0) * matrix);
114                _bb.expandBy(dbb.corner(1) * matrix);
115                _bb.expandBy(dbb.corner(2) * matrix);
116                _bb.expandBy(dbb.corner(3) * matrix);
117                _bb.expandBy(dbb.corner(4) * matrix);
118                _bb.expandBy(dbb.corner(5) * matrix);
119                _bb.expandBy(dbb.corner(6) * matrix);
120                _bb.expandBy(dbb.corner(7) * matrix);
121            }
122        }
123    }
124   
125protected:
126   
127    typedef std::vector<osg::Matrix> MatrixStack;
128
129    MatrixStack         _matrixStack;
130    osg::BoundingBox    _bb;
131};
132
133enum Faces
134{
135    FRONT_FACE = 1,
136    BACK_FACE = 2,
137    LEFT_FACE = 4,
138    RIGHT_FACE = 8,
139    TOP_FACE = 16,
140    BOTTOM_FACE = 32       
141};
142
143osg::Node* createCube(unsigned int mask)
144{
145    osg::Geode* geode = new osg::Geode;
146   
147    osg::Geometry* geometry = new osg::Geometry;
148    geode->addDrawable(geometry);
149   
150    osg::Vec3Array* vertices = new osg::Vec3Array;
151    geometry->setVertexArray(vertices);
152   
153    osg::Vec3Array* normals = new osg::Vec3Array;
154    geometry->setNormalArray(normals);
155    geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
156   
157    osg::Vec4Array* colours = new osg::Vec4Array;
158    geometry->setColorArray(colours);
159    geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
160    colours->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
161   
162   
163    osg::Vec3 origin(0.0f,0.0f,0.0f);
164    osg::Vec3 dx(2.0f,0.0f,0.0f);
165    osg::Vec3 dy(0.0f,1.0f,0.0f);
166    osg::Vec3 dz(0.0f,0.0f,1.0f);
167   
168    osg::Vec3 px(1.0f,0.0,0.0f);
169    osg::Vec3 nx(-1.0f,0.0,0.0f);
170    osg::Vec3 py(0.0f,1.0f,0.0f);
171    osg::Vec3 ny(0.0f,-1.0f,0.0f);
172    osg::Vec3 pz(0.0f,0.0f,1.0f);
173    osg::Vec3 nz(0.0f,0.0f,-1.0f);
174
175    if (mask & FRONT_FACE)
176    {
177        // front face   
178        vertices->push_back(origin);
179        vertices->push_back(origin+dx);
180        vertices->push_back(origin+dx+dz);
181        vertices->push_back(origin+dz);
182        normals->push_back(ny);
183        normals->push_back(ny);
184        normals->push_back(ny);
185        normals->push_back(ny);
186    }
187
188    if (mask & BACK_FACE)
189    {
190        // back face   
191        vertices->push_back(origin+dy);
192        vertices->push_back(origin+dy+dz);
193        vertices->push_back(origin+dy+dx+dz);
194        vertices->push_back(origin+dy+dx);
195        normals->push_back(py);
196        normals->push_back(py);
197        normals->push_back(py);
198        normals->push_back(py);
199    }
200
201    if (mask & LEFT_FACE)
202    {
203        // left face   
204        vertices->push_back(origin+dy);
205        vertices->push_back(origin);
206        vertices->push_back(origin+dz);
207        vertices->push_back(origin+dy+dz);
208        normals->push_back(nx);
209        normals->push_back(nx);
210        normals->push_back(nx);
211        normals->push_back(nx);
212    }
213
214    if (mask & RIGHT_FACE)
215    {
216        // right face   
217        vertices->push_back(origin+dx+dy);
218        vertices->push_back(origin+dx+dy+dz);
219        vertices->push_back(origin+dx+dz);
220        vertices->push_back(origin+dx);
221        normals->push_back(px);
222        normals->push_back(px);
223        normals->push_back(px);
224        normals->push_back(px);
225    }
226
227    if (mask & TOP_FACE)
228    {
229        // top face   
230        vertices->push_back(origin+dz);
231        vertices->push_back(origin+dz+dx);
232        vertices->push_back(origin+dz+dx+dy);
233        vertices->push_back(origin+dz+dy);
234        normals->push_back(pz);
235        normals->push_back(pz);
236        normals->push_back(pz);
237        normals->push_back(pz);
238    }
239
240    if (mask & BOTTOM_FACE)
241    {
242        // bottom face   
243        vertices->push_back(origin);
244        vertices->push_back(origin+dy);
245        vertices->push_back(origin+dx+dy);
246        vertices->push_back(origin+dx);
247        normals->push_back(nz);
248        normals->push_back(nz);
249        normals->push_back(nz);
250        normals->push_back(nz);
251    }
252   
253    geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, vertices->size()));
254
255    return geode;
256}
257
258class SwitchHandler : public osgGA::GUIEventHandler
259{
260public:
261
262    SwitchHandler():
263        _childNum(0) {}
264   
265    virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& /*aa*/, osg::Object* object, osg::NodeVisitor* /*nv*/)
266    {
267        osg::Switch* sw = dynamic_cast<osg::Switch*>(object);
268        if (!sw) return false;
269
270        if (ea.getHandled()) return false;
271       
272        switch(ea.getEventType())
273        {
274            case(osgGA::GUIEventAdapter::KEYDOWN):
275            {
276                if (ea.getKey()=='n')
277                {
278                    ++_childNum;
279                    if (_childNum >= sw->getNumChildren()) _childNum = 0;
280
281                    sw->setSingleChildOn(_childNum);
282                    return true;
283                }               
284                break;
285            }
286            default:
287                break;
288        }
289        return false;
290    }
291
292protected:
293
294    virtual ~SwitchHandler() {}
295    unsigned int    _childNum;
296
297};
298
299osg::Node* createTestModel()
300{
301    osg::Switch* sw = new osg::Switch;
302    sw->setEventCallback(new SwitchHandler);
303   
304    sw->addChild(createCube(FRONT_FACE), true);
305    sw->addChild(createCube(FRONT_FACE | BACK_FACE), false);
306    sw->addChild(createCube(FRONT_FACE | BACK_FACE | LEFT_FACE), false);
307    sw->addChild(createCube(FRONT_FACE | BACK_FACE | LEFT_FACE | RIGHT_FACE), false);
308    sw->addChild(createCube(FRONT_FACE | BACK_FACE | LEFT_FACE | RIGHT_FACE | TOP_FACE), false);
309    sw->addChild(createCube(FRONT_FACE | BACK_FACE | LEFT_FACE | RIGHT_FACE | TOP_FACE | BOTTOM_FACE), false);
310   
311    return sw;
312}
313
314
315
316class ShadowCallback : public osg::NodeCallback
317{
318public:
319
320    osg::Vec4 _lightpos;
321    osg::ref_ptr<osg::StateSet> _ss1;
322    osg::ref_ptr<osg::StateSet> _mainShadowStateSet;
323    osg::ref_ptr<osg::StateSet> _shadowVolumeStateSet;
324    osg::ref_ptr<osg::StateSet> _shadowedSceneStateSet;
325
326    ShadowCallback(osgShadow::ShadowVolumeGeometry::DrawMode drawMode)
327    {
328        osg::Vec4 ambient(0.2,0.2,0.2,1.0);
329        osg::Vec4 diffuse(0.8,0.8,0.8,1.0);
330        osg::Vec4 zero_colour(0.0,0.0,0.0,1.0);
331        _lightpos.set(0.0,0.0,1.0,0.0);
332   
333        // first group, render the depth buffer + ambient light contribution
334        {
335            _ss1 = new osg::StateSet;
336
337            osg::LightModel* lm1 = new osg::LightModel;
338            lm1->setAmbientIntensity(ambient);
339            _ss1->setAttribute(lm1);
340
341            osg::Light* light1 = new osg::Light;
342            light1->setAmbient(ambient);
343            light1->setDiffuse(zero_colour);
344            light1->setPosition(_lightpos);
345            _ss1->setAttributeAndModes(light1, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
346            _ss1->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
347        }
348
349        {
350            _mainShadowStateSet = new osg::StateSet;
351
352            osg::Depth* depth = new osg::Depth;
353            depth->setWriteMask(false);
354            depth->setFunction(osg::Depth::LEQUAL);
355            _mainShadowStateSet->setAttribute(depth);
356            _mainShadowStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
357        }
358
359        {
360            _shadowVolumeStateSet = new osg::StateSet;
361           
362            osg::Depth* depth = new osg::Depth;
363            depth->setWriteMask(false);
364            depth->setFunction(osg::Depth::LEQUAL);
365            _shadowVolumeStateSet->setAttribute(depth);
366            _shadowVolumeStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
367            _shadowVolumeStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
368
369
370            if (drawMode == osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED)
371            {
372                osg::StencilTwoSided* stencil = new osg::StencilTwoSided;
373                stencil->setFunction(osg::StencilTwoSided::BACK, osg::StencilTwoSided::ALWAYS,0,~0u);
374                stencil->setOperation(osg::StencilTwoSided::BACK, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::DECR_WRAP);
375                stencil->setFunction(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::ALWAYS,0,~0u);
376                stencil->setOperation(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::INCR_WRAP);
377
378                osg::ColorMask* colourMask = new osg::ColorMask(false, false, false, false);
379
380                _shadowVolumeStateSet->setAttributeAndModes(stencil,osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
381                _shadowVolumeStateSet->setAttribute(colourMask, osg::StateAttribute::OVERRIDE);
382                _shadowVolumeStateSet->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
383
384
385            }
386            else
387            {
388                osg::Stencil* stencil = new osg::Stencil;
389                stencil->setFunction(osg::Stencil::ALWAYS,0,~0u);
390                stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
391
392                osg::ColorMask* colourMask = new osg::ColorMask(false, false, false, false);
393
394                _shadowVolumeStateSet->setAttributeAndModes(stencil,osg::StateAttribute::ON);
395                _shadowVolumeStateSet->setAttribute(colourMask);
396                _shadowVolumeStateSet->setMode(GL_CULL_FACE,osg::StateAttribute::ON);
397            }
398        }
399
400
401        {
402            _shadowedSceneStateSet = new osg::StateSet;
403
404            osg::Depth* depth = new osg::Depth;
405            depth->setWriteMask(false);
406            depth->setFunction(osg::Depth::LEQUAL);
407            _shadowedSceneStateSet->setAttribute(depth);
408            _shadowedSceneStateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
409            _shadowedSceneStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
410
411
412            osg::LightModel* lm1 = new osg::LightModel;
413            lm1->setAmbientIntensity(zero_colour);
414            _shadowedSceneStateSet->setAttribute(lm1);
415
416            osg::LightSource* lightsource = new osg::LightSource;
417//            lightsource->setLight(light.get());
418
419            osg::Light* light = new osg::Light;
420            light->setAmbient(zero_colour);
421            light->setDiffuse(diffuse);
422            light->setPosition(_lightpos);
423
424            _shadowedSceneStateSet->setMode(GL_LIGHT0, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
425            _shadowedSceneStateSet->setAttribute(light);
426
427            // set up the stencil ops so that only operator on this mirrors stencil value.
428            osg::Stencil* stencil = new osg::Stencil;
429            stencil->setFunction(osg::Stencil::EQUAL,0,~0u);
430            stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
431            _shadowedSceneStateSet->setAttributeAndModes(stencil,osg::StateAttribute::ON);
432
433            osg::BlendFunc* blend = new osg::BlendFunc;
434            blend->setFunction(osg::BlendFunc::ONE, osg::BlendFunc::ONE);
435            _shadowedSceneStateSet->setAttributeAndModes(blend, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
436            _shadowedSceneStateSet->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
437        }
438
439        _ss1->setThreadSafeRefUnref(true);
440        _mainShadowStateSet->setThreadSafeRefUnref(true);
441        _shadowVolumeStateSet->setThreadSafeRefUnref(true);
442        _shadowedSceneStateSet->setThreadSafeRefUnref(true);
443
444    }
445   
446    virtual void operator()(osg::Node* node, osg::NodeVisitor* nv)
447    {
448        osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
449        if (!cv)
450        {
451            traverse(node,nv);
452            return;
453        }
454
455//        osg::notify(osg::NOTICE)<<std::endl<<std::endl<<"Cull callback"<<std::endl;
456
457       
458        osg::ref_ptr<osgUtil::RenderBin> original_bin = cv->getCurrentRenderBin();
459       
460        osg::ref_ptr<osgUtil::RenderBin> new_bin = original_bin->find_or_insert(999,"RenderBin");
461
462        cv->setCurrentRenderBin(new_bin.get());
463
464        traverse(node,nv);
465       
466        cv->setCurrentRenderBin(original_bin.get());
467
468#if 0
469        osg::notify(osg::NOTICE)<<"new_bin->getStateGraphList().size()= "<<new_bin->getStateGraphList().size()<<std::endl;
470        osg::notify(osg::NOTICE)<<"new_bin->getRenderBinList().size()= "<<new_bin->getRenderBinList().size()<<std::endl;
471        osg::notify(osg::NOTICE)<<"new_bin->getRenderLeafList().size()= "<<new_bin->getRenderLeafList().size()<<std::endl;
472       
473       
474        for(osgUtil::RenderBin::RenderBinList::iterator itr = new_bin->getRenderBinList().begin();
475            itr != new_bin->getRenderBinList().end();
476            ++itr)
477        {
478            osg::notify(osg::NOTICE)<<"bin num = "<<itr->first<<std::endl;
479        }
480#endif       
481       
482        osgUtil::RenderBin::RenderBinList::iterator itr =  new_bin->getRenderBinList().find(1000);
483        osg::ref_ptr<osgUtil::RenderBin> shadowVolumeBin;
484        if (itr != new_bin->getRenderBinList().end())
485        {
486            shadowVolumeBin = itr->second;
487           
488            if (shadowVolumeBin.valid())
489            {
490                // osg::notify(osg::NOTICE)<<"Found shadow volume bin, now removing it"<<std::endl;
491                new_bin->getRenderBinList().erase(itr);
492            }
493        }
494       
495#if 0
496        for(osgUtil::RenderBin::RenderBinList::iterator itr = new_bin->getRenderBinList().begin();
497            itr != new_bin->getRenderBinList().end();
498            ++itr)
499        {
500            osg::notify(osg::NOTICE)<<"bin num = "<<itr->first<<std::endl;
501        }
502
503        osg::notify(osg::NOTICE)<<"after new_bin->getStateGraphList().size()= "<<new_bin->getStateGraphList().size()<<std::endl;
504        osg::notify(osg::NOTICE)<<"after new_bin->getRenderBinList().size()= "<<new_bin->getRenderBinList().size()<<std::endl;
505        osg::notify(osg::NOTICE)<<"after new_bin->getRenderLeafList().size()= "<<new_bin->getRenderLeafList().size()<<std::endl;
506#endif
507
508
509        original_bin->setStateSet(_ss1.get());
510
511        osgUtil::RenderStage* orig_rs = cv->getRenderStage();
512        osgUtil::RenderStage* new_rs = new osgUtil::RenderStage;
513        orig_rs->addPostRenderStage(new_rs);
514       
515        new_rs->setViewport(orig_rs->getViewport());
516        new_rs->setClearColor(orig_rs->getClearColor());
517        new_rs->setClearMask(GL_STENCIL_BUFFER_BIT);
518        new_rs->setDrawBuffer(orig_rs->getDrawBuffer());
519        new_rs->setReadBuffer(orig_rs->getReadBuffer());
520        new_rs->setColorMask(orig_rs->getColorMask());
521        new_rs->setPositionalStateContainer(orig_rs->getPositionalStateContainer());
522#if 1
523
524#if 0       
525        osg::notify(osg::NOTICE)<<"orig_rs="<<orig_rs<<std::endl;
526        osg::notify(osg::NOTICE)<<"new_rs="<<new_rs<<std::endl;
527#endif       
528        if (shadowVolumeBin.valid())
529        {
530            // new_rs->setStateSet(_mainShadowStateSet.get());
531            new_rs->getRenderBinList()[0] = shadowVolumeBin;
532            shadowVolumeBin->setStateSet(_shadowVolumeStateSet.get());
533           
534            osg::ref_ptr<osgUtil::RenderBin> nested_bin = new_rs->find_or_insert(1,"RenderBin");
535            nested_bin->getRenderBinList()[0] = new_bin;
536           
537            nested_bin->setStateSet(_shadowedSceneStateSet.get());
538           
539#if 0
540            osg::notify(osg::NOTICE)<<"shadowVolumeBin="<<shadowVolumeBin.get()<<std::endl;
541            osg::notify(osg::NOTICE)<<"nested_bin="<<nested_bin.get()<<std::endl;
542#endif
543        }
544#endif
545
546    }
547};
548
549
550
551int main(int argc, char** argv)
552{
553    // use an ArgumentParser object to manage the program arguments.
554    osg::ArgumentParser arguments(&argc, argv);
555
556    // set up the usage document, in case we need to print out how to use this program.
557    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName() + " is the example which demonstrates using of GL_ARB_shadow extension implemented in osg::Texture class");
558    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName());
559    arguments.getApplicationUsage()->addCommandLineOption("-h or --help", "Display this information");
560    arguments.getApplicationUsage()->addCommandLineOption("--positionalLight", "Use a positional light.");
561    arguments.getApplicationUsage()->addCommandLineOption("--directionalLight", "Use a direction light.");
562    arguments.getApplicationUsage()->addCommandLineOption("--addOccluderToScene", "Add the occluders geometry.");
563    arguments.getApplicationUsage()->addCommandLineOption("--noUpdate", "Disable the updating the of light source.");
564    arguments.getApplicationUsage()->addCommandLineOption("--base", "Add a base geometry to test shadows.");
565    arguments.getApplicationUsage()->addCommandLineOption("--noShadow", "Disable the shadows.");
566    arguments.getApplicationUsage()->addCommandLineOption("--two-sided", "Use two-sided stencil extension for shadow volumes.");
567    arguments.getApplicationUsage()->addCommandLineOption("--two-pass", "Use two-pass stencil for shadow volumes.");
568
569    // hint to tell viewer to request stencil buffer when setting up windows
570    osg::DisplaySettings::instance()->setMinimumNumStencilBits(8);
571
572    // construct the viewer.
573    osgViewer::Viewer viewer;
574
575    // if user request help write it out to cout.
576    if (arguments.read("-h") || arguments.read("--help"))
577    {
578        arguments.getApplicationUsage()->write(std::cout);
579        return 1;
580    }
581
582    bool postionalLight = false;
583    while (arguments.read("--positionalLight")) postionalLight = true;
584    while (arguments.read("--directionalLight")) postionalLight = false;
585
586    bool addOccluderToScene = false;
587    while (arguments.read("--addOccluderToScene")) addOccluderToScene = true;
588
589    bool updateLightPosition = true;
590    while (arguments.read("--noUpdate")) updateLightPosition = false;
591
592    bool createBase = false;
593    while (arguments.read("--base")) createBase = true;
594
595    bool doShadow = true;
596    while (arguments.read("--noShadow")) doShadow = false;
597   
598    bool cullCallback = false;
599    while (arguments.read("-c")) cullCallback = true;
600
601    int screenNum = -1;
602    while (arguments.read("--screen", screenNum)) viewer.setUpViewOnSingleScreen(screenNum);
603
604    osgShadow::ShadowVolumeGeometry::DrawMode drawMode = osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED;
605    while (arguments.read("--two-sided")) drawMode = osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED;
606    while (arguments.read("--two-pass")) drawMode = osgShadow::ShadowVolumeGeometry::STENCIL_TWO_PASS;
607   
608
609    // set up the camera manipulators.
610    {
611        osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
612
613        keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() );
614        keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() );
615        keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() );
616        keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );
617
618        std::string pathfile;
619        char keyForAnimationPath = '5';
620        while (arguments.read("-p",pathfile))
621        {
622            osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile);
623            if (apm || !apm->valid())
624            {
625                unsigned int num = keyswitchManipulator->getNumMatrixManipulators();
626                keyswitchManipulator->addMatrixManipulator( keyForAnimationPath, "Path", apm );
627                keyswitchManipulator->selectMatrixManipulator(num);
628                ++keyForAnimationPath;
629            }
630        }
631
632        viewer.setCameraManipulator( keyswitchManipulator.get() );
633    }
634
635
636    // add the state manipulator
637    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
638
639    // add stats
640    viewer.addEventHandler( new osgViewer::StatsHandler() );
641
642    // any option left unread are converted into errors to write out later.
643    arguments.reportRemainingOptionsAsUnrecognized();
644
645    // report any errors if they have occured when parsing the program aguments.
646    if (arguments.errors())
647    {
648      arguments.writeErrorMessages(std::cout);
649      return 1;
650    }
651
652
653    osg::ref_ptr<osg::Node> model = osgDB::readNodeFiles(arguments);
654    if (!model)
655    {
656        model = createTestModel();
657    }
658
659    // get the bounds of the model.   
660    ComputeBoundingBoxVisitor cbbv;
661    model->accept(cbbv);
662    osg::BoundingBox bb = cbbv.getBoundingBox();
663
664    if (createBase)
665    {
666        osg::ref_ptr<osg::Group> newGroup = new osg::Group;
667        newGroup->addChild(model.get());
668       
669        osg::Geode* geode = new osg::Geode;
670       
671        osg::Vec3 widthVec(bb.radius(), 0.0f, 0.0f);
672        osg::Vec3 depthVec(0.0f, bb.radius(), 0.0f);
673        osg::Vec3 centerBase( (bb.xMin()+bb.xMax())*0.5f, (bb.yMin()+bb.yMax())*0.5f, bb.zMin()-bb.radius()*0.1f );
674       
675        geode->addDrawable( osg::createTexturedQuadGeometry( centerBase-widthVec*1.5f-depthVec*1.5f,
676                                                             widthVec*3.0f, depthVec*3.0f) );
677        newGroup->addChild(geode);
678       
679        model = newGroup.get();
680    }
681
682    // get the bounds of the model.
683    cbbv.reset();
684    model->accept(cbbv);
685    bb = cbbv.getBoundingBox();
686   
687    osg::ref_ptr<osg::Group> group = new osg::Group;
688
689    // set up the occluder
690    osg::ref_ptr<osgShadow::OccluderGeometry> occluder = new osgShadow::OccluderGeometry;
691    occluder->computeOccluderGeometry(model.get());
692//    cbbv.getPolytope(occluder->getBoundingPolytope(),0.001);
693    cbbv.getBase(occluder->getBoundingPolytope(),0.001);
694
695    if (addOccluderToScene)
696    {
697        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
698        geode->addDrawable(occluder.get());
699        group->addChild(geode.get());
700    }
701   
702    osg::ref_ptr<osgShadow::ShadowVolumeGeometry> shadowVolume = new osgShadow::ShadowVolumeGeometry;
703
704    // shadowVolume->setUseDisplayList(!updateLightPosition);
705    shadowVolume->setUseDisplayList(false);
706
707    osg::Vec4 lightpos;
708   
709    if (postionalLight)
710    {
711        lightpos.set(bb.center().x(), bb.center().y(), bb.zMax() + bb.radius()  ,1.0f);
712    }
713    else
714    {
715        lightpos.set(0.5f,0.25f,0.8f,0.0f);
716    }
717
718
719
720    osg::ref_ptr<osg::Light> light = new osg::Light;
721
722    if (!doShadow)
723    {
724        group->addChild(model.get());
725
726        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
727        occluder->computeShadowVolumeGeometry(lightpos, *shadowVolume);
728        geode->addDrawable(shadowVolume.get());
729        group->addChild(geode.get());
730
731        osg::StateSet* ss = geode->getOrCreateStateSet();
732        ss->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
733
734    }
735    else if (cullCallback)
736    {
737   
738        int shadowVolumeBin = 1000;
739   
740        group->setCullCallback(new ShadowCallback(drawMode));
741
742        group->addChild(model.get());
743
744        {
745            osg::ref_ptr<osg::Geode> geode = new osg::Geode;
746            group->addChild(geode.get());
747
748            occluder->computeShadowVolumeGeometry(lightpos, *shadowVolume);
749            shadowVolume->setDrawMode(drawMode);
750
751
752            if (drawMode == osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED)
753            {
754                osg::notify(osg::NOTICE)<<"STENCIL_TWO_SIDED seleteced"<<std::endl;
755
756                osg::StateSet* ss_sv1 = geode->getOrCreateStateSet();
757                ss_sv1->setRenderBinDetails(shadowVolumeBin, "RenderBin");
758                geode->addDrawable(shadowVolume.get());
759            }
760            else
761            {
762                osg::notify(osg::NOTICE)<<"STENCIL_TWO_PASSES seleteced"<<std::endl;
763
764                osg::StateSet* ss_sv1 = geode->getOrCreateStateSet();
765                ss_sv1->setRenderBinDetails(shadowVolumeBin, "RenderBin");
766                geode->addDrawable(shadowVolume.get());
767            }
768
769        }
770
771    }   
772    else
773    {
774        osg::Vec4 ambient(0.2,0.2,0.2,1.0);
775        osg::Vec4 diffuse(0.8,0.8,0.8,1.0);
776        osg::Vec4 zero_colour(0.0,0.0,0.0,1.0);
777   
778        // first group, render the depth buffer + ambient light contribution
779        {
780
781            osg::Group* first_model_group = new osg::Group;
782            first_model_group->addChild(model.get());
783            group->addChild(first_model_group);
784
785            osg::StateSet* ss1 = first_model_group->getOrCreateStateSet();
786
787            osg::LightModel* lm1 = new osg::LightModel;
788            lm1->setAmbientIntensity(ambient);
789            ss1->setAttribute(lm1);
790
791            osg::Light* light1 = new osg::Light;
792            light1->setAmbient(ambient);
793            light1->setDiffuse(zero_colour);
794            light1->setPosition(lightpos);
795            ss1->setAttributeAndModes(light1, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
796            ss1->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
797       
798        }   
799   
800        // second group
801        {
802            // use a camera here just to implement a seperate post rendering stage.
803            osg::Camera* camera = new osg::Camera;
804            camera->setRenderOrder(osg::Camera::POST_RENDER);
805            camera->setClearMask(GL_STENCIL_BUFFER_BIT);
806            group->addChild(camera);
807
808            osg::StateSet* ss_camera = camera->getOrCreateStateSet();
809
810            osg::Depth* depth = new osg::Depth;
811            depth->setWriteMask(false);
812            depth->setFunction(osg::Depth::LEQUAL);
813            ss_camera->setAttribute(depth);
814
815            {
816                osg::ref_ptr<osg::Geode> geode = new osg::Geode;
817                occluder->computeShadowVolumeGeometry(lightpos, *shadowVolume);
818                shadowVolume->setDrawMode(drawMode);
819               
820
821                if (drawMode == osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED)
822                {
823                    osg::notify(osg::NOTICE)<<"STENCIL_TWO_SIDED seleteced"<<std::endl;
824
825                    osg::StencilTwoSided* stencil = new osg::StencilTwoSided;
826                    stencil->setFunction(osg::StencilTwoSided::BACK, osg::StencilTwoSided::ALWAYS,0,~0u);
827                    stencil->setOperation(osg::StencilTwoSided::BACK, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::DECR_WRAP);
828                    stencil->setFunction(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::ALWAYS,0,~0u);
829                    stencil->setOperation(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::INCR_WRAP);
830
831
832                    osg::ColorMask* colourMask = new osg::ColorMask(false, false, false, false);
833
834                    osg::StateSet* ss_sv1 = geode->getOrCreateStateSet();
835                    ss_sv1->setRenderBinDetails(0, "RenderBin");
836                    ss_sv1->setAttributeAndModes(stencil,osg::StateAttribute::ON);
837                    ss_sv1->setAttribute(colourMask);
838                    ss_sv1->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
839                   
840                    geode->addDrawable(shadowVolume.get());
841                   
842                    camera->addChild(geode.get());
843
844                }
845                else
846                {
847                    osg::notify(osg::NOTICE)<<"STENCIL_TWO_PASSES seleteced"<<std::endl;
848
849                    osg::Stencil* stencil = new osg::Stencil;
850                    stencil->setFunction(osg::Stencil::ALWAYS,0,~0u);
851                    stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
852
853                    osg::ColorMask* colourMask = new osg::ColorMask(false, false, false, false);
854
855                    osg::StateSet* ss_sv1 = geode->getOrCreateStateSet();
856                    ss_sv1->setRenderBinDetails(0, "RenderBin");
857                    ss_sv1->setAttributeAndModes(stencil,osg::StateAttribute::ON);
858                    ss_sv1->setAttribute(colourMask);
859                    ss_sv1->setMode(GL_CULL_FACE,osg::StateAttribute::ON);
860                   
861                    geode->addDrawable(shadowVolume.get());
862                   
863                    camera->addChild(geode.get());
864                }
865
866            }
867
868
869            // render scene graph adding contribution of light
870            {
871                osg::Group* second_model_group = new osg::Group;
872                second_model_group->addChild(model.get());
873
874
875                osg::StateSet* ss1 = second_model_group->getOrCreateStateSet();
876                ss1->setRenderBinDetails(5, "RenderBin");
877
878                osg::LightModel* lm1 = new osg::LightModel;
879                lm1->setAmbientIntensity(zero_colour);
880                ss1->setAttribute(lm1);
881
882
883                osg::LightSource* lightsource = new osg::LightSource;
884                lightsource->setLight(light.get());
885                light->setAmbient(zero_colour);
886                light->setDiffuse(diffuse);
887                light->setPosition(lightpos);
888                second_model_group->addChild(lightsource);
889
890                ss1->setMode(GL_LIGHT0, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
891
892                // set up the stencil ops so that only operator on this mirrors stencil value.
893                osg::Stencil* stencil = new osg::Stencil;
894                stencil->setFunction(osg::Stencil::EQUAL,0,~0u);
895                stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
896                ss1->setAttributeAndModes(stencil,osg::StateAttribute::ON);
897
898                osg::BlendFunc* blend = new osg::BlendFunc;
899                blend->setFunction(osg::BlendFunc::ONE, osg::BlendFunc::ONE);
900                ss1->setAttributeAndModes(blend, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
901                ss1->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
902
903                camera->addChild(second_model_group);
904            }
905                   
906        }
907
908    }
909
910
911    viewer.setSceneData(group.get());
912   
913    // create the windows and run the threads.
914    viewer.realize();
915
916    // osgDB::writeNodeFile(*group,"test.osg");
917
918    while (!viewer.done())
919    {
920        if (updateLightPosition)
921        {
922            float t = viewer.getFrameStamp()->getSimulationTime();
923            if (postionalLight)
924            {
925                lightpos.set(bb.center().x()+sinf(t)*bb.radius(), bb.center().y() + cosf(t)*bb.radius(), bb.zMax() + bb.radius()  ,1.0f);
926            }
927            else
928            {
929                lightpos.set(sinf(t),cosf(t),0.8f,0.0f);
930            }
931            light->setPosition(lightpos);
932            occluder->computeShadowVolumeGeometry(lightpos, *shadowVolume);
933        }
934
935        viewer.frame();
936    }
937   
938    return 0;
939}
Note: See TracBrowser for help on using the browser.