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

Revision 6138, 31.9 kB (checked in by robert, 8 years ago)

Moved the basic ShadowVolume? code into osgShadow

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