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

Revision 6039, 17.2 kB (checked in by robert, 7 years ago)

Commented out the default saving of models

  • 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
12#include <osgGA/TrackballManipulator>
13#include <osgGA/FlightManipulator>
14#include <osgGA/DriveManipulator>
15#include <osgGA/KeySwitchMatrixManipulator>
16#include <osgGA/AnimationPathManipulator>
17#include <osgGA/TerrainManipulator>
18#include <osgGA/AnimationPathManipulator>
19#include <osgGA/StateSetManipulator>
20
21#include <osgViewer/Viewer>
22#include <osgViewer/StatsHandler>
23
24#include <osgShadow/OccluderGeometry>
25
26#include <osgDB/ReadFile>
27#include <osgDB/WriteFile>
28
29#include <iostream>
30
31class ComputeBoundingBoxVisitor : public osg::NodeVisitor
32{
33public:
34    ComputeBoundingBoxVisitor():
35        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
36    {
37    }
38   
39    virtual void reset()
40    {
41        _matrixStack.clear();
42        _bb.init();
43    }
44   
45    osg::BoundingBox& getBoundingBox() { return _bb; }
46
47    void getPolytope(osg::Polytope& polytope, float margin=0.1) const
48    {
49        float delta = _bb.radius()*margin;
50        polytope.add( osg::Plane(0.0, 0.0, 1.0, -(_bb.zMin()-delta)) );
51        polytope.add( osg::Plane(0.0, 0.0, -1.0, (_bb.zMax()+delta)) );
52
53        polytope.add( osg::Plane(1.0, 0.0, 0.0, -(_bb.xMin()-delta)) );
54        polytope.add( osg::Plane(-1.0, 0.0, 0.0, (_bb.xMax()+delta)) );
55
56        polytope.add( osg::Plane(0.0, 1.0, 0.0, -(_bb.yMin()-delta)) );
57        polytope.add( osg::Plane(0.0, -1.0, 0.0, (_bb.yMax()+delta)) );
58    }
59       
60    void getBase(osg::Polytope& polytope, float margin=0.1) const
61    {
62        float delta = _bb.radius()*margin;
63        polytope.add( osg::Plane(0.0, 0.0, 1.0, -(_bb.zMin()-delta)) );
64    }
65   
66    void apply(osg::Node& node)
67    {
68        traverse(node);
69    }
70   
71    void apply(osg::Transform& transform)
72    {
73        osg::Matrix matrix;
74        if (!_matrixStack.empty()) matrix = _matrixStack.back();
75       
76        transform.computeLocalToWorldMatrix(matrix,this);
77       
78        pushMatrix(matrix);
79       
80        traverse(transform);
81       
82        popMatrix();
83    }
84   
85    void apply(osg::Geode& geode)
86    {
87        for(unsigned int i=0; i<geode.getNumDrawables(); ++i)
88        {
89            apply(geode.getDrawable(i));
90        }
91    }
92   
93    void pushMatrix(osg::Matrix& matrix)
94    {
95        _matrixStack.push_back(matrix);
96    }
97   
98    void popMatrix()
99    {
100        _matrixStack.pop_back();
101    }
102
103    void apply(osg::Drawable* drawable)
104    {
105        if (_matrixStack.empty()) _bb.expandBy(drawable->getBound());
106        else
107        {
108            osg::Matrix& matrix = _matrixStack.back();
109            const osg::BoundingBox& dbb = drawable->getBound();
110            if (dbb.valid())
111            {
112                _bb.expandBy(dbb.corner(0) * matrix);
113                _bb.expandBy(dbb.corner(1) * matrix);
114                _bb.expandBy(dbb.corner(2) * matrix);
115                _bb.expandBy(dbb.corner(3) * matrix);
116                _bb.expandBy(dbb.corner(4) * matrix);
117                _bb.expandBy(dbb.corner(5) * matrix);
118                _bb.expandBy(dbb.corner(6) * matrix);
119                _bb.expandBy(dbb.corner(7) * matrix);
120            }
121        }
122    }
123   
124protected:
125   
126    typedef std::vector<osg::Matrix> MatrixStack;
127
128    MatrixStack         _matrixStack;
129    osg::BoundingBox    _bb;
130};
131
132
133
134int main(int argc, char** argv)
135{
136    // use an ArgumentParser object to manage the program arguments.
137    osg::ArgumentParser arguments(&argc, argv);
138
139    // set up the usage document, in case we need to print out how to use this program.
140    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName() + " is the example which demonstrates using of GL_ARB_shadow extension implemented in osg::Texture class");
141    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName());
142    arguments.getApplicationUsage()->addCommandLineOption("-h or --help", "Display this information");
143    arguments.getApplicationUsage()->addCommandLineOption("--positionalLight", "Use a positional light.");
144    arguments.getApplicationUsage()->addCommandLineOption("--directionalLight", "Use a direction light.");
145    arguments.getApplicationUsage()->addCommandLineOption("--addOccluderToScene", "Add the occluders geometry.");
146    arguments.getApplicationUsage()->addCommandLineOption("--noUpdate", "Disable the updating the of light source.");
147    arguments.getApplicationUsage()->addCommandLineOption("--base", "Add a base geometry to test shadows.");
148    arguments.getApplicationUsage()->addCommandLineOption("--noShadow", "Disable the shadows.");
149    arguments.getApplicationUsage()->addCommandLineOption("--two-sided", "Use two-sided stencil extension for shadow volumes.");
150    arguments.getApplicationUsage()->addCommandLineOption("--two-pass", "Use two-pass stencil for shadow volumes.");
151
152    // hint to tell viewer to request stencil buffer when setting up windows
153    osg::DisplaySettings::instance()->setMinimumNumStencilBits(8);
154
155    // construct the viewer.
156    osgViewer::Viewer viewer;
157
158    // if user request help write it out to cout.
159    if (arguments.read("-h") || arguments.read("--help"))
160    {
161        arguments.getApplicationUsage()->write(std::cout);
162        return 1;
163    }
164
165    bool postionalLight = false;
166    while (arguments.read("--positionalLight")) postionalLight = true;
167    while (arguments.read("--directionalLight")) postionalLight = false;
168
169    bool addOccluderToScene = false;
170    while (arguments.read("--addOccluderToScene")) addOccluderToScene = true;
171
172    bool updateLightPosition = true;
173    while (arguments.read("--noUpdate")) updateLightPosition = false;
174
175    bool createBase = false;
176    while (arguments.read("--base")) createBase = true;
177
178    bool doShadow = true;
179    while (arguments.read("--noShadow")) doShadow = false;
180   
181    int screenNum = -1;
182    while (arguments.read("--screen", screenNum)) viewer.setUpViewOnSingleScreen(screenNum);
183
184    osgShadow::ShadowVolumeGeometry::DrawMode drawMode = osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED;
185    while (arguments.read("--two-sided")) drawMode = osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED;
186    while (arguments.read("--two-pass")) drawMode = osgShadow::ShadowVolumeGeometry::STENCIL_TWO_PASS;
187   
188
189    // set up the camera manipulators.
190    {
191        osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
192
193        keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() );
194        keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() );
195        keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() );
196        keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );
197
198        std::string pathfile;
199        char keyForAnimationPath = '5';
200        while (arguments.read("-p",pathfile))
201        {
202            osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile);
203            if (apm || !apm->valid())
204            {
205                unsigned int num = keyswitchManipulator->getNumMatrixManipulators();
206                keyswitchManipulator->addMatrixManipulator( keyForAnimationPath, "Path", apm );
207                keyswitchManipulator->selectMatrixManipulator(num);
208                ++keyForAnimationPath;
209            }
210        }
211
212        viewer.setCameraManipulator( keyswitchManipulator.get() );
213    }
214
215
216    // add the state manipulator
217    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
218
219    // add stats
220    viewer.addEventHandler( new osgViewer::StatsHandler() );
221
222    // any option left unread are converted into errors to write out later.
223    arguments.reportRemainingOptionsAsUnrecognized();
224
225    // report any errors if they have occured when parsing the program aguments.
226    if (arguments.errors())
227    {
228      arguments.writeErrorMessages(std::cout);
229      return 1;
230    }
231
232
233    osg::ref_ptr<osg::Node> model = osgDB::readNodeFiles(arguments);
234    if (!model)
235    {
236        osg::notify(osg::NOTICE)<<"No model loaded, please specify a model to load."<<std::endl;
237        return 1;
238    }
239
240    // get the bounds of the model.   
241    ComputeBoundingBoxVisitor cbbv;
242    model->accept(cbbv);
243    osg::BoundingBox bb = cbbv.getBoundingBox();
244
245    if (createBase)
246    {
247        osg::ref_ptr<osg::Group> newGroup = new osg::Group;
248        newGroup->addChild(model.get());
249       
250        osg::Geode* geode = new osg::Geode;
251       
252        osg::Vec3 widthVec(bb.radius(), 0.0f, 0.0f);
253        osg::Vec3 depthVec(0.0f, bb.radius(), 0.0f);
254        osg::Vec3 centerBase( (bb.xMin()+bb.xMax())*0.5f, (bb.yMin()+bb.yMax())*0.5f, bb.zMin()-bb.radius()*0.1f );
255       
256        geode->addDrawable( osg::createTexturedQuadGeometry( centerBase-widthVec*1.5f-depthVec*1.5f,
257                                                             widthVec*3.0f, depthVec*3.0f) );
258        newGroup->addChild(geode);
259       
260        model = newGroup.get();
261    }
262
263    // get the bounds of the model.
264    cbbv.reset();
265    model->accept(cbbv);
266    bb = cbbv.getBoundingBox();
267   
268    osg::ref_ptr<osg::Group> group = new osg::Group;
269
270    // set up the occluder
271    osg::ref_ptr<osgShadow::OccluderGeometry> occluder = new osgShadow::OccluderGeometry;
272    occluder->computeOccluderGeometry(model.get());
273//    cbbv.getPolytope(occluder->getBoundingPolytope(),0.001);
274    cbbv.getBase(occluder->getBoundingPolytope(),0.001);
275
276    if (addOccluderToScene)
277    {
278        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
279        geode->addDrawable(occluder.get());
280        group->addChild(geode.get());
281    }
282   
283    osg::ref_ptr<osgShadow::ShadowVolumeGeometry> shadowVolume = new osgShadow::ShadowVolumeGeometry;
284
285    // shadowVolume->setUseDisplayList(!updateLightPosition);
286    shadowVolume->setUseDisplayList(false);
287
288    osg::Vec4 lightpos;
289   
290    if (postionalLight)
291    {
292        lightpos.set(bb.center().x(), bb.center().y(), bb.zMax() + bb.radius()  ,1.0f);
293    }
294    else
295    {
296        lightpos.set(0.5f,0.25f,0.8f,0.0f);
297    }
298
299
300
301    osg::ref_ptr<osg::Light> light = new osg::Light;
302
303    if (!doShadow)
304    {
305        group->addChild(model.get());
306
307        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
308        occluder->computeShadowVolumeGeometry(lightpos, *shadowVolume);
309        geode->addDrawable(shadowVolume.get());
310        group->addChild(geode.get());
311
312        osg::StateSet* ss = geode->getOrCreateStateSet();
313        ss->setAttributeAndModes(new osg::CullFace(osg::CullFace::BACK), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
314
315    }
316    else
317    {
318        osg::Vec4 ambient(0.2,0.2,0.2,1.0);
319        osg::Vec4 diffuse(0.8,0.8,0.8,1.0);
320        osg::Vec4 zero_colour(0.0,0.0,0.0,1.0);
321   
322        // first group, render the depth buffer + ambient light contribution
323        {
324
325            osg::Group* first_model_group = new osg::Group;
326            first_model_group->addChild(model.get());
327            group->addChild(first_model_group);
328
329            osg::StateSet* ss1 = first_model_group->getOrCreateStateSet();
330
331            osg::LightModel* lm1 = new osg::LightModel;
332            lm1->setAmbientIntensity(ambient);
333            ss1->setAttribute(lm1);
334
335            osg::Light* light1 = new osg::Light;
336            light1->setAmbient(ambient);
337            light1->setDiffuse(zero_colour);
338            light1->setPosition(lightpos);
339            ss1->setAttributeAndModes(light1, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
340            ss1->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
341       
342        }   
343   
344        // second group
345        {
346            // use a camera here just to implement a seperate post rendering stage.
347            osg::Camera* camera = new osg::Camera;
348            camera->setRenderOrder(osg::Camera::POST_RENDER);
349            camera->setClearMask(GL_STENCIL_BUFFER_BIT);
350            group->addChild(camera);
351
352            osg::StateSet* ss_camera = camera->getOrCreateStateSet();
353
354            osg::Depth* depth = new osg::Depth;
355            depth->setWriteMask(false);
356            depth->setFunction(osg::Depth::LEQUAL);
357            ss_camera->setAttribute(depth);
358
359            {
360                osg::ref_ptr<osg::Geode> geode = new osg::Geode;
361                occluder->computeShadowVolumeGeometry(lightpos, *shadowVolume);
362                shadowVolume->setDrawMode(drawMode);
363               
364
365                if (drawMode == osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED)
366                {
367                    osg::notify(osg::NOTICE)<<"STENCIL_TWO_SIDED seleteced"<<std::endl;
368
369                    osg::StencilTwoSided* stencil = new osg::StencilTwoSided;
370                    stencil->setFunction(osg::StencilTwoSided::BACK, osg::StencilTwoSided::ALWAYS,0,~0u);
371                    stencil->setOperation(osg::StencilTwoSided::BACK, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::DECR_WRAP);
372                    stencil->setFunction(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::ALWAYS,0,~0u);
373                    stencil->setOperation(osg::StencilTwoSided::FRONT, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::KEEP, osg::StencilTwoSided::INCR_WRAP);
374
375
376                    osg::ColorMask* colourMask = new osg::ColorMask(false, false, false, false);
377
378                    osg::StateSet* ss_sv1 = geode->getOrCreateStateSet();
379                    ss_sv1->setRenderBinDetails(0, "RenderBin");
380                    ss_sv1->setAttributeAndModes(stencil,osg::StateAttribute::ON);
381                    ss_sv1->setAttribute(colourMask);
382                    ss_sv1->setMode(GL_CULL_FACE,osg::StateAttribute::OFF);
383                   
384                    geode->addDrawable(shadowVolume.get());
385                   
386                    camera->addChild(geode.get());
387
388                }
389                else
390                {
391                    osg::notify(osg::NOTICE)<<"STENCIL_TWO_PASSES seleteced"<<std::endl;
392
393                    osg::Stencil* stencil = new osg::Stencil;
394                    stencil->setFunction(osg::Stencil::ALWAYS,0,~0u);
395                    stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
396
397                    osg::ColorMask* colourMask = new osg::ColorMask(false, false, false, false);
398
399                    osg::StateSet* ss_sv1 = geode->getOrCreateStateSet();
400                    ss_sv1->setRenderBinDetails(0, "RenderBin");
401                    ss_sv1->setAttributeAndModes(stencil,osg::StateAttribute::ON);
402                    ss_sv1->setAttribute(colourMask);
403                    ss_sv1->setMode(GL_CULL_FACE,osg::StateAttribute::ON);
404                   
405                    geode->addDrawable(shadowVolume.get());
406                   
407                    camera->addChild(geode.get());
408                }
409
410            }
411
412
413            // render scene graph adding contribution of light
414            {
415                osg::Group* second_model_group = new osg::Group;
416                second_model_group->addChild(model.get());
417
418
419                osg::StateSet* ss1 = second_model_group->getOrCreateStateSet();
420                ss1->setRenderBinDetails(5, "RenderBin");
421
422                osg::LightModel* lm1 = new osg::LightModel;
423                lm1->setAmbientIntensity(zero_colour);
424                ss1->setAttribute(lm1);
425
426
427                osg::LightSource* lightsource = new osg::LightSource;
428                lightsource->setLight(light.get());
429                light->setAmbient(zero_colour);
430                light->setDiffuse(diffuse);
431                light->setPosition(lightpos);
432                second_model_group->addChild(lightsource);
433
434                ss1->setMode(GL_LIGHT0, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
435
436                // set up the stencil ops so that only operator on this mirrors stencil value.
437                osg::Stencil* stencil = new osg::Stencil;
438                stencil->setFunction(osg::Stencil::EQUAL,0,~0u);
439                stencil->setOperation(osg::Stencil::KEEP, osg::Stencil::KEEP, osg::Stencil::KEEP);
440                ss1->setAttributeAndModes(stencil,osg::StateAttribute::ON);
441
442                osg::BlendFunc* blend = new osg::BlendFunc;
443                blend->setFunction(osg::BlendFunc::ONE, osg::BlendFunc::ONE);
444                ss1->setAttributeAndModes(blend, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
445                ss1->setMode(GL_LIGHTING, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
446
447                camera->addChild(second_model_group);
448            }
449                   
450        }
451
452    }
453
454
455    viewer.setSceneData(group.get());
456   
457    // create the windows and run the threads.
458    viewer.realize();
459
460    // osgDB::writeNodeFile(*group,"test.osg");
461
462    while (!viewer.done())
463    {
464        if (updateLightPosition)
465        {
466            float t = viewer.getFrameStamp()->getReferenceTime();
467            if (postionalLight)
468            {
469                lightpos.set(bb.center().x()+sinf(t)*bb.radius(), bb.center().y() + cosf(t)*bb.radius(), bb.zMax() + bb.radius()  ,1.0f);
470            }
471            else
472            {
473                lightpos.set(sinf(t),cosf(t),0.8f,0.0f);
474            }
475            light->setPosition(lightpos);
476            occluder->computeShadowVolumeGeometry(lightpos, *shadowVolume);
477        }
478
479        viewer.frame();
480    }
481   
482    return 0;
483}
Note: See TracBrowser for help on using the browser.