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

Revision 12750, 39.4 kB (checked in by robert, 22 months ago)

Added public interface for selecting use of perspective and light space perspective shadow maps. Implementation
of backends not implemented yet so will follow.

  • 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("--lispsm")) vdsm->setShadowMapProjectionHint(osgShadow::ViewDependentShadowMap::LIGHT_SPACE_PERSPECTIVE_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.