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

Revision 5781, 9.8 kB (checked in by robert, 7 years ago)

Added dynamic updating of light position and multi-pass addition of ambient and diffuse lighting

  • 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
7#include <osgProducer/Viewer>
8
9#include <osgShadow/OccluderGeometry>
10
11#include <osgDB/ReadFile>
12
13
14class ComputeBoundingBoxVisitor : public osg::NodeVisitor
15{
16public:
17    ComputeBoundingBoxVisitor():
18        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN)
19    {
20    }
21   
22    virtual void reset()
23    {
24        _matrixStack.clear();
25        _bb.init();
26    }
27   
28    osg::BoundingBox& getBoundingBox() { return _bb; }
29
30    void getPolytope(osg::Polytope& polytope, float margin=0.1) const
31    {
32        float delta = _bb.radius()*margin;
33        polytope.add( osg::Plane(0.0, 0.0, 1.0, -(_bb.zMin()-delta)) );
34        polytope.add( osg::Plane(0.0, 0.0, -1.0, (_bb.zMax()+delta)) );
35
36        polytope.add( osg::Plane(1.0, 0.0, 0.0, -(_bb.xMin()-delta)) );
37        polytope.add( osg::Plane(-1.0, 0.0, 0.0, (_bb.xMax()+delta)) );
38
39        polytope.add( osg::Plane(0.0, 1.0, 0.0, -(_bb.yMin()-delta)) );
40        polytope.add( osg::Plane(0.0, -1.0, 0.0, (_bb.yMax()+delta)) );
41    }
42       
43    void apply(osg::Node& node)
44    {
45        traverse(node);
46    }
47   
48    void apply(osg::Transform& transform)
49    {
50        osg::Matrix matrix;
51        if (!_matrixStack.empty()) matrix = _matrixStack.back();
52       
53        transform.computeLocalToWorldMatrix(matrix,this);
54       
55        pushMatrix(matrix);
56       
57        traverse(transform);
58       
59        popMatrix();
60    }
61   
62    void apply(osg::Geode& geode)
63    {
64        for(unsigned int i=0; i<geode.getNumDrawables(); ++i)
65        {
66            apply(geode.getDrawable(i));
67        }
68    }
69   
70    void pushMatrix(osg::Matrix& matrix)
71    {
72        _matrixStack.push_back(matrix);
73    }
74   
75    void popMatrix()
76    {
77        _matrixStack.pop_back();
78    }
79
80    void apply(osg::Drawable* drawable)
81    {
82        if (_matrixStack.empty()) _bb.expandBy(drawable->getBound());
83        else
84        {
85            osg::Matrix& matrix = _matrixStack.back();
86            const osg::BoundingBox& dbb = drawable->getBound();
87            if (dbb.valid())
88            {
89                _bb.expandBy(dbb.corner(0) * matrix);
90                _bb.expandBy(dbb.corner(1) * matrix);
91                _bb.expandBy(dbb.corner(2) * matrix);
92                _bb.expandBy(dbb.corner(3) * matrix);
93                _bb.expandBy(dbb.corner(4) * matrix);
94                _bb.expandBy(dbb.corner(5) * matrix);
95                _bb.expandBy(dbb.corner(6) * matrix);
96                _bb.expandBy(dbb.corner(7) * matrix);
97            }
98        }
99    }
100   
101protected:
102   
103    typedef std::vector<osg::Matrix> MatrixStack;
104
105    MatrixStack         _matrixStack;
106    osg::BoundingBox    _bb;
107};
108
109
110
111int main(int argc, char** argv)
112{
113    // use an ArgumentParser object to manage the program arguments.
114    osg::ArgumentParser arguments(&argc, argv);
115
116    // set up the usage document, in case we need to print out how to use this program.
117    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName() + " is the example which demonstrates using of GL_ARB_shadow extension implemented in osg::Texture class");
118    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName());
119    arguments.getApplicationUsage()->addCommandLineOption("-h or --help", "Display this information");
120    arguments.getApplicationUsage()->addCommandLineOption("--with-base-texture", "Adde base texture to shadowed model.");
121    arguments.getApplicationUsage()->addCommandLineOption("--no-base-texture", "Adde base texture to shadowed model.");
122
123    // construct the viewer.
124    osgProducer::Viewer viewer(arguments);
125
126    // set up the value with sensible default event handlers.
127    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
128
129    // get details on keyboard and mouse bindings used by the viewer.
130    viewer.getUsage(*arguments. getApplicationUsage());
131
132    // if user request help write it out to cout.
133    if (arguments.read("-h") || arguments.read("--help"))
134    {
135        arguments.getApplicationUsage()->write(std::cout);
136        return 1;
137    }
138
139    bool postionalLight = false;
140    while (arguments.read("--positionalLight")) postionalLight = true;
141    while (arguments.read("--directionalLight")) postionalLight = false;
142
143    bool addOccluderToScene = false;
144    while (arguments.read("addOccluderToScene")) addOccluderToScene = true;
145
146    bool updateLightPosition = true;
147
148    bool doShadow = true;
149
150    // any option left unread are converted into errors to write out later.
151    arguments.reportRemainingOptionsAsUnrecognized();
152
153    // report any errors if they have occured when parsing the program aguments.
154    if (arguments.errors())
155    {
156      arguments.writeErrorMessages(std::cout);
157      return 1;
158    }
159
160
161    osg::ref_ptr<osg::Node> model = osgDB::readNodeFiles(arguments);
162    if (!model)
163    {
164        osg::notify(osg::NOTICE)<<"No model loaded, please specify a model to load."<<std::endl;
165        return 1;
166    }
167
168    // get the bounds of the model.   
169    ComputeBoundingBoxVisitor cbbv;
170    model->accept(cbbv);
171    osg::BoundingBox bb = cbbv.getBoundingBox();
172   
173    osg::ref_ptr<osg::Group> group = new osg::Group;
174
175    // set up the occluder
176    osg::ref_ptr<osgShadow::OccluderGeometry> occluder = new osgShadow::OccluderGeometry;
177    occluder->computeOccluderGeometry(model.get());
178    cbbv.getPolytope(occluder->getBoundingPolytope(),0.001);
179
180    if (addOccluderToScene)
181    {
182        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
183        geode->addDrawable(occluder.get());
184        group->addChild(geode.get());
185    }
186   
187    osg::ref_ptr<osgShadow::ShadowVolumeGeometry> shadowVolume = new osgShadow::ShadowVolumeGeometry;
188
189    shadowVolume->setUseDisplayList(!updateLightPosition);
190
191    osg::Vec4 lightpos;
192   
193    if (postionalLight)
194    {
195        lightpos.set(bb.center().x(), bb.center().y(), bb.zMax() + bb.radius()  ,1.0f);
196    }
197    else
198    {
199        lightpos.set(0.5f,0.25f,0.8f,0.0f);
200    }
201
202
203    osg::ref_ptr<osg::Light> light = new osg::Light;
204
205    if (!doShadow)
206    {
207        group->addChild(model.get());
208
209        osg::ref_ptr<osg::Geode> geode = new osg::Geode;
210        occluder->comptueShadowVolumeGeometry(lightpos, *shadowVolume);
211        geode->addDrawable(shadowVolume.get());
212        group->addChild(geode.get());
213    }
214    else
215    {
216        osg::Vec4 ambient(0.5,0.5,0.5,1.0);
217        osg::Vec4 diffuse(1.0,1.0,1.0,1.0);
218        osg::Vec4 zero_colour(0.0,0.0,0.0,1.0);
219   
220        // first group
221        {
222
223            osg::Group* first_model_group = new osg::Group;
224            first_model_group->addChild(model.get());
225            group->addChild(first_model_group);
226
227            osg::StateSet* ss1 = first_model_group->getOrCreateStateSet();
228
229            osg::LightModel* lm1 = new osg::LightModel;
230            lm1->setAmbientIntensity(ambient);
231            ss1->setAttribute(lm1);
232
233            osg::Light* light1 = new osg::Light;
234            light1->setAmbient(ambient);
235            light1->setDiffuse(zero_colour);
236            light1->setPosition(lightpos);
237            ss1->setAttributeAndModes(light1, osg::StateAttribute::ON);
238       
239        }   
240   
241        // second group
242        {
243
244            osg::Group* second_model_group = new osg::Group;
245            second_model_group->addChild(model.get());
246            group->addChild(second_model_group);
247
248            osg::StateSet* ss1 = second_model_group->getOrCreateStateSet();
249            ss1->setRenderBinDetails(1, "RenderBin");
250
251            osg::LightModel* lm1 = new osg::LightModel;
252            lm1->setAmbientIntensity(zero_colour);
253            ss1->setAttribute(lm1);
254
255
256            osg::LightSource* lightsource = new osg::LightSource;
257            lightsource->setLight(light.get());
258            light->setAmbient(zero_colour);
259            light->setDiffuse(diffuse);
260            light->setPosition(lightpos);
261            second_model_group->addChild(lightsource);
262           
263            ss1->setMode(GL_LIGHT0, osg::StateAttribute::ON);
264           
265            osg::Depth* depth = new osg::Depth;
266            depth->setWriteMask(false);
267            depth->setFunction(osg::Depth::LEQUAL);
268            ss1->setAttribute(depth);
269           
270            osg::BlendFunc* blend = new osg::BlendFunc;
271            blend->setFunction(osg::BlendFunc::ONE, osg::BlendFunc::ONE);
272            ss1->setAttributeAndModes(blend, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
273       
274        }   
275
276        {
277            osg::ref_ptr<osg::Geode> geode = new osg::Geode;
278            occluder->comptueShadowVolumeGeometry(lightpos, *shadowVolume);
279            geode->addDrawable(shadowVolume.get());
280            group->addChild(geode.get());
281        }
282
283    }
284
285
286    viewer.setSceneData(group.get());
287
288    // create the windows and run the threads.
289    viewer.realize();
290
291    while (!viewer.done())
292    {
293      // wait for all cull and draw threads to complete.
294      viewer.sync();
295
296        if (updateLightPosition)
297        {
298            float t = viewer.getFrameStamp()->getReferenceTime();
299            if (postionalLight)
300            {
301                lightpos.set(bb.center().x()+sinf(t)*bb.radius(), bb.center().y() + cosf(t)*bb.radius(), bb.zMax() + bb.radius()  ,1.0f);
302            }
303            else
304            {
305                lightpos.set(sinf(t),cosf(t),0.8f,0.0f);
306            }
307            light->setPosition(lightpos);
308            occluder->comptueShadowVolumeGeometry(lightpos, *shadowVolume);
309       }
310
311      // update the scene by traversing it with the the update visitor which will
312      // call all node update callbacks and animations.
313      viewer.update();
314         
315      // fire off the cull and draw traversals of the scene.
316      viewer.frame();
317    }
318   
319    // wait for all cull and draw threads to complete.
320    viewer.sync();
321
322    // run a clean up frame to delete all OpenGL objects.
323    viewer.cleanup_frame();
324
325    // wait for all the clean up frame to complete.
326    viewer.sync();
327
328    return 0;
329}
Note: See TracBrowser for help on using the browser.