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

Revision 6235, 14.1 kB (checked in by robert, 8 years ago)

Added support for ShadowTexture? and ShadowMap? to osgshadow example

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