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

Revision 7539, 30.3 kB (checked in by robert, 7 years ago)

From Mihair Radu, "Most of the additions are small utility methods:
- set the resolution of the shadow map; it calls dirty() to
re-initialize at next update
- keep a list of Shader objects to use instead of the default ones, if
the list is empty, the default shaders are used
- explicitly create the Uniform variables, so that subsequent additions
that require more Uniforms can put them in a central place
- set a Light or LightSource? to use explicitly for shadow casting,
allows multiple lights in the scene, with one casting shadows

There are two additions that do not ( yet ) function correctly, but in
the present usage they do not interfere with the regular usage of the
techique:
- support for using spotlights, it's using Light.spotCutoff to determine
if it's a spot-light and not point-light,

there is an error in the setup of either the shadow camera or the

texgen, most likely due to the direction of the spotlight, since the
position is being used just like in point or directional lights.
- creation of a debugHUD

the hud is created properly, ( the example included shows it ), but

it displays only white, there has been some discussion of displaying the
shadow map, but I could not find it, the addition of a simple fragment
shader with the appropriate color transform should get this going."

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1/* OpenSceneGraph example, osgshadow.
2*
3*  Permission is hereby granted, free of charge, to any person obtaining a copy
4*  of this software and associated documentation files (the "Software"), to deal
5*  in the Software without restriction, including without limitation the rights
6*  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7*  copies of the Software, and to permit persons to whom the Software is
8*  furnished to do so, subject to the following conditions:
9*
10*  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
11*  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
12*  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
13*  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
14*  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
15*  OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
16*  THE SOFTWARE.
17*/
18
19#include <osg/ArgumentParser>
20#include <osg/ComputeBoundsVisitor>
21#include <osg/Texture2D>
22#include <osg/ShapeDrawable>
23#include <osg/MatrixTransform>
24#include <osg/Geometry>
25
26#include <osgGA/TrackballManipulator>
27#include <osgGA/FlightManipulator>
28#include <osgGA/DriveManipulator>
29#include <osgGA/KeySwitchMatrixManipulator>
30#include <osgGA/AnimationPathManipulator>
31#include <osgGA/TerrainManipulator>
32#include <osgGA/AnimationPathManipulator>
33#include <osgGA/StateSetManipulator>
34
35#include <osgViewer/Viewer>
36#include <osgViewer/ViewerEventHandlers>
37
38#include <osgShadow/ShadowedScene>
39#include <osgShadow/ShadowVolume>
40#include <osgShadow/ShadowTexture>
41#include <osgShadow/ShadowMap>
42#include <osgShadow/SoftShadowMap>
43#include <osgShadow/ParallelSplitShadowMap>
44
45#include <osgDB/ReadFile>
46#include <osgDB/WriteFile>
47
48#include <iostream>
49
50// for the grid data..
51#include "../osghangglide/terrain_coords.h"
52
53const int ReceivesShadowTraversalMask = 0x1;
54const int CastsShadowTraversalMask = 0x2;
55 
56namespace ModelOne
57{
58
59    enum Faces
60    {
61        FRONT_FACE = 1,
62        BACK_FACE = 2,
63        LEFT_FACE = 4,
64        RIGHT_FACE = 8,
65        TOP_FACE = 16,
66        BOTTOM_FACE = 32       
67    };
68
69    osg::Node* createCube(unsigned int mask)
70    {
71        osg::Geode* geode = new osg::Geode;
72
73        osg::Geometry* geometry = new osg::Geometry;
74        geode->addDrawable(geometry);
75
76        osg::Vec3Array* vertices = new osg::Vec3Array;
77        geometry->setVertexArray(vertices);
78
79        osg::Vec3Array* normals = new osg::Vec3Array;
80        geometry->setNormalArray(normals);
81        geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
82
83        osg::Vec4Array* colours = new osg::Vec4Array;
84        geometry->setColorArray(colours);
85        geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
86        colours->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
87
88
89        osg::Vec3 origin(0.0f,0.0f,0.0f);
90        osg::Vec3 dx(2.0f,0.0f,0.0f);
91        osg::Vec3 dy(0.0f,1.0f,0.0f);
92        osg::Vec3 dz(0.0f,0.0f,1.0f);
93
94        osg::Vec3 px(1.0f,0.0,0.0f);
95        osg::Vec3 nx(-1.0f,0.0,0.0f);
96        osg::Vec3 py(0.0f,1.0f,0.0f);
97        osg::Vec3 ny(0.0f,-1.0f,0.0f);
98        osg::Vec3 pz(0.0f,0.0f,1.0f);
99        osg::Vec3 nz(0.0f,0.0f,-1.0f);
100
101        if (mask & FRONT_FACE)
102        {
103            // front face   
104            vertices->push_back(origin);
105            vertices->push_back(origin+dx);
106            vertices->push_back(origin+dx+dz);
107            vertices->push_back(origin+dz);
108            normals->push_back(ny);
109            normals->push_back(ny);
110            normals->push_back(ny);
111            normals->push_back(ny);
112        }
113
114        if (mask & BACK_FACE)
115        {
116            // back face   
117            vertices->push_back(origin+dy);
118            vertices->push_back(origin+dy+dz);
119            vertices->push_back(origin+dy+dx+dz);
120            vertices->push_back(origin+dy+dx);
121            normals->push_back(py);
122            normals->push_back(py);
123            normals->push_back(py);
124            normals->push_back(py);
125        }
126
127        if (mask & LEFT_FACE)
128        {
129            // left face   
130            vertices->push_back(origin+dy);
131            vertices->push_back(origin);
132            vertices->push_back(origin+dz);
133            vertices->push_back(origin+dy+dz);
134            normals->push_back(nx);
135            normals->push_back(nx);
136            normals->push_back(nx);
137            normals->push_back(nx);
138        }
139
140        if (mask & RIGHT_FACE)
141        {
142            // right face   
143            vertices->push_back(origin+dx+dy);
144            vertices->push_back(origin+dx+dy+dz);
145            vertices->push_back(origin+dx+dz);
146            vertices->push_back(origin+dx);
147            normals->push_back(px);
148            normals->push_back(px);
149            normals->push_back(px);
150            normals->push_back(px);
151        }
152
153        if (mask & TOP_FACE)
154        {
155            // top face   
156            vertices->push_back(origin+dz);
157            vertices->push_back(origin+dz+dx);
158            vertices->push_back(origin+dz+dx+dy);
159            vertices->push_back(origin+dz+dy);
160            normals->push_back(pz);
161            normals->push_back(pz);
162            normals->push_back(pz);
163            normals->push_back(pz);
164        }
165
166        if (mask & BOTTOM_FACE)
167        {
168            // bottom face   
169            vertices->push_back(origin);
170            vertices->push_back(origin+dy);
171            vertices->push_back(origin+dx+dy);
172            vertices->push_back(origin+dx);
173            normals->push_back(nz);
174            normals->push_back(nz);
175            normals->push_back(nz);
176            normals->push_back(nz);
177        }
178
179        geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, vertices->size()));
180
181        return geode;
182    }
183
184    class SwitchHandler : public osgGA::GUIEventHandler
185    {
186    public:
187
188        SwitchHandler():
189            _childNum(0) {}
190
191        virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& /*aa*/, osg::Object* object, osg::NodeVisitor* /*nv*/)
192        {
193            osg::Switch* sw = dynamic_cast<osg::Switch*>(object);
194            if (!sw) return false;
195
196            if (ea.getHandled()) return false;
197
198            switch(ea.getEventType())
199            {
200                case(osgGA::GUIEventAdapter::KEYDOWN):
201                {
202                    if (ea.getKey()=='n')
203                    {
204                        ++_childNum;
205                        if (_childNum >= sw->getNumChildren()) _childNum = 0;
206
207                        sw->setSingleChildOn(_childNum);
208                        return true;
209                    }               
210                    break;
211                }
212                default:
213                    break;
214            }
215            return false;
216        }
217
218    protected:
219
220        virtual ~SwitchHandler() {}
221        unsigned int    _childNum;
222
223    };
224
225
226    osg::Node* createModel(osg::ArgumentParser& /*arguments*/)
227    {
228        osg::Switch* sw = new osg::Switch;
229        sw->setEventCallback(new ModelOne::SwitchHandler);
230
231        sw->addChild(ModelOne::createCube(ModelOne::FRONT_FACE), true);
232        sw->addChild(ModelOne::createCube(ModelOne::FRONT_FACE | ModelOne::BACK_FACE), false);
233        sw->addChild(ModelOne::createCube(ModelOne::FRONT_FACE | ModelOne::BACK_FACE | ModelOne::LEFT_FACE), false);
234        sw->addChild(ModelOne::createCube(ModelOne::FRONT_FACE | ModelOne::BACK_FACE | ModelOne::LEFT_FACE | ModelOne::RIGHT_FACE), false);
235        sw->addChild(ModelOne::createCube(ModelOne::FRONT_FACE | ModelOne::BACK_FACE | ModelOne::LEFT_FACE | ModelOne::RIGHT_FACE | ModelOne::TOP_FACE), false);
236        sw->addChild(ModelOne::createCube(ModelOne::FRONT_FACE | ModelOne::BACK_FACE | ModelOne::LEFT_FACE | ModelOne::RIGHT_FACE | ModelOne::TOP_FACE | ModelOne::BOTTOM_FACE), false);
237       
238        return sw;   
239    }
240}
241
242namespace ModelTwo
243{
244    osg::AnimationPath* createAnimationPath(const osg::Vec3& center,float radius,double looptime)
245    {
246        // set up the animation path
247        osg::AnimationPath* animationPath = new osg::AnimationPath;
248        animationPath->setLoopMode(osg::AnimationPath::LOOP);
249
250        int numSamples = 40;
251        float yaw = 0.0f;
252        float yaw_delta = 2.0f*osg::PI/((float)numSamples-1.0f);
253        float roll = osg::inDegrees(30.0f);
254
255        double time=0.0f;
256        double time_delta = looptime/(double)numSamples;
257        for(int i=0;i<numSamples;++i)
258        {
259            osg::Vec3 position(center+osg::Vec3(sinf(yaw)*radius,cosf(yaw)*radius,0.0f));
260            osg::Quat rotation(osg::Quat(roll,osg::Vec3(0.0,1.0,0.0))*osg::Quat(-(yaw+osg::inDegrees(90.0f)),osg::Vec3(0.0,0.0,1.0)));
261
262            animationPath->insert(time,osg::AnimationPath::ControlPoint(position,rotation));
263
264            yaw += yaw_delta;
265            time += time_delta;
266
267        }
268        return animationPath;   
269    }
270
271    osg::Node* createBase(const osg::Vec3& center,float radius)
272    {
273
274        osg::Geode* geode = new osg::Geode;
275
276        // set up the texture of the base.
277        osg::StateSet* stateset = new osg::StateSet();
278        osg::Image* image = osgDB::readImageFile("Images/lz.rgb");
279        if (image)
280        {
281            osg::Texture2D* texture = new osg::Texture2D;
282            texture->setImage(image);
283            stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
284        }
285
286        geode->setStateSet( stateset );
287
288
289        osg::HeightField* grid = new osg::HeightField;
290        grid->allocate(38,39);
291        grid->setOrigin(center+osg::Vec3(-radius,-radius,0.0f));
292        grid->setXInterval(radius*2.0f/(float)(38-1));
293        grid->setYInterval(radius*2.0f/(float)(39-1));
294
295        float minHeight = FLT_MAX;
296        float maxHeight = -FLT_MAX;
297
298
299        unsigned int r;
300        for(r=0;r<39;++r)
301        {
302            for(unsigned int c=0;c<38;++c)
303            {
304                float h = vertex[r+c*39][2];
305                if (h>maxHeight) maxHeight=h;
306                if (h<minHeight) minHeight=h;
307            }
308        }
309
310        float hieghtScale = radius*0.5f/(maxHeight-minHeight);
311        float hieghtOffset = -(minHeight+maxHeight)*0.5f;
312
313        for(r=0;r<39;++r)
314        {
315            for(unsigned int c=0;c<38;++c)
316            {
317                float h = vertex[r+c*39][2];
318                grid->setHeight(c,r,(h+hieghtOffset)*hieghtScale);
319            }
320        }
321
322        geode->addDrawable(new osg::ShapeDrawable(grid));
323
324        osg::Group* group = new osg::Group;
325        group->addChild(geode);
326
327        return group;
328
329    }
330
331    osg::Node* createMovingModel(const osg::Vec3& center, float radius)
332    {
333        float animationLength = 10.0f;
334
335        osg::AnimationPath* animationPath = createAnimationPath(center,radius,animationLength);
336
337        osg::Group* model = new osg::Group;
338
339        osg::Node* cessna = osgDB::readNodeFile("cessna.osg");
340        if (cessna)
341        {
342            const osg::BoundingSphere& bs = cessna->getBound();
343
344            float size = radius/bs.radius()*0.3f;
345            osg::MatrixTransform* positioned = new osg::MatrixTransform;
346            positioned->setDataVariance(osg::Object::STATIC);
347            positioned->setMatrix(osg::Matrix::translate(-bs.center())*
348                                  osg::Matrix::scale(size,size,size)*
349                                  osg::Matrix::rotate(osg::inDegrees(180.0f),0.0f,0.0f,2.0f));
350
351            positioned->addChild(cessna);
352
353            osg::MatrixTransform* xform = new osg::MatrixTransform;
354            xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0f,2.0));
355            xform->addChild(positioned);
356
357            model->addChild(xform);
358        }
359
360        return model;
361    }
362
363    osg::Node* createModel(osg::ArgumentParser& /*arguments*/)
364    {
365        osg::Vec3 center(0.0f,0.0f,0.0f);
366        float radius = 100.0f;
367        osg::Vec3 lightPosition(center+osg::Vec3(0.0f,0.0f,radius));
368
369        // the shadower model
370        osg::Node* shadower = createMovingModel(center,radius*0.5f);
371        shadower->setNodeMask(CastsShadowTraversalMask);
372
373        // the shadowed model
374        osg::Node* shadowed = createBase(center-osg::Vec3(0.0f,0.0f,radius*0.25),radius);
375        shadowed->setNodeMask(ReceivesShadowTraversalMask);
376       
377        osg::Group* group = new osg::Group;
378
379        group->addChild(shadowed);
380        group->addChild(shadower);
381       
382        return group;
383    }
384}
385
386namespace ModelThree
387{
388    osg::Group* createModel(osg::ArgumentParser& arguments)
389    {
390        osg::Group* scene = new osg::Group;
391
392        osg::ref_ptr<osg::Geode> geode_1 = new osg::Geode;
393        scene->addChild(geode_1.get());
394
395        osg::ref_ptr<osg::Geode> geode_2 = new osg::Geode;
396        osg::ref_ptr<osg::MatrixTransform> transform_2 = new osg::MatrixTransform;
397        transform_2->addChild(geode_2.get());
398        transform_2->setUpdateCallback(new osg::AnimationPathCallback(osg::Vec3(0, 0, 0), osg::Z_AXIS, osg::inDegrees(45.0f)));
399        scene->addChild(transform_2.get());
400
401        osg::ref_ptr<osg::Geode> geode_3 = new osg::Geode;
402        osg::ref_ptr<osg::MatrixTransform> transform_3 = new osg::MatrixTransform;
403        transform_3->addChild(geode_3.get());
404        transform_3->setUpdateCallback(new osg::AnimationPathCallback(osg::Vec3(0, 0, 0), osg::Z_AXIS, osg::inDegrees(-22.5f)));
405        scene->addChild(transform_3.get());
406
407        const float radius = 0.8f;
408        const float height = 1.0f;
409        osg::ref_ptr<osg::TessellationHints> hints = new osg::TessellationHints;
410        hints->setDetailRatio(2.0f);
411        osg::ref_ptr<osg::ShapeDrawable> shape;
412
413        shape = new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0f, 0.0f, -2.0f), 10, 10.0f, 0.1f), hints.get());
414        shape->setColor(osg::Vec4(0.5f, 0.5f, 0.7f, 1.0f));
415        geode_1->addDrawable(shape.get());
416
417        shape = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0f, 0.0f, 0.0f), radius * 2), hints.get());
418        shape->setColor(osg::Vec4(0.8f, 0.8f, 0.8f, 1.0f));
419        geode_1->addDrawable(shape.get());
420
421        shape = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(-3.0f, 0.0f, 0.0f), radius), hints.get());
422        shape->setColor(osg::Vec4(0.6f, 0.8f, 0.8f, 1.0f));
423        geode_2->addDrawable(shape.get());
424
425        shape = new osg::ShapeDrawable(new osg::Box(osg::Vec3(3.0f, 0.0f, 0.0f), 2 * radius), hints.get());
426        shape->setColor(osg::Vec4(0.4f, 0.9f, 0.3f, 1.0f));
427        geode_2->addDrawable(shape.get());
428
429        shape = new osg::ShapeDrawable(new osg::Cone(osg::Vec3(0.0f, -3.0f, 0.0f), radius, height), hints.get());
430        shape->setColor(osg::Vec4(0.2f, 0.5f, 0.7f, 1.0f));
431        geode_2->addDrawable(shape.get());
432
433        shape = new osg::ShapeDrawable(new osg::Cylinder(osg::Vec3(0.0f, 3.0f, 0.0f), radius, height), hints.get());
434        shape->setColor(osg::Vec4(1.0f, 0.3f, 0.3f, 1.0f));
435        geode_2->addDrawable(shape.get());
436
437        shape = new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0f, 0.0f, 3.0f), 2.0f, 2.0f, 0.1f), hints.get());
438        shape->setColor(osg::Vec4(0.8f, 0.8f, 0.4f, 1.0f));
439        geode_3->addDrawable(shape.get());
440
441        // material
442        osg::ref_ptr<osg::Material> matirial = new osg::Material;
443        matirial->setColorMode(osg::Material::DIFFUSE);
444        matirial->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
445        matirial->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(1, 1, 1, 1));
446        matirial->setShininess(osg::Material::FRONT_AND_BACK, 64.0f);
447        scene->getOrCreateStateSet()->setAttributeAndModes(matirial.get(), osg::StateAttribute::ON);
448
449        bool withBaseTexture = true;
450        while(arguments.read("--with-base-texture")) { withBaseTexture = true; }
451        while(arguments.read("--no-base-texture")) { withBaseTexture = false; }
452
453        if (withBaseTexture)
454        {
455            scene->getOrCreateStateSet()->setTextureAttributeAndModes( 0, new osg::Texture2D(osgDB::readImageFile("Images/lz.rgb")), osg::StateAttribute::ON);
456        }
457
458        return scene;
459    }
460   
461}
462
463
464osg::Node* createTestModel(osg::ArgumentParser& arguments)
465{
466    if (arguments.read("-1"))
467    {
468        return ModelOne::createModel(arguments);
469    }
470    else if (arguments.read("-2"))
471    {
472        return ModelTwo::createModel(arguments);
473    }
474    else /*if (arguments.read("-3"))*/
475    {
476        return ModelThree::createModel(arguments);
477    }
478   
479}
480
481int main(int argc, char** argv)
482{
483    // use an ArgumentParser object to manage the program arguments.
484    osg::ArgumentParser arguments(&argc, argv);
485
486    // set up the usage document, in case we need to print out how to use this program.
487    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName() + " is the example which demonstrates using of GL_ARB_shadow extension implemented in osg::Texture class");
488    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName());
489    arguments.getApplicationUsage()->addCommandLineOption("-h or --help", "Display this information");
490    arguments.getApplicationUsage()->addCommandLineOption("--positionalLight", "Use a positional light.");
491    arguments.getApplicationUsage()->addCommandLineOption("--directionalLight", "Use a direction light.");
492    arguments.getApplicationUsage()->addCommandLineOption("--noUpdate", "Disable the updating the of light source.");
493    arguments.getApplicationUsage()->addCommandLineOption("--base", "Add a base geometry to test shadows.");
494    arguments.getApplicationUsage()->addCommandLineOption("--sv", "Select ShadowVolume implementation.");
495    arguments.getApplicationUsage()->addCommandLineOption("--ssm", "Select SoftShadowMap implementation.");
496    arguments.getApplicationUsage()->addCommandLineOption("--sm", "Select ShadowMap implementation.");
497//    arguments.getApplicationUsage()->addCommandLineOption("--pssm", "Select ParallelSplitShadowMap implementation.");
498    arguments.getApplicationUsage()->addCommandLineOption("--pssm", "Select ParallelSplitShadowMap implementation.");//ADEGLI
499    arguments.getApplicationUsage()->addCommandLineOption("--mapcount", "ParallelSplitShadowMap texture count.");//ADEGLI
500    arguments.getApplicationUsage()->addCommandLineOption("--mapres", "ParallelSplitShadowMap texture resolution.");//ADEGLI
501    arguments.getApplicationUsage()->addCommandLineOption("--debug-color", "ParallelSplitShadowMap display debugging color (only the first 3 maps are color r=0,g=1,b=2.");//ADEGLI
502    arguments.getApplicationUsage()->addCommandLineOption("--minNearSplit", "ParallelSplitShadowMap shadow map near offset.");//ADEGLI
503    arguments.getApplicationUsage()->addCommandLineOption("--maxFarDist", "ParallelSplitShadowMap max far distance to shadow.");//ADEGLI
504    arguments.getApplicationUsage()->addCommandLineOption("--moveVCamFactor", "ParallelSplitShadowMap move the virtual frustum behind the real camera, (also back ground object can cast shadow).");//ADEGLI
505    arguments.getApplicationUsage()->addCommandLineOption("--NVidea", "ParallelSplitShadowMap set default PolygonOffset for NVidea.");//ADEGLI
506    arguments.getApplicationUsage()->addCommandLineOption("--PolyOffset-Factor", "ParallelSplitShadowMap set PolygonOffset factor.");//ADEGLI
507    arguments.getApplicationUsage()->addCommandLineOption("--PolyOffset-Unit", "ParallelSplitShadowMap set PolygonOffset unit.");//ADEGLI
508    arguments.getApplicationUsage()->addCommandLineOption("--CullFaceFront", "ParallelSplitShadowMap add a cull face: front.");//ADEGLI
509
510   
511    arguments.getApplicationUsage()->addCommandLineOption("-1", "Use test model one.");
512    arguments.getApplicationUsage()->addCommandLineOption("-2", "Use test model two.");
513    arguments.getApplicationUsage()->addCommandLineOption("-3", "Use test model three.");
514    arguments.getApplicationUsage()->addCommandLineOption("--two-sided", "Use two-sided stencil extension for shadow volumes.");
515    arguments.getApplicationUsage()->addCommandLineOption("--two-pass", "Use two-pass stencil for shadow volumes.");
516
517
518    // construct the viewer.
519    osgViewer::Viewer viewer(arguments);
520
521    // if user request help write it out to cout.
522    if (arguments.read("-h") || arguments.read("--help"))
523    {
524        arguments.getApplicationUsage()->write(std::cout);
525        return 1;
526    }
527
528    // default to single threaded during dev work.
529    viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
530   
531    while (arguments.read("--SingleThreaded")) viewer.setThreadingModel(osgViewer::Viewer::SingleThreaded);
532    while (arguments.read("--CullDrawThreadPerContext")) viewer.setThreadingModel(osgViewer::Viewer::CullDrawThreadPerContext);
533    while (arguments.read("--DrawThreadPerContext")) viewer.setThreadingModel(osgViewer::Viewer::DrawThreadPerContext);
534    while (arguments.read("--CullThreadPerCameraDrawThreadPerContext")) viewer.setThreadingModel(osgViewer::Viewer::CullThreadPerCameraDrawThreadPerContext);
535
536
537    bool postionalLight = true;
538    while (arguments.read("--positionalLight")) postionalLight = true;
539    while (arguments.read("--directionalLight")) postionalLight = false;
540
541    bool updateLightPosition = true;
542    while (arguments.read("--noUpdate")) updateLightPosition = false;
543
544
545    int screenNum = -1;
546    while (arguments.read("--screen", screenNum)) viewer.setUpViewOnSingleScreen(screenNum);
547
548    // set up the camera manipulators.
549    {
550        osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
551
552        keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() );
553        keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() );
554        keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() );
555        keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );
556
557        std::string pathfile;
558        char keyForAnimationPath = '5';
559        while (arguments.read("-p",pathfile))
560        {
561            osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile);
562            if (apm || !apm->valid())
563            {
564                unsigned int num = keyswitchManipulator->getNumMatrixManipulators();
565                keyswitchManipulator->addMatrixManipulator( keyForAnimationPath, "Path", apm );
566                keyswitchManipulator->selectMatrixManipulator(num);
567                ++keyForAnimationPath;
568            }
569        }
570
571        viewer.setCameraManipulator( keyswitchManipulator.get() );
572    }
573
574    // add the state manipulator
575    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
576
577    // add stats
578    viewer.addEventHandler( new osgViewer::StatsHandler() );
579
580    // add the record camera path handler
581    viewer.addEventHandler(new osgViewer::RecordCameraPathHandler);
582
583
584    osg::ref_ptr<osgShadow::ShadowedScene> shadowedScene = new osgShadow::ShadowedScene;
585   
586    shadowedScene->setReceivesShadowTraversalMask(ReceivesShadowTraversalMask);
587    shadowedScene->setCastsShadowTraversalMask(CastsShadowTraversalMask);
588   
589   
590    if (arguments.read("--sv"))
591    {
592        // hint to tell viewer to request stencil buffer when setting up windows
593        osg::DisplaySettings::instance()->setMinimumNumStencilBits(8);
594
595        osg::ref_ptr<osgShadow::ShadowVolume> sv = new osgShadow::ShadowVolume;
596        sv->setDynamicShadowVolumes(updateLightPosition);
597        while (arguments.read("--two-sided")) sv->setDrawMode(osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED);
598        while (arguments.read("--two-pass")) sv->setDrawMode(osgShadow::ShadowVolumeGeometry::STENCIL_TWO_PASS);
599
600        shadowedScene->setShadowTechnique(sv.get());
601    }
602    else if (arguments.read("--st"))
603    {
604        osg::ref_ptr<osgShadow::ShadowTexture> st = new osgShadow::ShadowTexture;
605        shadowedScene->setShadowTechnique(st.get());
606    }
607    else if (arguments.read("--pssm"))
608    {
609        int mapcount = 3;
610        while (arguments.read("--mapcount", mapcount));
611        osg::ref_ptr<osgShadow::ParallelSplitShadowMap> pssm = new osgShadow::ParallelSplitShadowMap(NULL,mapcount);
612
613        int mapres = 1024;
614        while (arguments.read("--mapres", mapres))
615            pssm->setTextureResolution(mapres);
616       
617        while (arguments.read("--debug-color")) { pssm->setDebugColorOn(); }
618         
619
620        int minNearSplit=0;
621        while (arguments.read("--minNearSplit", minNearSplit))
622            if ( minNearSplit > 0 ) {
623                pssm->setMinNearDistanceForSplits(minNearSplit);
624                std::cout << "ParallelSplitShadowMap : setMinNearDistanceForSplits(" << minNearSplit <<")" << std::endl;
625            }
626
627        int maxfardist = 0;
628        while (arguments.read("--maxFarDist", maxfardist))
629            if ( maxfardist > 0 ) {
630                pssm->setMaxFarDistance(maxfardist);
631                std::cout << "ParallelSplitShadowMap : setMaxFarDistance(" << maxfardist<<")" << std::endl;
632            }
633
634        int moveVCamFactor = 0;
635        while (arguments.read("--moveVCamFactor", moveVCamFactor))
636            if ( maxfardist > 0 ) {
637                pssm->setMoveVCamBehindRCamFactor(moveVCamFactor);
638                std::cout << "ParallelSplitShadowMap : setMoveVCamBehindRCamFactor(" << moveVCamFactor<<")" << std::endl;
639            }
640           
641
642        double polyoffsetfactor = -0.02;
643        double polyoffsetunit = 1.0;
644        while (arguments.read("--PolyOffset-Factor", polyoffsetfactor));
645        while (arguments.read("--PolyOffset-Unit", polyoffsetunit));
646        pssm->setPolygonOffset(osg::Vec2(polyoffsetfactor,polyoffsetunit)); //ATI Radeon
647
648        if (arguments.read("--NVidea")){
649            //pssm->setPolygonOffset(osg::Vec2(-0.02,1.0)); //ATI Radeon
650            pssm->setPolygonOffset(osg::Vec2(10.0f,20.0f)); //NVidea
651        }
652
653        if ( arguments.read("--CullFaceFront") ) {
654            pssm->forceFrontCullFace();
655        }
656
657        shadowedScene->setShadowTechnique(pssm.get());
658    }
659    else if (arguments.read("--ssm"))
660    {
661        osg::ref_ptr<osgShadow::SoftShadowMap> sm = new osgShadow::SoftShadowMap;
662        shadowedScene->setShadowTechnique(sm.get());
663    }
664    else /* if (arguments.read("--sm")) */
665    {
666        osg::ref_ptr<osgShadow::ShadowMap> sm = new osgShadow::ShadowMap;
667        shadowedScene->setShadowTechnique(sm.get());
668
669        int mapres = 1024;
670        while (arguments.read("--mapres", mapres))
671            sm->setTextureSize(osg::Vec2s(mapres,mapres));
672   }
673   
674    osg::ref_ptr<osg::Node> model = osgDB::readNodeFiles(arguments);
675    if (model.valid())
676    {
677        model->setNodeMask(CastsShadowTraversalMask | ReceivesShadowTraversalMask);
678    }
679    else
680    {
681        model = createTestModel(arguments);
682    }
683
684    // get the bounds of the model.   
685    osg::ComputeBoundsVisitor cbbv;
686    model->accept(cbbv);
687    osg::BoundingBox bb = cbbv.getBoundingBox();
688
689    osg::Vec4 lightpos;
690   
691    if (postionalLight)
692    {
693        lightpos.set(bb.center().x(), bb.center().y(), bb.zMax() + bb.radius()  ,1.0f);
694    }
695    else
696    {
697        lightpos.set(0.5f,0.25f,0.8f,0.0f);
698    }
699
700
701    if ( arguments.read("--base"))
702    {
703
704        osg::Geode* geode = new osg::Geode;
705       
706        osg::Vec3 widthVec(bb.radius(), 0.0f, 0.0f);
707        osg::Vec3 depthVec(0.0f, bb.radius(), 0.0f);
708        osg::Vec3 centerBase( (bb.xMin()+bb.xMax())*0.5f, (bb.yMin()+bb.yMax())*0.5f, bb.zMin()-bb.radius()*0.1f );
709       
710        geode->addDrawable( osg::createTexturedQuadGeometry( centerBase-widthVec*1.5f-depthVec*1.5f,
711                                                             widthVec*3.0f, depthVec*3.0f) );
712                                                             
713        geode->setNodeMask(shadowedScene->getReceivesShadowTraversalMask());
714       
715        geode->getOrCreateStateSet()->setTextureAttributeAndModes(0, new osg::Texture2D(osgDB::readImageFile("Images/lz.rgb")));
716
717        shadowedScene->addChild(geode);
718    }
719
720    osg::ref_ptr<osg::LightSource> ls = new osg::LightSource;
721    ls->getLight()->setPosition(lightpos);
722   
723    bool spotlight = false;
724    if (arguments.read("--spotLight"))
725    {
726        spotlight = true;
727
728        osg::Vec3 center = bb.center();
729        osg::Vec3 lightdir = center - osg::Vec3(lightpos.x(), lightpos.y(), lightpos.z());
730        lightdir.normalize();
731        ls->getLight()->setDirection(lightdir);
732        ls->getLight()->setSpotCutoff(30.0f);
733
734        //set the LightSource, only for checking, there is only 1 light in the scene
735        dynamic_cast<osgShadow::ShadowMap*>(shadowedScene->getShadowTechnique())->setLight(ls.get());
736    }
737
738    if ( arguments.read("--coloured-light"))
739    {
740        ls->getLight()->setAmbient(osg::Vec4(1.0,0.0,0.0,1.0));
741        ls->getLight()->setDiffuse(osg::Vec4(0.0,1.0,0.0,1.0));
742    }
743    else
744    {
745        ls->getLight()->setAmbient(osg::Vec4(0.2,0.2,0.2,1.0));
746        ls->getLight()->setDiffuse(osg::Vec4(0.8,0.8,0.8,1.0));
747    }
748
749    shadowedScene->addChild(model.get());
750    shadowedScene->addChild(ls.get());
751   
752    viewer.setSceneData(shadowedScene.get());
753
754    // create the windows and run the threads.
755    viewer.realize();
756
757    // it is done after viewer.realize() so that the windows are already initialized
758    if ( arguments.read("--debugHUD"))
759    {
760        osgViewer::Viewer::Windows windows;
761        viewer.getWindows(windows);
762       
763        if (windows.empty()) return 1;
764       
765        osgShadow::ShadowMap* sm = dynamic_cast<osgShadow::ShadowMap*>(shadowedScene->getShadowTechnique());
766        osg::ref_ptr<osg::Camera> hudCamera = sm->makeDebugHUD();
767       
768        // set up cameras to rendering on the first window available.
769        hudCamera->setGraphicsContext(windows[0]);
770        hudCamera->setViewport(0,0,windows[0]->getTraits()->width, windows[0]->getTraits()->height);
771
772        viewer.addSlave(hudCamera.get(), false);
773    }
774
775
776    // osgDB::writeNodeFile(*group,"test.osg");
777
778    while (!viewer.done())
779    {
780        if (updateLightPosition)
781        {
782            float t = viewer.getFrameStamp()->getSimulationTime();
783            if (postionalLight)
784            {
785                lightpos.set(bb.center().x()+sinf(t)*bb.radius(), bb.center().y() + cosf(t)*bb.radius(), bb.zMax() + bb.radius()*2.0f  ,1.0f);
786            }
787            else
788            {
789                lightpos.set(sinf(t),cosf(t),1.0f,0.0f);
790            }
791            ls->getLight()->setPosition(lightpos);
792           
793            osg::Vec3f lightDir(-lightpos.x(),-lightpos.y(),-lightpos.z());
794            if(spotlight)
795                lightDir =  osg::Vec3(bb.center().x()+sinf(t)*bb.radius()/2.0, bb.center().y() + cosf(t)*bb.radius()/2.0, bb.center().z())
796                - osg::Vec3(lightpos.x(), lightpos.y(), lightpos.z()) ;
797            lightDir.normalize();
798            ls->getLight()->setDirection(lightDir);
799        }
800
801        viewer.frame();
802    }
803   
804    return 0;
805}
Note: See TracBrowser for help on using the browser.