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

Revision 6141, 15.5 kB (checked in by robert, 7 years ago)

Cleaned up osgshadow example so that it now relies upon osgShadow for its
shadow implementation

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osg/ArgumentParser>
2
3#include <osgGA/TrackballManipulator>
4#include <osgGA/FlightManipulator>
5#include <osgGA/DriveManipulator>
6#include <osgGA/KeySwitchMatrixManipulator>
7#include <osgGA/AnimationPathManipulator>
8#include <osgGA/TerrainManipulator>
9#include <osgGA/AnimationPathManipulator>
10#include <osgGA/StateSetManipulator>
11
12#include <osgViewer/Viewer>
13#include <osgViewer/StatsHandler>
14
15#include <osgShadow/ShadowedScene>
16#include <osgShadow/ShadowVolume>
17
18#include <osgDB/ReadFile>
19#include <osgDB/WriteFile>
20
21#include <iostream>
22
23class ComputeBoundingBoxVisitor : public osg::NodeVisitor
24{
25public:
26    ComputeBoundingBoxVisitor():
27        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
28    {
29    }
30   
31    virtual void reset()
32    {
33        _matrixStack.clear();
34        _bb.init();
35    }
36   
37    osg::BoundingBox& getBoundingBox() { return _bb; }
38
39    void getPolytope(osg::Polytope& polytope, float margin=0.1) const
40    {
41        float delta = _bb.radius()*margin;
42        polytope.add( osg::Plane(0.0, 0.0, 1.0, -(_bb.zMin()-delta)) );
43        polytope.add( osg::Plane(0.0, 0.0, -1.0, (_bb.zMax()+delta)) );
44
45        polytope.add( osg::Plane(1.0, 0.0, 0.0, -(_bb.xMin()-delta)) );
46        polytope.add( osg::Plane(-1.0, 0.0, 0.0, (_bb.xMax()+delta)) );
47
48        polytope.add( osg::Plane(0.0, 1.0, 0.0, -(_bb.yMin()-delta)) );
49        polytope.add( osg::Plane(0.0, -1.0, 0.0, (_bb.yMax()+delta)) );
50    }
51       
52    void getBase(osg::Polytope& polytope, float margin=0.1) const
53    {
54        float delta = _bb.radius()*margin;
55        polytope.add( osg::Plane(0.0, 0.0, 1.0, -(_bb.zMin()-delta)) );
56    }
57   
58    void apply(osg::Node& node)
59    {
60        traverse(node);
61    }
62   
63    void apply(osg::Transform& transform)
64    {
65        osg::Matrix matrix;
66        if (!_matrixStack.empty()) matrix = _matrixStack.back();
67       
68        transform.computeLocalToWorldMatrix(matrix,this);
69       
70        pushMatrix(matrix);
71       
72        traverse(transform);
73       
74        popMatrix();
75    }
76   
77    void apply(osg::Geode& geode)
78    {
79        for(unsigned int i=0; i<geode.getNumDrawables(); ++i)
80        {
81            apply(geode.getDrawable(i));
82        }
83    }
84   
85    void pushMatrix(osg::Matrix& matrix)
86    {
87        _matrixStack.push_back(matrix);
88    }
89   
90    void popMatrix()
91    {
92        _matrixStack.pop_back();
93    }
94
95    void apply(osg::Drawable* drawable)
96    {
97        if (_matrixStack.empty()) _bb.expandBy(drawable->getBound());
98        else
99        {
100            osg::Matrix& matrix = _matrixStack.back();
101            const osg::BoundingBox& dbb = drawable->getBound();
102            if (dbb.valid())
103            {
104                _bb.expandBy(dbb.corner(0) * matrix);
105                _bb.expandBy(dbb.corner(1) * matrix);
106                _bb.expandBy(dbb.corner(2) * matrix);
107                _bb.expandBy(dbb.corner(3) * matrix);
108                _bb.expandBy(dbb.corner(4) * matrix);
109                _bb.expandBy(dbb.corner(5) * matrix);
110                _bb.expandBy(dbb.corner(6) * matrix);
111                _bb.expandBy(dbb.corner(7) * matrix);
112            }
113        }
114    }
115   
116protected:
117   
118    typedef std::vector<osg::Matrix> MatrixStack;
119
120    MatrixStack         _matrixStack;
121    osg::BoundingBox    _bb;
122};
123
124enum Faces
125{
126    FRONT_FACE = 1,
127    BACK_FACE = 2,
128    LEFT_FACE = 4,
129    RIGHT_FACE = 8,
130    TOP_FACE = 16,
131    BOTTOM_FACE = 32       
132};
133
134osg::Node* createCube(unsigned int mask)
135{
136    osg::Geode* geode = new osg::Geode;
137   
138    osg::Geometry* geometry = new osg::Geometry;
139    geode->addDrawable(geometry);
140   
141    osg::Vec3Array* vertices = new osg::Vec3Array;
142    geometry->setVertexArray(vertices);
143   
144    osg::Vec3Array* normals = new osg::Vec3Array;
145    geometry->setNormalArray(normals);
146    geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
147   
148    osg::Vec4Array* colours = new osg::Vec4Array;
149    geometry->setColorArray(colours);
150    geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
151    colours->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
152   
153   
154    osg::Vec3 origin(0.0f,0.0f,0.0f);
155    osg::Vec3 dx(2.0f,0.0f,0.0f);
156    osg::Vec3 dy(0.0f,1.0f,0.0f);
157    osg::Vec3 dz(0.0f,0.0f,1.0f);
158   
159    osg::Vec3 px(1.0f,0.0,0.0f);
160    osg::Vec3 nx(-1.0f,0.0,0.0f);
161    osg::Vec3 py(0.0f,1.0f,0.0f);
162    osg::Vec3 ny(0.0f,-1.0f,0.0f);
163    osg::Vec3 pz(0.0f,0.0f,1.0f);
164    osg::Vec3 nz(0.0f,0.0f,-1.0f);
165
166    if (mask & FRONT_FACE)
167    {
168        // front face   
169        vertices->push_back(origin);
170        vertices->push_back(origin+dx);
171        vertices->push_back(origin+dx+dz);
172        vertices->push_back(origin+dz);
173        normals->push_back(ny);
174        normals->push_back(ny);
175        normals->push_back(ny);
176        normals->push_back(ny);
177    }
178
179    if (mask & BACK_FACE)
180    {
181        // back face   
182        vertices->push_back(origin+dy);
183        vertices->push_back(origin+dy+dz);
184        vertices->push_back(origin+dy+dx+dz);
185        vertices->push_back(origin+dy+dx);
186        normals->push_back(py);
187        normals->push_back(py);
188        normals->push_back(py);
189        normals->push_back(py);
190    }
191
192    if (mask & LEFT_FACE)
193    {
194        // left face   
195        vertices->push_back(origin+dy);
196        vertices->push_back(origin);
197        vertices->push_back(origin+dz);
198        vertices->push_back(origin+dy+dz);
199        normals->push_back(nx);
200        normals->push_back(nx);
201        normals->push_back(nx);
202        normals->push_back(nx);
203    }
204
205    if (mask & RIGHT_FACE)
206    {
207        // right face   
208        vertices->push_back(origin+dx+dy);
209        vertices->push_back(origin+dx+dy+dz);
210        vertices->push_back(origin+dx+dz);
211        vertices->push_back(origin+dx);
212        normals->push_back(px);
213        normals->push_back(px);
214        normals->push_back(px);
215        normals->push_back(px);
216    }
217
218    if (mask & TOP_FACE)
219    {
220        // top face   
221        vertices->push_back(origin+dz);
222        vertices->push_back(origin+dz+dx);
223        vertices->push_back(origin+dz+dx+dy);
224        vertices->push_back(origin+dz+dy);
225        normals->push_back(pz);
226        normals->push_back(pz);
227        normals->push_back(pz);
228        normals->push_back(pz);
229    }
230
231    if (mask & BOTTOM_FACE)
232    {
233        // bottom face   
234        vertices->push_back(origin);
235        vertices->push_back(origin+dy);
236        vertices->push_back(origin+dx+dy);
237        vertices->push_back(origin+dx);
238        normals->push_back(nz);
239        normals->push_back(nz);
240        normals->push_back(nz);
241        normals->push_back(nz);
242    }
243   
244    geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, vertices->size()));
245
246    return geode;
247}
248
249class SwitchHandler : public osgGA::GUIEventHandler
250{
251public:
252
253    SwitchHandler():
254        _childNum(0) {}
255   
256    virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& /*aa*/, osg::Object* object, osg::NodeVisitor* /*nv*/)
257    {
258        osg::Switch* sw = dynamic_cast<osg::Switch*>(object);
259        if (!sw) return false;
260
261        if (ea.getHandled()) return false;
262       
263        switch(ea.getEventType())
264        {
265            case(osgGA::GUIEventAdapter::KEYDOWN):
266            {
267                if (ea.getKey()=='n')
268                {
269                    ++_childNum;
270                    if (_childNum >= sw->getNumChildren()) _childNum = 0;
271
272                    sw->setSingleChildOn(_childNum);
273                    return true;
274                }               
275                break;
276            }
277            default:
278                break;
279        }
280        return false;
281    }
282
283protected:
284
285    virtual ~SwitchHandler() {}
286    unsigned int    _childNum;
287
288};
289
290osg::Node* createTestModel()
291{
292    osg::Switch* sw = new osg::Switch;
293    sw->setEventCallback(new SwitchHandler);
294   
295    sw->addChild(createCube(FRONT_FACE), true);
296    sw->addChild(createCube(FRONT_FACE | BACK_FACE), false);
297    sw->addChild(createCube(FRONT_FACE | BACK_FACE | LEFT_FACE), false);
298    sw->addChild(createCube(FRONT_FACE | BACK_FACE | LEFT_FACE | RIGHT_FACE), false);
299    sw->addChild(createCube(FRONT_FACE | BACK_FACE | LEFT_FACE | RIGHT_FACE | TOP_FACE), false);
300    sw->addChild(createCube(FRONT_FACE | BACK_FACE | LEFT_FACE | RIGHT_FACE | TOP_FACE | BOTTOM_FACE), false);
301   
302    return sw;
303}
304
305int main(int argc, char** argv)
306{
307    // use an ArgumentParser object to manage the program arguments.
308    osg::ArgumentParser arguments(&argc, argv);
309
310    // set up the usage document, in case we need to print out how to use this program.
311    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName() + " is the example which demonstrates using of GL_ARB_shadow extension implemented in osg::Texture class");
312    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName());
313    arguments.getApplicationUsage()->addCommandLineOption("-h or --help", "Display this information");
314    arguments.getApplicationUsage()->addCommandLineOption("--positionalLight", "Use a positional light.");
315    arguments.getApplicationUsage()->addCommandLineOption("--directionalLight", "Use a direction light.");
316    arguments.getApplicationUsage()->addCommandLineOption("--addOccluderToScene", "Add the occluders geometry.");
317    arguments.getApplicationUsage()->addCommandLineOption("--noUpdate", "Disable the updating the of light source.");
318    arguments.getApplicationUsage()->addCommandLineOption("--base", "Add a base geometry to test shadows.");
319    arguments.getApplicationUsage()->addCommandLineOption("--noShadow", "Disable the shadows.");
320    arguments.getApplicationUsage()->addCommandLineOption("--two-sided", "Use two-sided stencil extension for shadow volumes.");
321    arguments.getApplicationUsage()->addCommandLineOption("--two-pass", "Use two-pass stencil for shadow volumes.");
322
323    // hint to tell viewer to request stencil buffer when setting up windows
324    osg::DisplaySettings::instance()->setMinimumNumStencilBits(8);
325
326    // construct the viewer.
327    osgViewer::Viewer viewer;
328
329    // if user request help write it out to cout.
330    if (arguments.read("-h") || arguments.read("--help"))
331    {
332        arguments.getApplicationUsage()->write(std::cout);
333        return 1;
334    }
335
336    // default to single threaded during dev work.
337    viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
338   
339    while (arguments.read("--SingleThreaded")) viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
340    while (arguments.read("--CullDrawThreadPerContext")) viewer.setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext);
341    while (arguments.read("--DrawThreadPerContext")) viewer.setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
342    while (arguments.read("--CullThreadPerCameraDrawThreadPerContext")) viewer.setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
343
344
345    bool postionalLight = false;
346    while (arguments.read("--positionalLight")) postionalLight = true;
347    while (arguments.read("--directionalLight")) postionalLight = false;
348
349    bool updateLightPosition = true;
350    while (arguments.read("--noUpdate")) updateLightPosition = false;
351
352    bool createBase = false;
353    while (arguments.read("--base")) createBase = true;
354
355
356    int screenNum = -1;
357    while (arguments.read("--screen", screenNum)) viewer.setUpViewOnSingleScreen(screenNum);
358
359    osgShadow::ShadowVolumeGeometry::DrawMode drawMode = osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED;
360    while (arguments.read("--two-sided")) drawMode = osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED;
361    while (arguments.read("--two-pass")) drawMode = osgShadow::ShadowVolumeGeometry::STENCIL_TWO_PASS;
362
363
364    // set up the camera manipulators.
365    {
366        osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
367
368        keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() );
369        keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() );
370        keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() );
371        keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );
372
373        std::string pathfile;
374        char keyForAnimationPath = '5';
375        while (arguments.read("-p",pathfile))
376        {
377            osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile);
378            if (apm || !apm->valid())
379            {
380                unsigned int num = keyswitchManipulator->getNumMatrixManipulators();
381                keyswitchManipulator->addMatrixManipulator( keyForAnimationPath, "Path", apm );
382                keyswitchManipulator->selectMatrixManipulator(num);
383                ++keyForAnimationPath;
384            }
385        }
386
387        viewer.setCameraManipulator( keyswitchManipulator.get() );
388    }
389
390    // add the state manipulator
391    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
392
393    // add stats
394    viewer.addEventHandler( new osgViewer::StatsHandler() );
395
396    // any option left unread are converted into errors to write out later.
397    arguments.reportRemainingOptionsAsUnrecognized();
398
399    // report any errors if they have occured when parsing the program aguments.
400    if (arguments.errors())
401    {
402      arguments.writeErrorMessages(std::cout);
403      return 1;
404    }
405
406
407    osg::ref_ptr<osg::Node> model = osgDB::readNodeFiles(arguments);
408    if (!model)
409    {
410        model = createTestModel();
411    }
412
413    // get the bounds of the model.   
414    ComputeBoundingBoxVisitor cbbv;
415    model->accept(cbbv);
416    osg::BoundingBox bb = cbbv.getBoundingBox();
417
418    if (createBase)
419    {
420        osg::ref_ptr<osg::Group> newGroup = new osg::Group;
421        newGroup->addChild(model.get());
422       
423        osg::Geode* geode = new osg::Geode;
424       
425        osg::Vec3 widthVec(bb.radius(), 0.0f, 0.0f);
426        osg::Vec3 depthVec(0.0f, bb.radius(), 0.0f);
427        osg::Vec3 centerBase( (bb.xMin()+bb.xMax())*0.5f, (bb.yMin()+bb.yMax())*0.5f, bb.zMin()-bb.radius()*0.1f );
428       
429        geode->addDrawable( osg::createTexturedQuadGeometry( centerBase-widthVec*1.5f-depthVec*1.5f,
430                                                             widthVec*3.0f, depthVec*3.0f) );
431        newGroup->addChild(geode);
432       
433        model = newGroup.get();
434    }
435
436    osg::Vec4 lightpos;
437   
438    if (postionalLight)
439    {
440        lightpos.set(bb.center().x(), bb.center().y(), bb.zMax() + bb.radius()  ,1.0f);
441    }
442    else
443    {
444        lightpos.set(0.5f,0.25f,0.8f,0.0f);
445    }
446
447
448    osg::ref_ptr<osgShadow::ShadowedScene> shadowedScene = new osgShadow::ShadowedScene;
449   
450    osg::ref_ptr<osgShadow::ShadowVolume> shadowVolume = new osgShadow::ShadowVolume;
451    shadowedScene->setShadowTechnique(shadowVolume.get());
452    shadowVolume->setDynamicShadowVolumes(updateLightPosition);
453
454    osg::ref_ptr<osg::LightSource> ls = new osg::LightSource;
455    ls->getLight()->setPosition(lightpos);
456
457    shadowedScene->addChild(model.get());
458    shadowedScene->addChild(ls.get());
459
460    viewer.setSceneData(shadowedScene.get());
461   
462    // create the windows and run the threads.
463    viewer.realize();
464
465    // osgDB::writeNodeFile(*group,"test.osg");
466
467    while (!viewer.done())
468    {
469        if (updateLightPosition)
470        {
471            float t = viewer.getFrameStamp()->getSimulationTime();
472            if (postionalLight)
473            {
474                lightpos.set(bb.center().x()+sinf(t)*bb.radius(), bb.center().y() + cosf(t)*bb.radius(), bb.zMax() + bb.radius()  ,1.0f);
475            }
476            else
477            {
478                lightpos.set(sinf(t),cosf(t),1.0f,0.0f);
479            }
480            ls->getLight()->setPosition(lightpos);
481        }
482
483        viewer.frame();
484    }
485   
486    return 0;
487}
Note: See TracBrowser for help on using the browser.