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

Revision 5960, 13.7 kB (checked in by robert, 8 years ago)

Added DisplaySettings? support into osgViewer::Viewer

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