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

Revision 12761, 39.4 kB (checked in by robert, 3 years ago)

Changed new ViewDependentShadowMap? to default to a perspective shadow map with automatic detection of a spot light/perspetive light projection
matrix to prevent inappropriate usage of perspective shadow map.

  • 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#include <osgShadow/LightSpacePerspectiveShadowMap>
45#include <osgShadow/StandardShadowMap>
46#include <osgShadow/ViewDependentShadowMap>
47
48#include <osgDB/ReadFile>
49#include <osgDB/WriteFile>
50
51#include <osg/io_utils>
52#include <iostream>
53
54
55// for the grid data..
56#include "terrain_coords.h"
57// for the model number four - island scene
58#include "IslandScene.h"
59
60
61class ChangeFOVHandler : public osgGA::GUIEventHandler
62{
63public:
64    ChangeFOVHandler(osg::Camera* camera)
65        : _camera(camera)
66    {
67        double fovy, aspectRatio, zNear, zFar;
68        _camera->getProjectionMatrix().getPerspective(fovy, aspectRatio, zNear, zFar);
69        std::cout << "FOV is " << fovy << std::endl;
70    }
71
72    /** Deprecated, Handle events, return true if handled, false otherwise. */
73    virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
74    {
75        if (ea.getEventType() == osgGA::GUIEventAdapter::KEYUP)
76        {
77            if (ea.getKey() == '-' || ea.getKey() == '=' || ea.getKey() == '0')
78            {
79                double fovy, aspectRatio, zNear, zFar;
80                _camera->getProjectionMatrix().getPerspective(fovy, aspectRatio, zNear, zFar);
81
82                if (ea.getKey() == '-')
83                {
84                    fovy -= 5.0;
85                }
86
87                if (ea.getKey() == '=')
88                {
89                    fovy += 5.0;
90                }
91
92                if (ea.getKey() == '0')
93                {
94                    fovy = 45.0;
95                }
96
97                std::cout << "Setting FOV to " << fovy << std::endl;
98                _camera->getProjectionMatrix().makePerspective(fovy, aspectRatio, zNear, zFar);
99
100                return true;
101            }
102        }
103
104        return false;
105    }
106
107    osg::ref_ptr<osg::Camera> _camera;
108};
109
110
111class DumpShadowVolumesHandler : public osgGA::GUIEventHandler
112{
113public:
114    DumpShadowVolumesHandler(  )
115    {
116        set( false );
117    }
118
119    bool get() { return _value; }
120    void set( bool value ) { _value = value; }
121
122    /** Deprecated, Handle events, return true if handled, false otherwise. */
123    virtual bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa)
124    {
125        if (ea.getEventType() == osgGA::GUIEventAdapter::KEYUP)
126        {
127            if (ea.getKey() == 'D' )
128            {
129                set( true );
130                return true;
131            }
132        }
133
134        return false;
135    }
136
137    bool  _value;
138};
139
140
141static int ReceivesShadowTraversalMask = 0x1;
142static int CastsShadowTraversalMask = 0x2;
143
144namespace ModelOne
145{
146
147    enum Faces
148    {
149        FRONT_FACE = 1,
150        BACK_FACE = 2,
151        LEFT_FACE = 4,
152        RIGHT_FACE = 8,
153        TOP_FACE = 16,
154        BOTTOM_FACE = 32
155    };
156
157    osg::Node* createCube(unsigned int mask)
158    {
159        osg::Geode* geode = new osg::Geode;
160
161        osg::Geometry* geometry = new osg::Geometry;
162        geode->addDrawable(geometry);
163
164        osg::Vec3Array* vertices = new osg::Vec3Array;
165        geometry->setVertexArray(vertices);
166
167        osg::Vec3Array* normals = new osg::Vec3Array;
168        geometry->setNormalArray(normals);
169        geometry->setNormalBinding(osg::Geometry::BIND_PER_VERTEX);
170
171        osg::Vec4Array* colours = new osg::Vec4Array;
172        geometry->setColorArray(colours);
173        geometry->setColorBinding(osg::Geometry::BIND_OVERALL);
174        colours->push_back(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
175
176
177        osg::Vec3 origin(0.0f,0.0f,0.0f);
178        osg::Vec3 dx(2.0f,0.0f,0.0f);
179        osg::Vec3 dy(0.0f,1.0f,0.0f);
180        osg::Vec3 dz(0.0f,0.0f,1.0f);
181
182        osg::Vec3 px(1.0f,0.0,0.0f);
183        osg::Vec3 nx(-1.0f,0.0,0.0f);
184        osg::Vec3 py(0.0f,1.0f,0.0f);
185        osg::Vec3 ny(0.0f,-1.0f,0.0f);
186        osg::Vec3 pz(0.0f,0.0f,1.0f);
187        osg::Vec3 nz(0.0f,0.0f,-1.0f);
188
189        if (mask & FRONT_FACE)
190        {
191            // front face
192            vertices->push_back(origin);
193            vertices->push_back(origin+dx);
194            vertices->push_back(origin+dx+dz);
195            vertices->push_back(origin+dz);
196            normals->push_back(ny);
197            normals->push_back(ny);
198            normals->push_back(ny);
199            normals->push_back(ny);
200        }
201
202        if (mask & BACK_FACE)
203        {
204            // back face
205            vertices->push_back(origin+dy);
206            vertices->push_back(origin+dy+dz);
207            vertices->push_back(origin+dy+dx+dz);
208            vertices->push_back(origin+dy+dx);
209            normals->push_back(py);
210            normals->push_back(py);
211            normals->push_back(py);
212            normals->push_back(py);
213        }
214
215        if (mask & LEFT_FACE)
216        {
217            // left face
218            vertices->push_back(origin+dy);
219            vertices->push_back(origin);
220            vertices->push_back(origin+dz);
221            vertices->push_back(origin+dy+dz);
222            normals->push_back(nx);
223            normals->push_back(nx);
224            normals->push_back(nx);
225            normals->push_back(nx);
226        }
227
228        if (mask & RIGHT_FACE)
229        {
230            // right face
231            vertices->push_back(origin+dx+dy);
232            vertices->push_back(origin+dx+dy+dz);
233            vertices->push_back(origin+dx+dz);
234            vertices->push_back(origin+dx);
235            normals->push_back(px);
236            normals->push_back(px);
237            normals->push_back(px);
238            normals->push_back(px);
239        }
240
241        if (mask & TOP_FACE)
242        {
243            // top face
244            vertices->push_back(origin+dz);
245            vertices->push_back(origin+dz+dx);
246            vertices->push_back(origin+dz+dx+dy);
247            vertices->push_back(origin+dz+dy);
248            normals->push_back(pz);
249            normals->push_back(pz);
250            normals->push_back(pz);
251            normals->push_back(pz);
252        }
253
254        if (mask & BOTTOM_FACE)
255        {
256            // bottom face
257            vertices->push_back(origin);
258            vertices->push_back(origin+dy);
259            vertices->push_back(origin+dx+dy);
260            vertices->push_back(origin+dx);
261            normals->push_back(nz);
262            normals->push_back(nz);
263            normals->push_back(nz);
264            normals->push_back(nz);
265        }
266
267        geometry->addPrimitiveSet(new osg::DrawArrays(GL_QUADS, 0, vertices->size()));
268
269        return geode;
270    }
271
272    class SwitchHandler : public osgGA::GUIEventHandler
273    {
274    public:
275
276        SwitchHandler():
277            _childNum(0) {}
278
279        virtual bool handle(const osgGA::GUIEventAdapter& ea,osgGA::GUIActionAdapter& /*aa*/, osg::Object* object, osg::NodeVisitor* /*nv*/)
280        {
281            osg::Switch* sw = dynamic_cast<osg::Switch*>(object);
282            if (!sw) return false;
283
284            if (ea.getHandled()) return false;
285
286            switch(ea.getEventType())
287            {
288                case(osgGA::GUIEventAdapter::KEYDOWN):
289                {
290                    if (ea.getKey()=='n')
291                    {
292                        ++_childNum;
293                        if (_childNum >= sw->getNumChildren()) _childNum = 0;
294
295                        sw->setSingleChildOn(_childNum);
296                        return true;
297                    }
298                    break;
299                }
300                default:
301                    break;
302            }
303            return false;
304        }
305
306    protected:
307
308        virtual ~SwitchHandler() {}
309        unsigned int    _childNum;
310
311    };
312
313
314    osg::Node* createModel(osg::ArgumentParser& /*arguments*/)
315    {
316        osg::Switch* sw = new osg::Switch;
317        sw->setEventCallback(new ModelOne::SwitchHandler);
318
319        sw->addChild(ModelOne::createCube(ModelOne::FRONT_FACE), true);
320        sw->addChild(ModelOne::createCube(ModelOne::FRONT_FACE | ModelOne::BACK_FACE), false);
321        sw->addChild(ModelOne::createCube(ModelOne::FRONT_FACE | ModelOne::BACK_FACE | ModelOne::LEFT_FACE), false);
322        sw->addChild(ModelOne::createCube(ModelOne::FRONT_FACE | ModelOne::BACK_FACE | ModelOne::LEFT_FACE | ModelOne::RIGHT_FACE), false);
323        sw->addChild(ModelOne::createCube(ModelOne::FRONT_FACE | ModelOne::BACK_FACE | ModelOne::LEFT_FACE | ModelOne::RIGHT_FACE | ModelOne::TOP_FACE), false);
324        sw->addChild(ModelOne::createCube(ModelOne::FRONT_FACE | ModelOne::BACK_FACE | ModelOne::LEFT_FACE | ModelOne::RIGHT_FACE | ModelOne::TOP_FACE | ModelOne::BOTTOM_FACE), false);
325
326        return sw;
327    }
328}
329
330namespace ModelTwo
331{
332    osg::AnimationPath* createAnimationPath(const osg::Vec3& center,float radius,double looptime)
333    {
334        // set up the animation path
335        osg::AnimationPath* animationPath = new osg::AnimationPath;
336        animationPath->setLoopMode(osg::AnimationPath::LOOP);
337
338        int numSamples = 40;
339        float yaw = 0.0f;
340        float yaw_delta = 2.0f*osg::PI/((float)numSamples-1.0f);
341        float roll = osg::inDegrees(30.0f);
342
343        double time=0.0f;
344        double time_delta = looptime/(double)numSamples;
345        for(int i=0;i<numSamples;++i)
346        {
347            osg::Vec3 position(center+osg::Vec3(sinf(yaw)*radius,cosf(yaw)*radius,0.0f));
348            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)));
349
350            animationPath->insert(time,osg::AnimationPath::ControlPoint(position,rotation));
351
352            yaw += yaw_delta;
353            time += time_delta;
354
355        }
356        return animationPath;
357    }
358
359    osg::Node* createBase(const osg::Vec3& center,float radius)
360    {
361
362        osg::Geode* geode = new osg::Geode;
363
364        // set up the texture of the base.
365        osg::StateSet* stateset = new osg::StateSet();
366        osg::Image* image = osgDB::readImageFile("Images/lz.rgb");
367        if (image)
368        {
369            osg::Texture2D* texture = new osg::Texture2D;
370            texture->setImage(image);
371            stateset->setTextureAttributeAndModes(0,texture,osg::StateAttribute::ON);
372        }
373
374        geode->setStateSet( stateset );
375
376
377        osg::HeightField* grid = new osg::HeightField;
378        grid->allocate(38,39);
379        grid->setOrigin(center+osg::Vec3(-radius,-radius,0.0f));
380        grid->setXInterval(radius*2.0f/(float)(38-1));
381        grid->setYInterval(radius*2.0f/(float)(39-1));
382
383        float minHeight = FLT_MAX;
384        float maxHeight = -FLT_MAX;
385
386
387        unsigned int r;
388        for(r=0;r<39;++r)
389        {
390            for(unsigned int c=0;c<38;++c)
391            {
392                float h = vertex[r+c*39][2];
393                if (h>maxHeight) maxHeight=h;
394                if (h<minHeight) minHeight=h;
395            }
396        }
397
398        float hieghtScale = radius*0.5f/(maxHeight-minHeight);
399        float hieghtOffset = -(minHeight+maxHeight)*0.5f;
400
401        for(r=0;r<39;++r)
402        {
403            for(unsigned int c=0;c<38;++c)
404            {
405                float h = vertex[r+c*39][2];
406                grid->setHeight(c,r,(h+hieghtOffset)*hieghtScale);
407            }
408        }
409
410        geode->addDrawable(new osg::ShapeDrawable(grid));
411
412        osg::Group* group = new osg::Group;
413        group->addChild(geode);
414
415        return group;
416
417    }
418
419    osg::Node* createMovingModel(const osg::Vec3& center, float radius)
420    {
421        float animationLength = 10.0f;
422
423        osg::AnimationPath* animationPath = createAnimationPath(center,radius,animationLength);
424
425        osg::Group* model = new osg::Group;
426
427        osg::Node* cessna = osgDB::readNodeFile("cessna.osgt");
428        if (cessna)
429        {
430            const osg::BoundingSphere& bs = cessna->getBound();
431
432            float size = radius/bs.radius()*0.3f;
433            osg::MatrixTransform* positioned = new osg::MatrixTransform;
434            positioned->setDataVariance(osg::Object::STATIC);
435            positioned->setMatrix(osg::Matrix::translate(-bs.center())*
436                                  osg::Matrix::scale(size,size,size)*
437                                  osg::Matrix::rotate(osg::inDegrees(180.0f),0.0f,0.0f,2.0f));
438
439            positioned->addChild(cessna);
440
441            osg::MatrixTransform* xform = new osg::MatrixTransform;
442            xform->setUpdateCallback(new osg::AnimationPathCallback(animationPath,0.0f,2.0));
443            xform->addChild(positioned);
444
445            model->addChild(xform);
446        }
447
448        return model;
449    }
450
451    osg::Node* createModel(osg::ArgumentParser& /*arguments*/)
452    {
453        osg::Vec3 center(0.0f,0.0f,0.0f);
454        float radius = 100.0f;
455        osg::Vec3 lightPosition(center+osg::Vec3(0.0f,0.0f,radius));
456
457        // the shadower model
458        osg::Node* shadower = createMovingModel(center,radius*0.5f);
459        shadower->setNodeMask(CastsShadowTraversalMask);
460
461        // the shadowed model
462        osg::Node* shadowed = createBase(center-osg::Vec3(0.0f,0.0f,radius*0.25),radius);
463        shadowed->setNodeMask(ReceivesShadowTraversalMask);
464
465        osg::Group* group = new osg::Group;
466
467        group->addChild(shadowed);
468        group->addChild(shadower);
469
470        return group;
471    }
472}
473
474namespace ModelThree
475{
476    osg::Group* createModel(osg::ArgumentParser& arguments)
477    {
478        osg::Group* scene = new osg::Group;
479
480        osg::ref_ptr<osg::Geode> geode_1 = new osg::Geode;
481        scene->addChild(geode_1.get());
482
483        osg::ref_ptr<osg::Geode> geode_2 = new osg::Geode;
484        osg::ref_ptr<osg::MatrixTransform> transform_2 = new osg::MatrixTransform;
485        transform_2->addChild(geode_2.get());
486//        transform_2->setUpdateCallback(new osg::AnimationPathCallback(osg::Vec3(0, 0, 0), osg::Z_AXIS, osg::inDegrees(45.0f)));
487        scene->addChild(transform_2.get());
488
489        osg::ref_ptr<osg::Geode> geode_3 = new osg::Geode;
490        osg::ref_ptr<osg::MatrixTransform> transform_3 = new osg::MatrixTransform;
491        transform_3->addChild(geode_3.get());
492//        transform_3->setUpdateCallback(new osg::AnimationPathCallback(osg::Vec3(0, 0, 0), osg::Z_AXIS, osg::inDegrees(-22.5f)));
493        scene->addChild(transform_3.get());
494
495        const float radius = 0.8f;
496        const float height = 1.0f;
497        osg::ref_ptr<osg::TessellationHints> hints = new osg::TessellationHints;
498        hints->setDetailRatio(2.0f);
499        osg::ref_ptr<osg::ShapeDrawable> shape;
500
501        shape = new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0f, 0.0f, -2.0f), 10, 10.0f, 0.1f), hints.get());
502        shape->setColor(osg::Vec4(0.5f, 0.5f, 0.7f, 1.0f));
503        geode_1->addDrawable(shape.get());
504
505        shape = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(0.0f, 0.0f, 0.0f), radius * 2), hints.get());
506        shape->setColor(osg::Vec4(0.8f, 0.8f, 0.8f, 1.0f));
507        geode_1->addDrawable(shape.get());
508
509        shape = new osg::ShapeDrawable(new osg::Sphere(osg::Vec3(-3.0f, 0.0f, 0.0f), radius), hints.get());
510        shape->setColor(osg::Vec4(0.6f, 0.8f, 0.8f, 1.0f));
511        geode_2->addDrawable(shape.get());
512
513        shape = new osg::ShapeDrawable(new osg::Box(osg::Vec3(3.0f, 0.0f, 0.0f), 2 * radius), hints.get());
514        shape->setColor(osg::Vec4(0.4f, 0.9f, 0.3f, 1.0f));
515        geode_2->addDrawable(shape.get());
516
517        shape = new osg::ShapeDrawable(new osg::Cone(osg::Vec3(0.0f, -3.0f, 0.0f), radius, height), hints.get());
518        shape->setColor(osg::Vec4(0.2f, 0.5f, 0.7f, 1.0f));
519        geode_2->addDrawable(shape.get());
520
521        shape = new osg::ShapeDrawable(new osg::Cylinder(osg::Vec3(0.0f, 3.0f, 0.0f), radius, height), hints.get());
522        shape->setColor(osg::Vec4(1.0f, 0.3f, 0.3f, 1.0f));
523        geode_2->addDrawable(shape.get());
524
525        shape = new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.0f, 0.0f, 3.0f), 2.0f, 2.0f, 0.1f), hints.get());
526        shape->setColor(osg::Vec4(0.8f, 0.8f, 0.4f, 1.0f));
527        geode_3->addDrawable(shape.get());
528
529        // material
530        osg::ref_ptr<osg::Material> matirial = new osg::Material;
531        matirial->setColorMode(osg::Material::DIFFUSE);
532        matirial->setAmbient(osg::Material::FRONT_AND_BACK, osg::Vec4(0, 0, 0, 1));
533        matirial->setSpecular(osg::Material::FRONT_AND_BACK, osg::Vec4(1, 1, 1, 1));
534        matirial->setShininess(osg::Material::FRONT_AND_BACK, 64.0f);
535        scene->getOrCreateStateSet()->setAttributeAndModes(matirial.get(), osg::StateAttribute::ON);
536
537        bool withBaseTexture = true;
538        while(arguments.read("--with-base-texture")) { withBaseTexture = true; }
539        while(arguments.read("--no-base-texture")) { withBaseTexture = false; }
540
541        if (withBaseTexture)
542        {
543            scene->getOrCreateStateSet()->setTextureAttributeAndModes( 0, new osg::Texture2D(osgDB::readImageFile("Images/lz.rgb")), osg::StateAttribute::ON);
544        }
545
546        return scene;
547    }
548
549}
550
551
552osg::Node* createTestModel(osg::ArgumentParser& arguments)
553{
554    if (arguments.read("-1"))
555    {
556        return ModelOne::createModel(arguments);
557    }
558    else if (arguments.read("-2"))
559    {
560        return ModelTwo::createModel(arguments);
561    }
562    else if (arguments.read("-4"))
563    {
564        return ModelFour::createModel(arguments);
565    }
566    else /*if (arguments.read("-3"))*/
567    {
568        return ModelThree::createModel(arguments);
569    }
570
571}
572
573
574int main(int argc, char** argv)
575{
576    // use an ArgumentParser object to manage the program arguments.
577    osg::ArgumentParser arguments(&argc, argv);
578
579    // set up the usage document, in case we need to print out how to use this program.
580    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName() + " is the example which demonstrates using of GL_ARB_shadow extension implemented in osg::Texture class");
581    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName());
582    arguments.getApplicationUsage()->addCommandLineOption("-h or --help", "Display this information");
583    arguments.getApplicationUsage()->addCommandLineOption("--positionalLight", "Use a positional light.");
584    arguments.getApplicationUsage()->addCommandLineOption("--directionalLight", "Use a direction light.");
585    arguments.getApplicationUsage()->addCommandLineOption("--noUpdate", "Disable the updating the of light source.");
586
587    arguments.getApplicationUsage()->addCommandLineOption("--castsShadowMask", "Override default castsShadowMask (default - 0x2)");
588    arguments.getApplicationUsage()->addCommandLineOption("--receivesShadowMask", "Override default receivesShadowMask (default - 0x1)");
589
590    arguments.getApplicationUsage()->addCommandLineOption("--base", "Add a base geometry to test shadows.");
591    arguments.getApplicationUsage()->addCommandLineOption("--sv", "Select ShadowVolume implementation.");
592    arguments.getApplicationUsage()->addCommandLineOption("--ssm", "Select SoftShadowMap implementation.");
593    arguments.getApplicationUsage()->addCommandLineOption("--sm", "Select ShadowMap implementation.");
594
595    arguments.getApplicationUsage()->addCommandLineOption("--pssm", "Select ParallelSplitShadowMap implementation.");//ADEGLI
596    arguments.getApplicationUsage()->addCommandLineOption("--mapcount", "ParallelSplitShadowMap texture count.");//ADEGLI
597    arguments.getApplicationUsage()->addCommandLineOption("--mapres", "ParallelSplitShadowMap texture resolution.");//ADEGLI
598    arguments.getApplicationUsage()->addCommandLineOption("--debug-color", "ParallelSplitShadowMap display debugging color (only the first 3 maps are color r=0,g=1,b=2.");//ADEGLI
599    arguments.getApplicationUsage()->addCommandLineOption("--minNearSplit", "ParallelSplitShadowMap shadow map near offset.");//ADEGLI
600    arguments.getApplicationUsage()->addCommandLineOption("--maxFarDist", "ParallelSplitShadowMap max far distance to shadow.");//ADEGLI
601    arguments.getApplicationUsage()->addCommandLineOption("--moveVCamFactor", "ParallelSplitShadowMap move the virtual frustum behind the real camera, (also back ground object can cast shadow).");//ADEGLI
602    arguments.getApplicationUsage()->addCommandLineOption("--PolyOffset-Factor", "ParallelSplitShadowMap set PolygonOffset factor.");//ADEGLI
603    arguments.getApplicationUsage()->addCommandLineOption("--PolyOffset-Unit", "ParallelSplitShadowMap set PolygonOffset unit.");//ADEGLI
604
605    arguments.getApplicationUsage()->addCommandLineOption("--lispsm", "Select LightSpacePerspectiveShadowMap implementation.");
606    arguments.getApplicationUsage()->addCommandLineOption("--msm", "Select MinimalShadowMap implementation.");
607    arguments.getApplicationUsage()->addCommandLineOption("--ViewBounds", "MSM, LiSPSM optimize shadow for view frustum (weakest option)");
608    arguments.getApplicationUsage()->addCommandLineOption("--CullBounds", "MSM, LiSPSM optimize shadow for bounds of culled objects in view frustum (better option).");
609    arguments.getApplicationUsage()->addCommandLineOption("--DrawBounds", "MSM, LiSPSM optimize shadow for bounds of predrawn pixels in view frustum (best & default).");
610    arguments.getApplicationUsage()->addCommandLineOption("--mapres", "MSM, LiSPSM & texture resolution.");
611    arguments.getApplicationUsage()->addCommandLineOption("--maxFarDist", "MSM, LiSPSM max far distance to shadow.");
612    arguments.getApplicationUsage()->addCommandLineOption("--moveVCamFactor", "MSM, LiSPSM move the virtual frustum behind the real camera, (also back ground object can cast shadow).");
613    arguments.getApplicationUsage()->addCommandLineOption("--minLightMargin", "MSM, LiSPSM the same as --moveVCamFactor.");
614
615    arguments.getApplicationUsage()->addCommandLineOption("-1", "Use test model one.");
616    arguments.getApplicationUsage()->addCommandLineOption("-2", "Use test model two.");
617    arguments.getApplicationUsage()->addCommandLineOption("-3", "Use test model three (default).");
618    arguments.getApplicationUsage()->addCommandLineOption("-4", "Use test model four - island scene.");
619    arguments.getApplicationUsage()->addCommandLineOption("--two-sided", "Use two-sided stencil extension for shadow volumes.");
620    arguments.getApplicationUsage()->addCommandLineOption("--two-pass", "Use two-pass stencil for shadow volumes.");
621
622    // construct the viewer.
623    osgViewer::Viewer viewer(arguments);
624
625    // if user request help write it out to cout.
626    if (arguments.read("-h") || arguments.read("--help"))
627    {
628        arguments.getApplicationUsage()->write(std::cout);
629        return 1;
630    }
631
632    double zNear=1.0, zMid=10.0, zFar=1000.0;
633    if (arguments.read("--depth-partition",zNear, zMid, zFar))
634    {
635        // set up depth partitioning
636        osg::ref_ptr<osgViewer::DepthPartitionSettings> dps = new osgViewer::DepthPartitionSettings;
637        dps->_mode = osgViewer::DepthPartitionSettings::FIXED_RANGE;
638        dps->_zNear = zNear;
639        dps->_zMid = zMid;
640        dps->_zFar = zFar;
641        viewer.setUpDepthPartition(dps.get());
642    }
643
644    if (arguments.read("--dp"))
645    {
646        // set up depth partitioning
647        viewer.setUpDepthPartition();
648    }
649
650    float fov = 0.0;
651    while (arguments.read("--fov",fov)) {}
652
653    osg::Vec4 lightpos(0.0,0.0,1,0.0);
654    bool spotlight = false;
655    while (arguments.read("--positionalLight")) { lightpos.set(0.5,0.5,1.5,1.0); }
656    while (arguments.read("--directionalLight")) { lightpos.set(0.0,0.0,1,0.0); }
657    while (arguments.read("--spotLight")) { lightpos.set(0.5,0.5,1.5,1.0); spotlight = true; }
658
659    bool keepLightPos = false;
660    osg::Vec3 spotLookat(0.0,0.0,0.0);
661    while ( arguments.read("--light-pos", lightpos.x(), lightpos.y(), lightpos.z(), lightpos.w())) { keepLightPos = true; }
662    while ( arguments.read("--light-pos", lightpos.x(), lightpos.y(), lightpos.z())) { lightpos.w()=1.0; keepLightPos = true; }
663    while ( arguments.read("--light-dir", lightpos.x(), lightpos.y(), lightpos.z())) { lightpos.w()=0.0; keepLightPos = true; }
664    while ( arguments.read("--spot-lookat", spotLookat.x(), spotLookat.y(), spotLookat.z())) { }
665
666
667    while (arguments.read("--castsShadowMask", CastsShadowTraversalMask ));
668    while (arguments.read("--receivesShadowMask", ReceivesShadowTraversalMask ));
669
670    bool updateLightPosition = true;
671    while (arguments.read("--noUpdate")) updateLightPosition = false;
672
673    // set up the camera manipulators.
674    {
675        osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator = new osgGA::KeySwitchMatrixManipulator;
676
677        keyswitchManipulator->addMatrixManipulator( '1', "Trackball", new osgGA::TrackballManipulator() );
678        keyswitchManipulator->addMatrixManipulator( '2', "Flight", new osgGA::FlightManipulator() );
679        keyswitchManipulator->addMatrixManipulator( '3', "Drive", new osgGA::DriveManipulator() );
680        keyswitchManipulator->addMatrixManipulator( '4', "Terrain", new osgGA::TerrainManipulator() );
681
682        std::string pathfile;
683        char keyForAnimationPath = '5';
684        while (arguments.read("-p",pathfile))
685        {
686            osgGA::AnimationPathManipulator* apm = new osgGA::AnimationPathManipulator(pathfile);
687            if (apm || !apm->valid())
688            {
689                unsigned int num = keyswitchManipulator->getNumMatrixManipulators();
690                keyswitchManipulator->addMatrixManipulator( keyForAnimationPath, "Path", apm );
691                keyswitchManipulator->selectMatrixManipulator(num);
692                ++keyForAnimationPath;
693            }
694        }
695
696        viewer.setCameraManipulator( keyswitchManipulator.get() );
697    }
698
699    // add the state manipulator
700    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
701
702    // add stats
703    viewer.addEventHandler( new osgViewer::StatsHandler() );
704
705    // add the record camera path handler
706    viewer.addEventHandler(new osgViewer::RecordCameraPathHandler);
707
708    // add the window size toggle handler
709    viewer.addEventHandler(new osgViewer::WindowSizeHandler);
710
711    // add the threading handler
712    viewer.addEventHandler( new osgViewer::ThreadingHandler() );
713
714    osg::ref_ptr<osgShadow::ShadowedScene> shadowedScene = new osgShadow::ShadowedScene;
715
716    shadowedScene->setReceivesShadowTraversalMask(ReceivesShadowTraversalMask);
717    shadowedScene->setCastsShadowTraversalMask(CastsShadowTraversalMask);
718
719    osg::ref_ptr<osgShadow::MinimalShadowMap> msm = NULL;
720    if (arguments.read("--no-shadows"))
721    {
722        OSG_NOTICE<<"Not using a ShadowTechnique"<<std::endl;
723        shadowedScene->setShadowTechnique(0);
724    }
725    else if (arguments.read("--sv"))
726    {
727        // hint to tell viewer to request stencil buffer when setting up windows
728        osg::DisplaySettings::instance()->setMinimumNumStencilBits(8);
729
730        osg::ref_ptr<osgShadow::ShadowVolume> sv = new osgShadow::ShadowVolume;
731        sv->setDynamicShadowVolumes(updateLightPosition);
732        while (arguments.read("--two-sided")) sv->setDrawMode(osgShadow::ShadowVolumeGeometry::STENCIL_TWO_SIDED);
733        while (arguments.read("--two-pass")) sv->setDrawMode(osgShadow::ShadowVolumeGeometry::STENCIL_TWO_PASS);
734
735        shadowedScene->setShadowTechnique(sv.get());
736    }
737    else if (arguments.read("--st"))
738    {
739        osg::ref_ptr<osgShadow::ShadowTexture> st = new osgShadow::ShadowTexture;
740        shadowedScene->setShadowTechnique(st.get());
741    }
742    else if (arguments.read("--stsm"))
743    {
744        osg::ref_ptr<osgShadow::StandardShadowMap> st = new osgShadow::StandardShadowMap;
745        shadowedScene->setShadowTechnique(st.get());
746    }
747    else if (arguments.read("--pssm"))
748    {
749        int mapcount = 3;
750        while (arguments.read("--mapcount", mapcount));
751        osg::ref_ptr<osgShadow::ParallelSplitShadowMap> pssm = new osgShadow::ParallelSplitShadowMap(NULL,mapcount);
752
753        int mapres = 1024;
754        while (arguments.read("--mapres", mapres))
755            pssm->setTextureResolution(mapres);
756
757        while (arguments.read("--debug-color")) { pssm->setDebugColorOn(); }
758
759
760        int minNearSplit=0;
761        while (arguments.read("--minNearSplit", minNearSplit))
762            if ( minNearSplit > 0 ) {
763                pssm->setMinNearDistanceForSplits(minNearSplit);
764                std::cout << "ParallelSplitShadowMap : setMinNearDistanceForSplits(" << minNearSplit <<")" << std::endl;
765            }
766
767        int maxfardist = 0;
768        while (arguments.read("--maxFarDist", maxfardist))
769            if ( maxfardist > 0 ) {
770                pssm->setMaxFarDistance(maxfardist);
771                std::cout << "ParallelSplitShadowMap : setMaxFarDistance(" << maxfardist<<")" << std::endl;
772            }
773
774        int moveVCamFactor = 0;
775        while (arguments.read("--moveVCamFactor", moveVCamFactor))
776            if ( maxfardist > 0 ) {
777                pssm->setMoveVCamBehindRCamFactor(moveVCamFactor);
778                std::cout << "ParallelSplitShadowMap : setMoveVCamBehindRCamFactor(" << moveVCamFactor<<")" << std::endl;
779            }
780
781
782       
783        double polyoffsetfactor = pssm->getPolygonOffset().x();
784        double polyoffsetunit   = pssm->getPolygonOffset().y();
785        while (arguments.read("--PolyOffset-Factor", polyoffsetfactor));
786        while (arguments.read("--PolyOffset-Unit", polyoffsetunit));
787        pssm->setPolygonOffset(osg::Vec2(polyoffsetfactor,polyoffsetunit));
788
789        shadowedScene->setShadowTechnique(pssm.get());
790    }
791    else if (arguments.read("--ssm"))
792    {
793        osg::ref_ptr<osgShadow::SoftShadowMap> sm = new osgShadow::SoftShadowMap;
794        shadowedScene->setShadowTechnique(sm.get());
795    }
796    else if( arguments.read("--vdsm") )
797    {
798        osg::ref_ptr<osgShadow::ViewDependentShadowMap> vdsm = new osgShadow::ViewDependentShadowMap;
799        while( arguments.read("--debugHUD") ) vdsm->setDebugDraw( true );
800
801        if (arguments.read("--persp")) vdsm->setShadowMapProjectionHint(osgShadow::ViewDependentShadowMap::PERSPECTIVE_SHADOW_MAP);
802        if (arguments.read("--ortho")) vdsm->setShadowMapProjectionHint(osgShadow::ViewDependentShadowMap::ORTHOGRAPHIC_SHADOW_MAP);
803       
804        shadowedScene->setShadowTechnique(vdsm.get());
805    }
806    else if ( arguments.read("--lispsm") )
807    {
808        if( arguments.read( "--ViewBounds" ) )
809            msm = new osgShadow::LightSpacePerspectiveShadowMapVB;
810        else if( arguments.read( "--CullBounds" ) )
811            msm = new osgShadow::LightSpacePerspectiveShadowMapCB;
812        else // if( arguments.read( "--DrawBounds" ) ) // default
813            msm = new osgShadow::LightSpacePerspectiveShadowMapDB;
814    }
815    else if( arguments.read("--msm") )
816    {
817       if( arguments.read( "--ViewBounds" ) )
818            msm = new osgShadow::MinimalShadowMap;
819       else if( arguments.read( "--CullBounds" ) )
820            msm = new osgShadow::MinimalCullBoundsShadowMap;
821       else // if( arguments.read( "--DrawBounds" ) ) // default
822            msm = new osgShadow::MinimalDrawBoundsShadowMap;
823    }
824    else /* if (arguments.read("--sm")) */
825    {
826        osg::ref_ptr<osgShadow::ShadowMap> sm = new osgShadow::ShadowMap;
827        shadowedScene->setShadowTechnique(sm.get());
828
829        int mapres = 1024;
830        while (arguments.read("--mapres", mapres))
831            sm->setTextureSize(osg::Vec2s(mapres,mapres));
832    }
833
834    if( msm )// Set common MSM & LISPSM arguments
835    {
836        shadowedScene->setShadowTechnique( msm.get() );
837        while( arguments.read("--debugHUD") ) msm->setDebugDraw( true );
838
839        float minLightMargin = 10.f;
840        float maxFarPlane = 0;
841        unsigned int texSize = 1024;
842        unsigned int baseTexUnit = 0;
843        unsigned int shadowTexUnit = 1;
844
845        while ( arguments.read("--moveVCamFactor", minLightMargin ) );
846        while ( arguments.read("--minLightMargin", minLightMargin ) );
847        while ( arguments.read("--maxFarDist", maxFarPlane ) );
848        while ( arguments.read("--mapres", texSize ));
849        while ( arguments.read("--baseTextureUnit", baseTexUnit) );
850        while ( arguments.read("--shadowTextureUnit", shadowTexUnit) );
851
852        msm->setMinLightMargin( minLightMargin );
853        msm->setMaxFarPlane( maxFarPlane );
854        msm->setTextureSize( osg::Vec2s( texSize, texSize ) );
855        msm->setShadowTextureCoordIndex( shadowTexUnit );
856        msm->setShadowTextureUnit( shadowTexUnit );
857        msm->setBaseTextureCoordIndex( baseTexUnit );
858        msm->setBaseTextureUnit( baseTexUnit );
859    }
860
861    OSG_NOTICE<<"shadowedScene->getShadowTechnique()="<<shadowedScene->getShadowTechnique()<<std::endl;
862
863    osg::ref_ptr<osg::Node> model = osgDB::readNodeFiles(arguments);
864    if (model.valid())
865    {
866        model->setNodeMask(CastsShadowTraversalMask | ReceivesShadowTraversalMask);
867    }
868    else
869    {
870        model = createTestModel(arguments);
871    }
872
873    // get the bounds of the model.
874    osg::ComputeBoundsVisitor cbbv;
875    model->accept(cbbv);
876    osg::BoundingBox bb = cbbv.getBoundingBox();
877
878    if (lightpos.w()==1.0 && !keepLightPos)
879    {
880        lightpos.x() = bb.xMin()+(bb.xMax()-bb.xMin())*lightpos.x();
881        lightpos.y() = bb.yMin()+(bb.yMax()-bb.yMin())*lightpos.y();
882        lightpos.z() = bb.zMin()+(bb.zMax()-bb.zMin())*lightpos.z();
883    }
884     
885    if ( arguments.read("--base"))
886    {
887
888        osg::Geode* geode = new osg::Geode;
889
890        osg::Vec3 widthVec(bb.radius(), 0.0f, 0.0f);
891        osg::Vec3 depthVec(0.0f, bb.radius(), 0.0f);
892        osg::Vec3 centerBase( (bb.xMin()+bb.xMax())*0.5f, (bb.yMin()+bb.yMax())*0.5f, bb.zMin()-bb.radius()*0.1f );
893
894        geode->addDrawable( osg::createTexturedQuadGeometry( centerBase-widthVec*1.5f-depthVec*1.5f,
895                                                             widthVec*3.0f, depthVec*3.0f) );
896
897        geode->setNodeMask(shadowedScene->getReceivesShadowTraversalMask());
898
899        geode->getOrCreateStateSet()->setTextureAttributeAndModes(0, new osg::Texture2D(osgDB::readImageFile("Images/lz.rgb")));
900
901        shadowedScene->addChild(geode);
902    }
903
904    osg::ref_ptr<osg::LightSource> ls = new osg::LightSource;
905    ls->getLight()->setPosition(lightpos);
906
907    if (spotlight)
908    {
909        osg::Vec3 center = spotLookat;
910        osg::Vec3 lightdir = center - osg::Vec3(lightpos.x(), lightpos.y(), lightpos.z());
911        lightdir.normalize();
912        ls->getLight()->setDirection(lightdir);
913        ls->getLight()->setSpotCutoff(25.0f);
914
915        //set the LightSource, only for checking, there is only 1 light in the scene
916        osgShadow::ShadowMap* shadowMap = dynamic_cast<osgShadow::ShadowMap*>(shadowedScene->getShadowTechnique());
917        if( shadowMap ) shadowMap->setLight(ls.get());
918    }
919
920    if ( arguments.read("--coloured-light"))
921    {
922        ls->getLight()->setAmbient(osg::Vec4(1.0,0.0,0.0,1.0));
923        ls->getLight()->setDiffuse(osg::Vec4(0.0,1.0,0.0,1.0));
924    }
925    else
926    {
927        ls->getLight()->setAmbient(osg::Vec4(0.2,0.2,0.2,1.0));
928        ls->getLight()->setDiffuse(osg::Vec4(0.8,0.8,0.8,1.0));
929    }
930
931    shadowedScene->addChild(model.get());
932    shadowedScene->addChild(ls.get());
933
934    viewer.setSceneData(shadowedScene.get());
935
936    osg::ref_ptr< DumpShadowVolumesHandler > dumpShadowVolumes = new DumpShadowVolumesHandler;
937
938    viewer.addEventHandler(new ChangeFOVHandler(viewer.getCamera()));
939    viewer.addEventHandler( dumpShadowVolumes.get() );
940
941    // create the windows and run the threads.
942    viewer.realize();
943
944    if (fov!=0.0)
945    {
946        double fovy, aspectRatio, zNear, zFar;
947        viewer.getCamera()->getProjectionMatrix().getPerspective(fovy, aspectRatio, zNear, zFar);
948
949        std::cout << "Setting FOV to " << fov << std::endl;
950        viewer.getCamera()->getProjectionMatrix().makePerspective(fov, aspectRatio, zNear, zFar);
951    }
952
953    // it is done after viewer.realize() so that the windows are already initialized
954    if ( arguments.read("--debugHUD"))
955    {
956        osgViewer::Viewer::Windows windows;
957        viewer.getWindows(windows);
958
959        if (windows.empty()) return 1;
960
961        osgShadow::ShadowMap* sm = dynamic_cast<osgShadow::ShadowMap*>(shadowedScene->getShadowTechnique());
962        if( sm ) {
963            osg::ref_ptr<osg::Camera> hudCamera = sm->makeDebugHUD();
964
965            // set up cameras to rendering on the first window available.
966            hudCamera->setGraphicsContext(windows[0]);
967            hudCamera->setViewport(0,0,windows[0]->getTraits()->width, windows[0]->getTraits()->height);
968
969            viewer.addSlave(hudCamera.get(), false);
970        }
971    }
972
973
974    // osgDB::writeNodeFile(*group,"test.osgt");
975 
976    while (!viewer.done())
977    {
978        {
979            osgShadow::MinimalShadowMap * msm = dynamic_cast<osgShadow::MinimalShadowMap*>( shadowedScene->getShadowTechnique() );
980   
981            if( msm ) {
982
983                // If scene decorated by CoordinateSystemNode try to find localToWorld
984                // and set modellingSpaceToWorld matrix to optimize scene bounds computation
985
986                osg::NodePath np = viewer.getCoordinateSystemNodePath();
987                if( !np.empty() ) {
988                    osg::CoordinateSystemNode * csn =
989                        dynamic_cast<osg::CoordinateSystemNode *>( np.back() );
990
991                    if( csn ) {
992                        osg::Vec3d pos =
993                            viewer.getCameraManipulator()->getMatrix().getTrans();
994
995                        msm->setModellingSpaceToWorldTransform
996                            ( csn->computeLocalCoordinateFrame( pos ) );
997                    }
998                }
999            }       
1000        }
1001
1002        if (updateLightPosition)
1003        {
1004            float t = viewer.getFrameStamp()->getSimulationTime();
1005
1006            if (lightpos.w()==1.0)
1007            {
1008                lightpos.set(bb.center().x()+sinf(t)*bb.radius(), bb.center().y() + cosf(t)*bb.radius(), bb.zMax() + bb.radius()*3.0f  ,1.0f);
1009            }
1010            else
1011            {
1012                lightpos.set(sinf(t),cosf(t),1.0f,0.0f);
1013            }
1014            ls->getLight()->setPosition(lightpos);
1015
1016            osg::Vec3f lightDir(-lightpos.x(),-lightpos.y(),-lightpos.z());
1017            if(spotlight)
1018                lightDir =  osg::Vec3(bb.center().x()+sinf(t)*bb.radius()/2.0, bb.center().y() + cosf(t)*bb.radius()/2.0, bb.center().z())
1019                - osg::Vec3(lightpos.x(), lightpos.y(), lightpos.z()) ;
1020            lightDir.normalize();
1021            ls->getLight()->setDirection(lightDir);
1022        }
1023
1024        if( dumpShadowVolumes->get() )
1025        {
1026            dumpShadowVolumes->set( false );
1027
1028            static int dumpFileNo = 0;
1029            dumpFileNo ++;
1030            char filename[256];
1031            std::sprintf( filename, "shadowDump%d.osgt", dumpFileNo );
1032           
1033            osgShadow::MinimalShadowMap * msm = dynamic_cast<osgShadow::MinimalShadowMap*>( shadowedScene->getShadowTechnique() );
1034
1035            if( msm ) msm->setDebugDump( filename );           
1036        }
1037
1038        viewer.frame();
1039    }
1040
1041    return 0;
1042}
Note: See TracBrowser for help on using the browser.