root/OpenSceneGraph/trunk/src/osgShadow/ViewDependentShadowMap.cpp @ 14044

Revision 14044, 85.9 kB (checked in by robert, 4 hours ago)

Standardized on defined(ANDROID)

Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2011 Robert Osfield
2 *
3 * This library is open source and may be redistributed and/or modified under
4 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5 * (at your option) any later version.  The full license is in LICENSE file
6 * included with this distribution, and on the openscenegraph.org website.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11 * OpenSceneGraph Public License for more details.
12*/
13
14#include <osgShadow/ViewDependentShadowMap>
15#include <osgShadow/ShadowedScene>
16#include <osg/CullFace>
17#include <osg/Geode>
18#include <osg/io_utils>
19
20#include <sstream>
21
22using namespace osgShadow;
23
24//////////////////////////////////////////////////////////////////
25// fragment shader
26//
27#if 0
28static const char fragmentShaderSource_withBaseTexture[] =
29        "uniform sampler2D baseTexture;                                          \n"
30        "uniform sampler2DShadow shadowTexture;                                  \n"
31        "                                                                        \n"
32        "void main(void)                                                         \n"
33        "{                                                                       \n"
34        "  vec4 colorAmbientEmissive = gl_FrontLightModelProduct.sceneColor;     \n"
35        "  vec4 color = texture2D( baseTexture, gl_TexCoord[0].xy );                                            \n"
36        "  color *= mix( colorAmbientEmissive, gl_Color, shadow2DProj( shadowTexture, gl_TexCoord[1] ).r );     \n"
37        "  gl_FragColor = color;                                                                                \n"
38        "} \n";
39#else
40static const char fragmentShaderSource_withBaseTexture[] =
41        "uniform sampler2D baseTexture;                                          \n"
42        "uniform int baseTextureUnit;                                            \n"
43        "uniform sampler2DShadow shadowTexture0;                                 \n"
44        "uniform int shadowTextureUnit0;                                         \n"
45        "                                                                        \n"
46        "void main(void)                                                         \n"
47        "{                                                                       \n"
48        "  vec4 colorAmbientEmissive = gl_FrontLightModelProduct.sceneColor;     \n"
49        "  vec4 color = texture2D( baseTexture, gl_TexCoord[baseTextureUnit].xy );                                              \n"
50        "  color *= mix( colorAmbientEmissive, gl_Color, shadow2DProj( shadowTexture0, gl_TexCoord[shadowTextureUnit0] ).r );     \n"
51        "  gl_FragColor = color;                                                                                                \n"
52        "} \n";
53
54static const char fragmentShaderSource_withBaseTexture_twoShadowMaps[] =
55        "uniform sampler2D baseTexture;                                          \n"
56        "uniform int baseTextureUnit;                                            \n"
57        "uniform sampler2DShadow shadowTexture0;                                 \n"
58        "uniform int shadowTextureUnit0;                                         \n"
59        "uniform sampler2DShadow shadowTexture1;                                 \n"
60        "uniform int shadowTextureUnit1;                                         \n"
61        "                                                                        \n"
62        "void main(void)                                                         \n"
63        "{                                                                       \n"
64        "  vec4 colorAmbientEmissive = gl_FrontLightModelProduct.sceneColor;     \n"
65        "  vec4 color = texture2D( baseTexture, gl_TexCoord[baseTextureUnit].xy );              \n"
66        "  float shadow0 = shadow2DProj( shadowTexture0, gl_TexCoord[shadowTextureUnit0] ).r;   \n"
67        "  float shadow1 = shadow2DProj( shadowTexture1, gl_TexCoord[shadowTextureUnit1] ).r;   \n"
68        "  color *= mix( colorAmbientEmissive, gl_Color, shadow0*shadow1 );                     \n"
69        "  gl_FragColor = color;                                                                \n"
70        "} \n";
71#endif
72
73template<class T>
74class RenderLeafTraverser : public T
75{
76public:
77
78    RenderLeafTraverser()
79    {
80    }
81
82    void traverse(const osgUtil::RenderStage* rs)
83    {
84        traverse(static_cast<const osgUtil::RenderBin*>(rs));
85    }
86
87    void traverse(const osgUtil::RenderBin* renderBin)
88    {
89        const osgUtil::RenderBin::RenderBinList& rbl = renderBin->getRenderBinList();
90        for(osgUtil::RenderBin::RenderBinList::const_iterator itr = rbl.begin();
91            itr != rbl.end();
92            ++itr)
93        {
94            traverse(itr->second.get());
95        }
96
97        const osgUtil::RenderBin::RenderLeafList& rll = renderBin->getRenderLeafList();
98        for(osgUtil::RenderBin::RenderLeafList::const_iterator itr = rll.begin();
99            itr != rll.end();
100            ++itr)
101        {
102            handle(*itr);
103        }
104
105        const osgUtil::RenderBin::StateGraphList& rgl = renderBin->getStateGraphList();
106        for(osgUtil::RenderBin::StateGraphList::const_iterator itr = rgl.begin();
107            itr != rgl.end();
108            ++itr)
109        {
110            traverse(*itr);
111        }
112
113    }
114
115    void traverse(const osgUtil::StateGraph* stateGraph)
116    {
117        const osgUtil::StateGraph::ChildList& cl = stateGraph->_children;
118        for(osgUtil::StateGraph::ChildList::const_iterator itr = cl.begin();
119            itr != cl.end();
120            ++itr)
121        {
122            traverse(itr->second.get());
123        }
124
125        const osgUtil::StateGraph::LeafList& ll = stateGraph->_leaves;
126        for(osgUtil::StateGraph::LeafList::const_iterator itr = ll.begin();
127            itr != ll.end();
128            ++itr)
129        {
130            handle(itr->get());
131        }
132    }
133
134    inline void handle(const osgUtil::RenderLeaf* renderLeaf)
135    {
136        this->operator()(renderLeaf);
137    }
138};
139
140///////////////////////////////////////////////////////////////////////////////////////////////
141//
142// VDSMCameraCullCallback
143//
144class VDSMCameraCullCallback : public osg::NodeCallback
145{
146    public:
147
148        VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg::Polytope& polytope);
149
150        virtual void operator()(osg::Node*, osg::NodeVisitor* nv);
151
152        osg::RefMatrix* getProjectionMatrix() { return _projectionMatrix.get(); }
153        osgUtil::RenderStage* getRenderStage() { return _renderStage.get(); }
154
155    protected:
156
157        ViewDependentShadowMap*                 _vdsm;
158        osg::ref_ptr<osg::RefMatrix>            _projectionMatrix;
159        osg::ref_ptr<osgUtil::RenderStage>      _renderStage;
160        osg::Polytope                           _polytope;
161};
162
163VDSMCameraCullCallback::VDSMCameraCullCallback(ViewDependentShadowMap* vdsm, osg::Polytope& polytope):
164    _vdsm(vdsm),
165    _polytope(polytope)
166{
167}
168
169void VDSMCameraCullCallback::operator()(osg::Node* node, osg::NodeVisitor* nv)
170{
171    osgUtil::CullVisitor* cv = dynamic_cast<osgUtil::CullVisitor*>(nv);
172    osg::Camera* camera = dynamic_cast<osg::Camera*>(node);
173    OSG_INFO<<"VDSMCameraCullCallback::operator()(osg::Node* "<<camera<<", osg::NodeVisitor* "<<cv<<")"<<std::endl;
174
175#if 1
176    if (!_polytope.empty())
177    {
178        OSG_INFO<<"Pushing custom Polytope"<<std::endl;
179
180        osg::CullingSet& cs = cv->getProjectionCullingStack().back();
181
182        cs.setFrustum(_polytope);
183
184        cv->pushCullingSet();
185    }
186#endif
187    if (_vdsm->getShadowedScene())
188    {
189        _vdsm->getShadowedScene()->osg::Group::traverse(*nv);
190    }
191#if 1
192    if (!_polytope.empty())
193    {
194        OSG_INFO<<"Popping custom Polytope"<<std::endl;
195        cv->popCullingSet();
196    }
197#endif
198
199    _renderStage = cv->getCurrentRenderBin()->getStage();
200
201    OSG_INFO<<"VDSM second : _renderStage = "<<_renderStage<<std::endl;
202
203    if (cv->getComputeNearFarMode() != osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR)
204    {
205        // make sure that the near plane is computed correctly.
206        cv->computeNearPlane();
207
208        osg::Matrixd projection = *(cv->getProjectionMatrix());
209
210        OSG_INFO<<"RTT Projection matrix "<<projection<<std::endl;
211
212        osg::Matrix::value_type left, right, bottom, top, zNear, zFar;
213        osg::Matrix::value_type epsilon = 1e-6;
214        if (fabs(projection(0,3))<epsilon  && fabs(projection(1,3))<epsilon  && fabs(projection(2,3))<epsilon )
215        {
216            projection.getOrtho(left, right,
217                                bottom, top,
218                                zNear,  zFar);
219
220            OSG_INFO<<"Ortho zNear="<<zNear<<", zFar="<<zFar<<std::endl;
221        }
222        else
223        {
224            projection.getFrustum(left, right,
225                                bottom, top,
226                                zNear,  zFar);
227
228            OSG_INFO<<"Frustum zNear="<<zNear<<", zFar="<<zFar<<std::endl;
229        }
230
231        OSG_INFO<<"Calculated zNear = "<<cv->getCalculatedNearPlane()<<", zFar = "<<cv->getCalculatedFarPlane()<<std::endl;
232
233        zNear = osg::maximum(zNear, cv->getCalculatedNearPlane());
234        zFar = osg::minimum(zFar, cv->getCalculatedFarPlane());
235
236        cv->setCalculatedNearPlane(zNear);
237        cv->setCalculatedFarPlane(zFar);
238
239        cv->clampProjectionMatrix(projection, zNear, zFar);
240
241        //OSG_INFO<<"RTT zNear = "<<zNear<<", zFar = "<<zFar<<std::endl;
242        OSG_INFO<<"RTT Projection matrix after clamping "<<projection<<std::endl;
243
244        camera->setProjectionMatrix(projection);
245
246        _projectionMatrix = cv->getProjectionMatrix();
247    }
248}
249
250
251class ComputeLightSpaceBounds : public osg::NodeVisitor, public osg::CullStack
252{
253public:
254    ComputeLightSpaceBounds(osg::Viewport* viewport, const osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix):
255        osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ACTIVE_CHILDREN)
256    {
257        setCullingMode(osg::CullSettings::VIEW_FRUSTUM_CULLING);
258
259        pushViewport(viewport);
260        pushProjectionMatrix(new osg::RefMatrix(projectionMatrix));
261        pushModelViewMatrix(new osg::RefMatrix(viewMatrix),osg::Transform::ABSOLUTE_RF);
262    }
263
264    void apply(osg::Node& node)
265    {
266        if (isCulled(node)) return;
267
268        // push the culling mode.
269        pushCurrentMask();
270
271        traverse(node);
272
273        // pop the culling mode.
274        popCurrentMask();
275    }
276
277    void apply(osg::Geode& node)
278    {
279        if (isCulled(node)) return;
280
281        // push the culling mode.
282        pushCurrentMask();
283
284        for(unsigned int i=0; i<node.getNumDrawables();++i)
285        {
286            if (node.getDrawable(i))
287            {
288                updateBound(node.getDrawable(i)->getBound());
289            }
290        }
291
292        // pop the culling mode.
293        popCurrentMask();
294    }
295
296    void apply(osg::Billboard&)
297    {
298        OSG_INFO<<"Warning Billboards not yet supported"<<std::endl;
299        return;
300    }
301
302    void apply(osg::Projection&)
303    {
304        // projection nodes won't affect a shadow map so their subgraphs should be ignored
305        return;
306    }
307
308    void apply(osg::Transform& transform)
309    {
310        if (isCulled(transform)) return;
311
312        // push the culling mode.
313        pushCurrentMask();
314
315        // absolute transforms won't affect a shadow map so their subgraphs should be ignored.
316        if (transform.getReferenceFrame()==osg::Transform::RELATIVE_RF)
317        {
318            osg::ref_ptr<osg::RefMatrix> matrix = new osg::RefMatrix(*getModelViewMatrix());
319            transform.computeLocalToWorldMatrix(*matrix,this);
320            pushModelViewMatrix(matrix.get(), transform.getReferenceFrame());
321
322            traverse(transform);
323
324            popModelViewMatrix();
325        }
326
327        // pop the culling mode.
328        popCurrentMask();
329
330    }
331
332    void apply(osg::Camera&)
333    {
334        // camera nodes won't affect a shadow map so their subgraphs should be ignored
335        return;
336    }
337
338    void updateBound(const osg::BoundingBox& bb)
339    {
340        if (!bb.valid()) return;
341
342        const osg::Matrix& matrix = *getModelViewMatrix() * *getProjectionMatrix();
343
344        update(bb.corner(0) * matrix);
345        update(bb.corner(1) * matrix);
346        update(bb.corner(2) * matrix);
347        update(bb.corner(3) * matrix);
348        update(bb.corner(4) * matrix);
349        update(bb.corner(5) * matrix);
350        update(bb.corner(6) * matrix);
351        update(bb.corner(7) * matrix);
352    }
353
354    void update(const osg::Vec3& v)
355    {
356        if (v.z()<-1.0f)
357        {
358            //OSG_NOTICE<<"discarding("<<v<<")"<<std::endl;
359            return;
360        }
361        float x = v.x();
362        if (x<-1.0f) x=-1.0f;
363        if (x>1.0f) x=1.0f;
364        float y = v.y();
365        if (y<-1.0f) y=-1.0f;
366        if (y>1.0f) y=1.0f;
367        _bb.expandBy(osg::Vec3(x,y,v.z()));
368    }
369
370    osg::BoundingBox _bb;
371};
372
373///////////////////////////////////////////////////////////////////////////////////////////////
374//
375// LightData
376//
377ViewDependentShadowMap::LightData::LightData(ViewDependentShadowMap::ViewDependentData* vdd):
378    _viewDependentData(vdd),
379    directionalLight(false)
380{
381}
382
383void ViewDependentShadowMap::LightData::setLightData(osg::RefMatrix* lm, const osg::Light* l, const osg::Matrixd& modelViewMatrix)
384{
385    lightMatrix = lm;
386    light = l;
387
388    lightPos = light->getPosition();
389    directionalLight = (light->getPosition().w()== 0.0);
390    if (directionalLight)
391    {
392        lightPos3.set(0.0, 0.0, 0.0); // directional light has no destinct position
393        lightDir.set(-lightPos.x(), -lightPos.y(), -lightPos.z());
394        lightDir.normalize();
395        OSG_INFO<<"   Directional light, lightPos="<<lightPos<<", lightDir="<<lightDir<<std::endl;
396        if (lightMatrix.valid())
397        {
398            OSG_INFO<<"   Light matrix "<<*lightMatrix<<std::endl;
399            osg::Matrix lightToLocalMatrix(*lightMatrix * osg::Matrix::inverse(modelViewMatrix) );
400            lightDir = osg::Matrix::transform3x3( lightDir, lightToLocalMatrix );
401            lightDir.normalize();
402            OSG_INFO<<"   new LightDir ="<<lightDir<<std::endl;
403        }
404    }
405    else
406    {
407        OSG_INFO<<"   Positional light, lightPos="<<lightPos<<std::endl;
408        lightDir = light->getDirection();
409        lightDir.normalize();
410        if (lightMatrix.valid())
411        {
412            OSG_INFO<<"   Light matrix "<<*lightMatrix<<std::endl;
413            osg::Matrix lightToLocalMatrix(*lightMatrix * osg::Matrix::inverse(modelViewMatrix) );
414            lightPos = lightPos * lightToLocalMatrix;
415            lightDir = osg::Matrix::transform3x3( lightDir, lightToLocalMatrix );
416            lightDir.normalize();
417            OSG_INFO<<"   new LightPos ="<<lightPos<<std::endl;
418            OSG_INFO<<"   new LightDir ="<<lightDir<<std::endl;
419        }
420        lightPos3.set(lightPos.x()/lightPos.w(), lightPos.y()/lightPos.w(), lightPos.z()/lightPos.w());
421    }
422}
423
424///////////////////////////////////////////////////////////////////////////////////////////////
425//
426// ShadowData
427//
428ViewDependentShadowMap::ShadowData::ShadowData(ViewDependentShadowMap::ViewDependentData* vdd):
429    _viewDependentData(vdd),
430    _textureUnit(0)
431{
432
433    const ShadowSettings* settings = vdd->getViewDependentShadowMap()->getShadowedScene()->getShadowSettings();
434
435    bool debug = settings->getDebugDraw();
436
437    // set up texgen
438    _texgen = new osg::TexGen;
439
440    // set up the texture
441    _texture = new osg::Texture2D;
442
443    osg::Vec2s textureSize = debug ? osg::Vec2s(512,512) : settings->getTextureSize();
444    _texture->setTextureSize(textureSize.x(), textureSize.y());
445
446    if (debug)
447    {
448        _texture->setInternalFormat(GL_RGB);
449    }
450    else
451    {
452        _texture->setInternalFormat(GL_DEPTH_COMPONENT);
453        _texture->setShadowComparison(true);
454        _texture->setShadowTextureMode(osg::Texture2D::LUMINANCE);
455    }
456
457    _texture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::LINEAR);
458    _texture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::LINEAR);
459
460    // the shadow comparison should fail if object is outside the texture
461    _texture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::CLAMP_TO_BORDER);
462    _texture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::CLAMP_TO_BORDER);
463    _texture->setBorderColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
464    //_texture->setBorderColor(osg::Vec4(0.0f,0.0f,0.0f,0.0f));
465
466    // set up the camera
467    _camera = new osg::Camera;
468    _camera->setName("ShadowCamera");
469    _camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF_INHERIT_VIEWPOINT);
470
471    //_camera->setClearColor(osg::Vec4(1.0f,1.0f,1.0f,1.0f));
472    _camera->setClearColor(osg::Vec4(0.0f,0.0f,0.0f,0.0f));
473
474    _camera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_BOUNDING_VOLUMES);
475    //_camera->setComputeNearFarMode(osg::Camera::COMPUTE_NEAR_FAR_USING_PRIMITIVES);
476
477    // switch off small feature culling as this can cull out geometry that will still be large enough once perspective correction takes effect.
478    _camera->setCullingMode(_camera->getCullingMode() & ~osg::CullSettings::SMALL_FEATURE_CULLING);
479
480    // set viewport
481    _camera->setViewport(0,0,textureSize.x(),textureSize.y());
482
483
484    if (debug)
485    {
486        // clear just the depth buffer
487        _camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
488
489        // render after the main camera
490        _camera->setRenderOrder(osg::Camera::POST_RENDER);
491
492        // attach the texture and use it as the color buffer.
493        //_camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get());
494        _camera->attach(osg::Camera::COLOR_BUFFER, _texture.get());
495    }
496    else
497    {
498        // clear the depth and colour bufferson each clear.
499        _camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
500
501        // set the camera to render before the main camera.
502        _camera->setRenderOrder(osg::Camera::PRE_RENDER);
503
504        // tell the camera to use OpenGL frame buffer object where supported.
505        _camera->setRenderTargetImplementation(osg::Camera::FRAME_BUFFER_OBJECT);
506
507        // attach the texture and use it as the color buffer.
508        _camera->attach(osg::Camera::DEPTH_BUFFER, _texture.get());
509        //_camera->attach(osg::Camera::COLOR_BUFFER, _texture.get());
510    }
511}
512
513void ViewDependentShadowMap::ShadowData::releaseGLObjects(osg::State* state) const
514{
515    OSG_INFO<<"ViewDependentShadowMap::ShadowData::releaseGLObjects"<<std::endl;
516    _texture->releaseGLObjects(state);
517    _camera->releaseGLObjects(state);
518}
519
520///////////////////////////////////////////////////////////////////////////////////////////////
521//
522// Frustum
523//
524ViewDependentShadowMap::Frustum::Frustum(osgUtil::CullVisitor* cv, double minZNear, double maxZFar):
525    corners(8),
526    faces(6),
527    edges(12)
528{
529    projectionMatrix = *(cv->getProjectionMatrix());
530    modelViewMatrix = *(cv->getModelViewMatrix());
531
532    OSG_INFO<<"Projection matrix "<<projectionMatrix<<std::endl;
533
534    if (cv->getComputeNearFarMode()!=osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR)
535    {
536        osg::Matrix::value_type zNear = osg::maximum<osg::Matrix::value_type>(cv->getCalculatedNearPlane(),minZNear);
537        osg::Matrix::value_type zFar = osg::minimum<osg::Matrix::value_type>(cv->getCalculatedFarPlane(),maxZFar);
538
539        cv->clampProjectionMatrix(projectionMatrix, zNear, zFar);
540
541        OSG_INFO<<"zNear = "<<zNear<<", zFar = "<<zFar<<std::endl;
542        OSG_INFO<<"Projection matrix after clamping "<<projectionMatrix<<std::endl;
543    }
544
545    corners[0].set(-1.0,-1.0,-1.0);
546    corners[1].set(1.0,-1.0,-1.0);
547    corners[2].set(1.0,-1.0,1.0);
548    corners[3].set(-1.0,-1.0,1.0);
549    corners[4].set(-1.0,1.0,-1.0);
550    corners[5].set(1.0,1.0,-1.0);
551    corners[6].set(1.0,1.0,1.0);
552    corners[7].set(-1.0,1.0,1.0);
553
554    osg::Matrixd clipToWorld;
555    clipToWorld.invert(modelViewMatrix * projectionMatrix);
556
557    // transform frustum corners from clipspace to world coords, and compute center
558    for(Vertices::iterator itr = corners.begin();
559        itr != corners.end();
560        ++itr)
561    {
562        *itr = (*itr) * clipToWorld;
563
564        OSG_INFO<<"   corner "<<*itr<<std::endl;
565    }
566
567    // compute eye point
568    eye = osg::Vec3d(0.0,0.0,0.0) * osg::Matrix::inverse(modelViewMatrix);
569
570    // compute center and the frustumCenterLine
571    centerNearPlane = (corners[0]+corners[1]+corners[5]+corners[4])*0.25;
572    centerFarPlane = (corners[3]+corners[2]+corners[6]+corners[7])*0.25;
573    center = (centerNearPlane+centerFarPlane)*0.5;
574    frustumCenterLine = centerFarPlane-centerNearPlane;
575    frustumCenterLine.normalize();
576
577    OSG_INFO<<"   center "<<center<<std::endl;
578
579    faces[0].push_back(0);
580    faces[0].push_back(3);
581    faces[0].push_back(7);
582    faces[0].push_back(4);
583
584    faces[1].push_back(1);
585    faces[1].push_back(5);
586    faces[1].push_back(6);
587    faces[1].push_back(2);
588
589    faces[2].push_back(0);
590    faces[2].push_back(1);
591    faces[2].push_back(2);
592    faces[2].push_back(3);
593
594    faces[3].push_back(4);
595    faces[3].push_back(7);
596    faces[3].push_back(6);
597    faces[3].push_back(5);
598
599    faces[4].push_back(0);
600    faces[4].push_back(4);
601    faces[4].push_back(5);
602    faces[4].push_back(1);
603
604    faces[5].push_back(2);
605    faces[5].push_back(6);
606    faces[5].push_back(7);
607    faces[5].push_back(3);
608
609    edges[0].push_back(0); edges[0].push_back(1); // corner points on edge
610    edges[0].push_back(2); edges[0].push_back(4); // faces on edge
611
612    edges[1].push_back(1); edges[1].push_back(2); // corner points on edge
613    edges[1].push_back(2); edges[1].push_back(1); // faces on edge
614
615    edges[2].push_back(2); edges[2].push_back(3); // corner points on edge
616    edges[2].push_back(2); edges[2].push_back(5); // faces on edge
617
618    edges[3].push_back(3); edges[3].push_back(0); // corner points on edge
619    edges[3].push_back(2); edges[3].push_back(0); // faces on edge
620
621
622    edges[4].push_back(0); edges[4].push_back(4); // corner points on edge
623    edges[4].push_back(0); edges[4].push_back(4); // faces on edge
624
625    edges[5].push_back(1); edges[5].push_back(5); // corner points on edge
626    edges[5].push_back(4); edges[5].push_back(1); // faces on edge
627
628    edges[6].push_back(2); edges[6].push_back(6); // corner points on edge
629    edges[6].push_back(1); edges[6].push_back(5); // faces on edge
630
631    edges[7].push_back(3); edges[7].push_back(7); // corner points on edge
632    edges[7].push_back(5); edges[7].push_back(0); // faces on edge
633
634
635    edges[8].push_back(4); edges[8].push_back(5); // corner points on edge
636    edges[8].push_back(3); edges[8].push_back(4); // faces on edge
637
638    edges[9].push_back(5); edges[9].push_back(6); // corner points on edge
639    edges[9].push_back(3); edges[9].push_back(1); // faces on edge
640
641    edges[10].push_back(6);edges[10].push_back(7); // corner points on edge
642    edges[10].push_back(3);edges[10].push_back(5); // faces on edge
643
644    edges[11].push_back(7); edges[11].push_back(4); // corner points on edge
645    edges[11].push_back(3); edges[11].push_back(0); // faces on edge
646}
647
648
649///////////////////////////////////////////////////////////////////////////////////////////////
650//
651// ViewDependentData
652//
653ViewDependentShadowMap::ViewDependentData::ViewDependentData(ViewDependentShadowMap* vdsm):
654    _viewDependentShadowMap(vdsm)
655{
656    OSG_INFO<<"ViewDependentData::ViewDependentData()"<<this<<std::endl;
657    _stateset = new osg::StateSet;
658}
659
660void ViewDependentShadowMap::ViewDependentData::releaseGLObjects(osg::State* state) const
661{
662    for(ShadowDataList::const_iterator itr = _shadowDataList.begin();
663        itr != _shadowDataList.end();
664        ++itr)
665    {
666        (*itr)->releaseGLObjects(state);
667    }
668}
669
670///////////////////////////////////////////////////////////////////////////////////////////////
671//
672// ViewDependentShadowMap
673//
674ViewDependentShadowMap::ViewDependentShadowMap():
675    ShadowTechnique()
676{
677    _shadowRecievingPlaceholderStateSet = new osg::StateSet;
678}
679
680ViewDependentShadowMap::ViewDependentShadowMap(const ViewDependentShadowMap& vdsm, const osg::CopyOp& copyop):
681    ShadowTechnique(vdsm,copyop)
682{
683    _shadowRecievingPlaceholderStateSet = new osg::StateSet;
684}
685
686ViewDependentShadowMap::~ViewDependentShadowMap()
687{
688}
689
690
691void ViewDependentShadowMap::init()
692{
693    if (!_shadowedScene) return;
694
695    OSG_INFO<<"ViewDependentShadowMap::init()"<<std::endl;
696
697    createShaders();
698
699    _dirty = false;
700}
701
702void ViewDependentShadowMap::cleanSceneGraph()
703{
704    OSG_INFO<<"ViewDependentShadowMap::cleanSceneGraph()"<<std::endl;
705}
706
707ViewDependentShadowMap::ViewDependentData* ViewDependentShadowMap::createViewDependentData(osgUtil::CullVisitor* /*cv*/)
708{
709    return new ViewDependentData(this);
710}
711
712ViewDependentShadowMap::ViewDependentData* ViewDependentShadowMap::getViewDependentData(osgUtil::CullVisitor* cv)
713{
714    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_viewDependentDataMapMutex);
715    ViewDependentDataMap::iterator itr = _viewDependentDataMap.find(cv);
716    if (itr!=_viewDependentDataMap.end()) return itr->second.get();
717
718    osg::ref_ptr<ViewDependentData> vdd = createViewDependentData(cv);
719    _viewDependentDataMap[cv] = vdd;
720    return vdd.release();
721}
722
723void ViewDependentShadowMap::update(osg::NodeVisitor& nv)
724{
725    OSG_INFO<<"ViewDependentShadowMap::update(osg::NodeVisitor& "<<&nv<<")"<<std::endl;
726    _shadowedScene->osg::Group::traverse(nv);
727}
728
729void ViewDependentShadowMap::cull(osgUtil::CullVisitor& cv)
730{
731    OSG_INFO<<std::endl<<std::endl<<"ViewDependentShadowMap::cull(osg::CullVisitor&"<<&cv<<")"<<std::endl;
732
733    if (!_shadowCastingStateSet)
734    {
735        OSG_INFO<<"Warning, init() has not yet been called so ShadowCastingStateSet has not been setup yet, unable to create shadows."<<std::endl;
736        _shadowedScene->osg::Group::traverse(cv);
737        return;
738    }
739
740    ViewDependentData* vdd = getViewDependentData(&cv);
741
742    if (!vdd)
743    {
744        OSG_INFO<<"Warning, now ViewDependentData created, unable to create shadows."<<std::endl;
745        _shadowedScene->osg::Group::traverse(cv);
746        return;
747    }
748
749    ShadowSettings* settings = getShadowedScene()->getShadowSettings();
750
751    OSG_INFO<<"cv->getProjectionMatrix()="<<*cv.getProjectionMatrix()<<std::endl;
752
753    osg::CullSettings::ComputeNearFarMode cachedNearFarMode = cv.getComputeNearFarMode();
754
755    osg::RefMatrix& viewProjectionMatrix = *cv.getProjectionMatrix();
756
757    // check whether this main views projection is perspective or orthographic
758    bool orthographicViewFrustum = viewProjectionMatrix(0,3)==0.0 &&
759                                   viewProjectionMatrix(1,3)==0.0 &&
760                                   viewProjectionMatrix(2,3)==0.0;
761
762    double minZNear = 0.0;
763    double maxZFar = DBL_MAX;
764
765    if (cachedNearFarMode==osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR)
766    {
767        double left, right, top, bottom;
768        if (orthographicViewFrustum)
769        {
770            viewProjectionMatrix.getOrtho(left, right, bottom, top, minZNear, maxZFar);
771        }
772        else
773        {
774            viewProjectionMatrix.getFrustum(left, right, bottom, top, minZNear, maxZFar);
775        }
776        OSG_INFO<<"minZNear="<<minZNear<<", maxZFar="<<maxZFar<<std::endl;
777    }
778
779    // set the compute near/far mode to the highest quality setting to ensure we push the near plan out as far as possible
780    if (settings->getComputeNearFarModeOverride()!=osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR)
781    {
782        cv.setComputeNearFarMode(settings->getComputeNearFarModeOverride());
783    }
784
785    // 1. Traverse main scene graph
786    cv.pushStateSet( _shadowRecievingPlaceholderStateSet.get() );
787
788    osg::ref_ptr<osgUtil::StateGraph> decoratorStateGraph = cv.getCurrentStateGraph();
789
790    cullShadowReceivingScene(&cv);
791
792    cv.popStateSet();
793
794    if (cv.getComputeNearFarMode()!=osg::CullSettings::DO_NOT_COMPUTE_NEAR_FAR)
795    {
796        OSG_INFO<<"Just done main subgraph traversak"<<std::endl;
797        // make sure that the near plane is computed correctly so that any projection matrix computations
798        // are all done correctly.
799        cv.computeNearPlane();
800    }
801
802    // clamp the minZNear and maxZFar to those provided by ShadowSettings
803    maxZFar = osg::minimum(settings->getMaximumShadowMapDistance(),maxZFar);
804    if (minZNear>maxZFar) minZNear = maxZFar*settings->getMinimumShadowMapNearFarRatio();
805
806    //OSG_NOTICE<<"maxZFar "<<maxZFar<<std::endl;
807
808    Frustum frustum(&cv, minZNear, maxZFar);
809
810    // return compute near far mode back to it's original settings
811    cv.setComputeNearFarMode(cachedNearFarMode);
812
813    OSG_INFO<<"frustum.eye="<<frustum.eye<<", frustum.centerNearPlane, "<<frustum.centerNearPlane<<" distance = "<<(frustum.eye-frustum.centerNearPlane).length()<<std::endl;
814
815
816    // 2. select active light sources
817    //    create a list of light sources + their matrices to place them
818    selectActiveLights(&cv, vdd);
819
820
821    unsigned int pos_x = 0;
822    unsigned int textureUnit = settings->getBaseShadowTextureUnit();
823    unsigned int numValidShadows = 0;
824
825    ShadowDataList& sdl = vdd->getShadowDataList();
826    ShadowDataList previous_sdl;
827    previous_sdl.swap(sdl);
828
829    unsigned int numShadowMapsPerLight = settings->getNumShadowMapsPerLight();
830    if (numShadowMapsPerLight>2)
831    {
832        OSG_NOTICE<<"numShadowMapsPerLight of "<<numShadowMapsPerLight<<" is greater than maximum supported, falling back to 2."<<std::endl;
833        numShadowMapsPerLight = 2;
834    }
835
836    LightDataList& pll = vdd->getLightDataList();
837    for(LightDataList::iterator itr = pll.begin();
838        itr != pll.end();
839        ++itr)
840    {
841        // 3. create per light/per shadow map division of lightspace/frustum
842        //    create a list of light/shadow map data structures
843
844        LightData& pl = **itr;
845
846        // 3.1 compute light space polytope
847        //
848        osg::Polytope polytope = computeLightViewFrustumPolytope(frustum, pl);
849
850        // if polytope is empty then no rendering.
851        if (polytope.empty())
852        {
853            OSG_NOTICE<<"Polytope empty no shadow to render"<<std::endl;
854            continue;
855        }
856
857        // 3.2 compute RTT camera view+projection matrix settings
858        //
859        osg::Matrixd projectionMatrix;
860        osg::Matrixd viewMatrix;
861        if (!computeShadowCameraSettings(frustum, pl, projectionMatrix, viewMatrix))
862        {
863            OSG_NOTICE<<"No valid Camera settings, no shadow to render"<<std::endl;
864            continue;
865        }
866
867        // if we are using multiple shadow maps and CastShadowTraversalMask is being used
868        // traverse the scene to compute the extents of the objects
869        if (/*numShadowMapsPerLight>1 &&*/ _shadowedScene->getCastsShadowTraversalMask()!=0xffffffff)
870        {
871            // osg::ElapsedTime timer;
872
873            osg::ref_ptr<osg::Viewport> viewport = new osg::Viewport(0,0,2048,2048);
874            ComputeLightSpaceBounds clsb(viewport.get(), projectionMatrix, viewMatrix);
875            clsb.setTraversalMask(_shadowedScene->getCastsShadowTraversalMask());
876
877            osg::Matrixd invertModelView;
878            invertModelView.invert(viewMatrix);
879            osg::Polytope local_polytope(polytope);
880            local_polytope.transformProvidingInverse(invertModelView);
881
882            osg::CullingSet& cs = clsb.getProjectionCullingStack().back();
883            cs.setFrustum(local_polytope);
884            clsb.pushCullingSet();
885
886            _shadowedScene->accept(clsb);
887
888            // OSG_NOTICE<<"Extents of LightSpace "<<clsb._bb.xMin()<<", "<<clsb._bb.xMax()<<", "<<clsb._bb.yMin()<<", "<<clsb._bb.yMax()<<", "<<clsb._bb.zMin()<<", "<<clsb._bb.zMax()<<std::endl;
889            // OSG_NOTICE<<"  time "<<timer.elapsedTime_m()<<"ms, mask = "<<std::hex<<_shadowedScene->getCastsShadowTraversalMask()<<std::endl;
890
891            if (clsb._bb.xMin()>-1.0f || clsb._bb.xMax()<1.0f || clsb._bb.yMin()>-1.0f || clsb._bb.yMax()<1.0f)
892            {
893                // OSG_NOTICE<<"Need to clamp projection matrix"<<std::endl;
894
895#if 1
896                double xMid = (clsb._bb.xMin()+clsb._bb.xMax())*0.5f;
897                double xRange = clsb._bb.xMax()-clsb._bb.xMin();
898#else
899                double xMid = 0.0;
900                double xRange = 2.0;
901#endif
902                double yMid = (clsb._bb.yMin()+clsb._bb.yMax())*0.5f;
903                double yRange = (clsb._bb.yMax()-clsb._bb.yMin());
904
905                // OSG_NOTICE<<"  xMid="<<xMid<<", yMid="<<yMid<<", xRange="<<xRange<<", yRange="<<yRange<<std::endl;
906
907                projectionMatrix =
908                    projectionMatrix *
909                    osg::Matrixd::translate(osg::Vec3d(-xMid,-yMid,0.0)) *
910                    osg::Matrixd::scale(osg::Vec3d(2.0/xRange, 2.0/yRange,1.0));
911
912            }
913
914        }
915
916        double splitPoint = 0.0;
917
918        if (numShadowMapsPerLight>1)
919        {
920            osg::Vec3d eye_v = frustum.eye * viewMatrix;
921            osg::Vec3d center_v = frustum.center * viewMatrix;
922            osg::Vec3d viewdir_v = center_v-eye_v; viewdir_v.normalize();
923            osg::Vec3d lightdir(0.0,0.0,-1.0);
924
925            double dotProduct_v = lightdir * viewdir_v;
926            double angle = acosf(dotProduct_v);
927
928            osg::Vec3d eye_ls = eye_v * projectionMatrix;
929
930            OSG_INFO<<"Angle between view vector and eye "<<osg::RadiansToDegrees(angle)<<std::endl;
931            OSG_INFO<<"eye_ls="<<eye_ls<<std::endl;
932
933            if (eye_ls.y()>=-1.0 && eye_ls.y()<=1.0)
934            {
935                OSG_INFO<<"Eye point inside light space clip region   "<<std::endl;
936                splitPoint = 0.0;
937            }
938            else
939            {
940                double n = -1.0-eye_ls.y();
941                double f = 1.0-eye_ls.y();
942                double sqrt_nf = sqrt(n*f);
943                double mid = eye_ls.y()+sqrt_nf;
944                double ratioOfMidToUseForSplit = 0.8;
945                splitPoint = mid * ratioOfMidToUseForSplit;
946
947                OSG_INFO<<"  n="<<n<<", f="<<f<<", sqrt_nf="<<sqrt_nf<<" mid="<<mid<<std::endl;
948            }
949        }
950
951        // 4. For each light/shadow map
952        for (unsigned int sm_i=0; sm_i<numShadowMapsPerLight; ++sm_i)
953        {
954            osg::ref_ptr<ShadowData> sd;
955
956            if (previous_sdl.empty())
957            {
958                OSG_INFO<<"Create new ShadowData"<<std::endl;
959                sd = new ShadowData(vdd);
960            }
961            else
962            {
963                OSG_INFO<<"Taking ShadowData from from of previous_sdl"<<std::endl;
964                sd = previous_sdl.front();
965                previous_sdl.erase(previous_sdl.begin());
966            }
967
968            osg::ref_ptr<osg::Camera> camera = sd->_camera;
969
970            camera->setProjectionMatrix(projectionMatrix);
971            camera->setViewMatrix(viewMatrix);
972
973            if (settings->getDebugDraw())
974            {
975                camera->getViewport()->x() = pos_x;
976                pos_x += static_cast<unsigned int>(camera->getViewport()->width()) + 40;
977            }
978
979            // transform polytope in model coords into light spaces eye coords.
980            osg::Matrixd invertModelView;
981            invertModelView.invert(camera->getViewMatrix());
982
983            osg::Polytope local_polytope(polytope);
984            local_polytope.transformProvidingInverse(invertModelView);
985
986
987            if (numShadowMapsPerLight>1)
988            {
989                // compute the start and end range in non-dimensional coords
990#if 0
991                double r_start = (sm_i==0) ? -1.0 : (double(sm_i)/double(numShadowMapsPerLight)*2.0-1.0);
992                double r_end = (sm_i+1==numShadowMapsPerLight) ? 1.0 : (double(sm_i+1)/double(numShadowMapsPerLight)*2.0-1.0);
993#endif
994
995                // hardwired for 2 splits
996                double r_start = (sm_i==0) ? -1.0 : splitPoint;
997                double r_end = (sm_i+1==numShadowMapsPerLight) ? 1.0 : splitPoint;
998
999                // for all by the last shadowmap shift the r_end so that it overlaps slightly with the next shadowmap
1000                // to prevent a seam showing through between the shadowmaps
1001                if (sm_i+1<numShadowMapsPerLight) r_end+=0.01;
1002
1003
1004                if (sm_i>0)
1005                {
1006                    // not the first shadowmap so insert a polytope to clip the scene from before r_start
1007
1008                    // plane in clip space coords
1009                    osg::Plane plane(0.0,1.0,0.0,-r_start);
1010
1011                    // transform into eye coords
1012                    plane.transformProvidingInverse(projectionMatrix);
1013                    local_polytope.getPlaneList().push_back(plane);
1014
1015                    //OSG_NOTICE<<"Adding r_start plane "<<plane<<std::endl;
1016
1017                }
1018
1019                if (sm_i+1<numShadowMapsPerLight)
1020                {
1021                    // not the last shadowmap so insert a polytope to clip the scene from beyond r_end
1022
1023                    // plane in clip space coords
1024                    osg::Plane plane(0.0,-1.0,0.0,r_end);
1025
1026                    // transform into eye coords
1027                    plane.transformProvidingInverse(projectionMatrix);
1028                    local_polytope.getPlaneList().push_back(plane);
1029
1030                    //OSG_NOTICE<<"Adding r_end plane "<<plane<<std::endl;
1031                }
1032
1033                local_polytope.setupMask();
1034
1035
1036                // OSG_NOTICE<<"Need to adjust RTT camera projection and view matrix here, r_start="<<r_start<<", r_end="<<r_end<<std::endl;
1037                // OSG_NOTICE<<"  textureUnit = "<<textureUnit<<std::endl;
1038
1039                double mid_r = (r_start+r_end)*0.5;
1040                double range_r = (r_end-r_start);
1041
1042                // OSG_NOTICE<<"  mid_r = "<<mid_r<<", range_r = "<<range_r<<std::endl;
1043
1044                camera->setProjectionMatrix(
1045                    camera->getProjectionMatrix() *
1046                    osg::Matrixd::translate(osg::Vec3d(0.0,-mid_r,0.0)) *
1047                    osg::Matrixd::scale(osg::Vec3d(1.0,2.0/range_r,1.0)));
1048
1049            }
1050
1051
1052            osg::ref_ptr<VDSMCameraCullCallback> vdsmCallback = new VDSMCameraCullCallback(this, local_polytope);
1053            camera->setCullCallback(vdsmCallback.get());
1054
1055            // 4.3 traverse RTT camera
1056            //
1057
1058            cv.pushStateSet(_shadowCastingStateSet.get());
1059
1060            cullShadowCastingScene(&cv, camera.get());
1061
1062            cv.popStateSet();
1063
1064            if (!orthographicViewFrustum && settings->getShadowMapProjectionHint()==ShadowSettings::PERSPECTIVE_SHADOW_MAP)
1065            {
1066                adjustPerspectiveShadowMapCameraSettings(vdsmCallback->getRenderStage(), frustum, pl, camera.get());
1067                if (vdsmCallback->getProjectionMatrix())
1068                {
1069                    vdsmCallback->getProjectionMatrix()->set(camera->getProjectionMatrix());
1070                }
1071            }
1072
1073            // 4.4 compute main scene graph TexGen + uniform settings + setup state
1074            //
1075            assignTexGenSettings(&cv, camera.get(), textureUnit, sd->_texgen.get());
1076
1077            // mark the light as one that has active shadows and requires shaders
1078            pl.textureUnits.push_back(textureUnit);
1079
1080            // pass on shadow data to ShadowDataList
1081            sd->_textureUnit = textureUnit;
1082
1083            if (textureUnit >= 8)
1084            {
1085                OSG_NOTICE<<"Shadow texture unit is invalid for texgen, will not be used."<<std::endl;
1086            }
1087            else
1088            {
1089                sdl.push_back(sd);
1090            }
1091
1092            // increment counters.
1093            ++textureUnit;
1094            ++numValidShadows ;
1095        }
1096    }
1097
1098    if (numValidShadows>0)
1099    {
1100        decoratorStateGraph->setStateSet(selectStateSetForRenderingShadow(*vdd));
1101    }
1102
1103    // OSG_NOTICE<<"End of shadow setup Projection matrix "<<*cv.getProjectionMatrix()<<std::endl;
1104}
1105
1106bool ViewDependentShadowMap::selectActiveLights(osgUtil::CullVisitor* cv, ViewDependentData* vdd) const
1107{
1108    OSG_INFO<<"selectActiveLights"<<std::endl;
1109
1110    LightDataList& pll = vdd->getLightDataList();
1111
1112    LightDataList previous_ldl;
1113    previous_ldl.swap(pll);
1114
1115    //MR testing giving a specific light
1116    osgUtil::RenderStage * rs = cv->getCurrentRenderBin()->getStage();
1117
1118    OSG_INFO<<"selectActiveLights osgUtil::RenderStage="<<rs<<std::endl;
1119
1120    osg::Matrixd modelViewMatrix = *(cv->getModelViewMatrix());
1121
1122    osgUtil::PositionalStateContainer::AttrMatrixList& aml =
1123        rs->getPositionalStateContainer()->getAttrMatrixList();
1124
1125
1126    const ShadowSettings* settings = getShadowedScene()->getShadowSettings();
1127
1128    for(osgUtil::PositionalStateContainer::AttrMatrixList::reverse_iterator itr = aml.rbegin();
1129        itr != aml.rend();
1130        ++itr)
1131    {
1132        const osg::Light* light = dynamic_cast<const osg::Light*>(itr->first.get());
1133        if (light && light->getLightNum() >= 0)
1134        {
1135            // is LightNum matched to that defined in settings
1136            if (settings && settings->getLightNum()>=0 && light->getLightNum()!=settings->getLightNum()) continue;
1137
1138            LightDataList::iterator pll_itr = pll.begin();
1139            for(; pll_itr != pll.end(); ++pll_itr)
1140            {
1141                if ((*pll_itr)->light->getLightNum()==light->getLightNum()) break;
1142            }
1143
1144            if (pll_itr==pll.end())
1145            {
1146                OSG_INFO<<"Light num "<<light->getLightNum()<<std::endl;
1147                LightData* ld = new LightData(vdd);
1148                ld->setLightData(itr->second.get(), light, modelViewMatrix);
1149                pll.push_back(ld);
1150            }
1151            else
1152            {
1153                OSG_INFO<<"Light num "<<light->getLightNum()<<" already used, ignore light"<<std::endl;
1154            }
1155        }
1156    }
1157
1158    return !pll.empty();
1159}
1160
1161void ViewDependentShadowMap::createShaders()
1162{
1163    OSG_INFO<<"ViewDependentShadowMap::createShaders()"<<std::endl;
1164
1165    unsigned int _baseTextureUnit = 0;
1166
1167    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_accessUnfiromsAndProgramMutex);
1168
1169    _shadowCastingStateSet = new osg::StateSet;
1170
1171    ShadowSettings* settings = getShadowedScene()->getShadowSettings();
1172
1173    if (!settings->getDebugDraw())
1174    {
1175        // note soft (attribute only no mode override) setting. When this works ?
1176        // 1. for objects prepared for backface culling
1177        //    because they usually also set CullFace and CullMode on in their state
1178        //    For them we override CullFace but CullMode remains set by them
1179        // 2. For one faced, trees, and similar objects which cannot use
1180        //    backface nor front face so they usually use CullMode off set here.
1181        //    In this case we will draw them in their entirety.
1182
1183        _shadowCastingStateSet->setAttribute( new osg::CullFace( osg::CullFace::FRONT ),
1184                osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE );
1185
1186        // make sure GL_CULL_FACE is off by default
1187        // we assume that if object has cull face attribute set to back
1188        // it will also set cull face mode ON so no need for override
1189        _shadowCastingStateSet->setMode( GL_CULL_FACE, osg::StateAttribute::OFF );
1190    }
1191
1192#if 1
1193    float factor = 1.1;
1194    float units =  4.0;
1195#else
1196    float factor = -1.1;
1197    float units =  -4.0;
1198#endif
1199    _polygonOffset = new osg::PolygonOffset(factor, units);
1200    _shadowCastingStateSet->setAttribute(_polygonOffset.get(), osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
1201    _shadowCastingStateSet->setMode(GL_POLYGON_OFFSET_FILL, osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE);
1202
1203
1204    _uniforms.clear();
1205    osg::ref_ptr<osg::Uniform> baseTextureSampler = new osg::Uniform("baseTexture",(int)_baseTextureUnit);
1206    _uniforms.push_back(baseTextureSampler.get());
1207
1208    osg::ref_ptr<osg::Uniform> baseTextureUnit = new osg::Uniform("baseTextureUnit",(int)_baseTextureUnit);
1209    _uniforms.push_back(baseTextureUnit.get());
1210
1211    for(unsigned int sm_i=0; sm_i<settings->getNumShadowMapsPerLight(); ++sm_i)
1212    {
1213        {
1214            std::stringstream sstr;
1215            sstr<<"shadowTexture"<<sm_i;
1216            osg::ref_ptr<osg::Uniform> shadowTextureSampler = new osg::Uniform(sstr.str().c_str(),(int)(settings->getBaseShadowTextureUnit()+sm_i));
1217            _uniforms.push_back(shadowTextureSampler.get());
1218        }
1219
1220        {
1221            std::stringstream sstr;
1222            sstr<<"shadowTextureUnit"<<sm_i;
1223            osg::ref_ptr<osg::Uniform> shadowTextureUnit = new osg::Uniform(sstr.str().c_str(),(int)(settings->getBaseShadowTextureUnit()+sm_i));
1224            _uniforms.push_back(shadowTextureUnit.get());
1225        }
1226    }
1227
1228    switch(settings->getShaderHint())
1229    {
1230        case(ShadowSettings::NO_SHADERS):
1231        {
1232            OSG_INFO<<"No shaders provided by, user must supply own shaders"<<std::endl;
1233            break;
1234        }
1235        case(ShadowSettings::PROVIDE_VERTEX_AND_FRAGMENT_SHADER):
1236        case(ShadowSettings::PROVIDE_FRAGMENT_SHADER):
1237        {
1238            _program = new osg::Program;
1239
1240            //osg::ref_ptr<osg::Shader> fragment_shader = new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_noBaseTexture);
1241            if (settings->getNumShadowMapsPerLight()==2)
1242            {
1243                _program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_withBaseTexture_twoShadowMaps));
1244            }
1245            else
1246            {
1247                _program->addShader(new osg::Shader(osg::Shader::FRAGMENT, fragmentShaderSource_withBaseTexture));
1248            }
1249
1250            break;
1251        }
1252    }
1253
1254    {
1255        osg::ref_ptr<osg::Image> image = new osg::Image;
1256        image->allocateImage( 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE );
1257        *(osg::Vec4ub*)image->data() = osg::Vec4ub( 0xFF, 0xFF, 0xFF, 0xFF );
1258
1259        _fallbackBaseTexture = new osg::Texture2D(image.get());
1260        _fallbackBaseTexture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::REPEAT);
1261        _fallbackBaseTexture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::REPEAT);
1262        _fallbackBaseTexture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEAREST);
1263        _fallbackBaseTexture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST);
1264
1265        _fallbackShadowMapTexture = new osg::Texture2D(image.get());
1266        _fallbackShadowMapTexture->setWrap(osg::Texture2D::WRAP_S,osg::Texture2D::REPEAT);
1267        _fallbackShadowMapTexture->setWrap(osg::Texture2D::WRAP_T,osg::Texture2D::REPEAT);
1268        _fallbackShadowMapTexture->setFilter(osg::Texture2D::MIN_FILTER,osg::Texture2D::NEAREST);
1269        _fallbackShadowMapTexture->setFilter(osg::Texture2D::MAG_FILTER,osg::Texture2D::NEAREST);
1270
1271    }
1272}
1273
1274osg::Polytope ViewDependentShadowMap::computeLightViewFrustumPolytope(Frustum& frustum, LightData& positionedLight)
1275{
1276    OSG_INFO<<"computeLightViewFrustumPolytope()"<<std::endl;
1277
1278    osg::Polytope polytope;
1279    polytope.setToUnitFrustum();
1280
1281    polytope.transformProvidingInverse( frustum.projectionMatrix );
1282    polytope.transformProvidingInverse( frustum.modelViewMatrix );
1283
1284    osg::Polytope lightVolumePolytope;
1285
1286    if (positionedLight.directionalLight)
1287    {
1288        osg::Polytope::PlaneList& planes = polytope.getPlaneList();
1289        osg::Polytope::ClippingMask selector_mask = 0x1;
1290        osg::Polytope::ClippingMask result_mask = 0x0;
1291        for(unsigned int i=0; i<planes.size(); ++i, selector_mask <<= 1)
1292        {
1293            OSG_INFO<<"      plane "<<planes[i]<<"  planes["<<i<<"].dotProductNormal(lightDir)="<<planes[i].dotProductNormal(positionedLight.lightDir);
1294            if (planes[i].dotProductNormal(positionedLight.lightDir)>=0.0)
1295            {
1296                OSG_INFO<<"     Need remove side "<<i<<std::endl;
1297            }
1298            else
1299            {
1300                OSG_INFO<<std::endl;
1301                lightVolumePolytope.add(planes[i]);
1302                result_mask = result_mask | selector_mask;
1303            }
1304        }
1305
1306        OSG_INFO<<"    planes.size() = "<<planes.size()<<std::endl;
1307        OSG_INFO<<"    planes.getResultMask() = "<<polytope.getResultMask()<<std::endl;
1308        OSG_INFO<<"    resultMask = "<<result_mask<<std::endl;
1309        polytope.setResultMask(result_mask);
1310    }
1311    else
1312    {
1313        const osg::Polytope::PlaneList& planes = polytope.getPlaneList();
1314        osg::Polytope::ClippingMask selector_mask = 0x1;
1315        osg::Polytope::ClippingMask result_mask = 0x0;
1316        for(unsigned int i=0; i<planes.size(); ++i, selector_mask <<= 1)
1317        {
1318
1319            double d = planes[i].distance(positionedLight.lightPos3);
1320            OSG_INFO<<"      plane "<<planes[i]<<"  planes["<<i<<"].distance(lightPos3)="<<d;
1321            if (d<0.0)
1322            {
1323                OSG_INFO<<"     Need remove side "<<i<<std::endl;
1324            }
1325            else
1326            {
1327                OSG_INFO<<std::endl;
1328                lightVolumePolytope.add(planes[i]);
1329                result_mask = result_mask | selector_mask;
1330            }
1331        }
1332        OSG_INFO<<"    planes.size() = "<<planes.size()<<std::endl;
1333        OSG_INFO<<"    planes.getResultMask() = "<<polytope.getResultMask()<<std::endl;
1334        OSG_INFO<<"    resultMask = "<<result_mask<<std::endl;
1335        polytope.setResultMask(result_mask);
1336    }
1337
1338    OSG_INFO<<"Which frustum edges are active?"<<std::endl;
1339    for(unsigned int i=0; i<12; ++i)
1340    {
1341        Frustum::Indices& indices = frustum.edges[i];
1342
1343        unsigned int corner_a = indices[0];
1344        unsigned int corner_b = indices[1];
1345        unsigned int face_a = indices[2];
1346        unsigned int face_b = indices[3];
1347        bool face_a_active = (polytope.getResultMask()&(0x1<<face_a))!=0;
1348        bool face_b_active = (polytope.getResultMask()&(0x1<<face_b))!=0;
1349        unsigned int numActive = 0;
1350        if (face_a_active) ++numActive;
1351        if (face_b_active) ++numActive;
1352        if (numActive==1)
1353        {
1354
1355            osg::Plane boundaryPlane;
1356
1357            if (positionedLight.directionalLight)
1358            {
1359                osg::Vec3d normal = (frustum.corners[corner_b]-frustum.corners[corner_a])^positionedLight.lightDir;
1360                normal.normalize();
1361                boundaryPlane.set(normal, frustum.corners[corner_a]);
1362            }
1363            else
1364            {
1365                boundaryPlane.set(positionedLight.lightPos3, frustum.corners[corner_a], frustum.corners[corner_b]);
1366            }
1367
1368            OSG_INFO<<"Boundary Edge "<<i<<", corner_a="<<corner_a<<", corner_b="<<corner_b<<", face_a_active="<<face_a_active<<", face_b_active="<<face_b_active;
1369            if (boundaryPlane.distance(frustum.center)<0.0)
1370            {
1371                boundaryPlane.flip();
1372                OSG_INFO<<", flipped boundary edge "<<boundaryPlane<<std::endl;
1373            }
1374            else
1375            {
1376                OSG_INFO<<", no need to flip boundary edge "<<boundaryPlane<<std::endl;
1377            }
1378            lightVolumePolytope.add(boundaryPlane);
1379        }
1380        else OSG_INFO<<"Internal Edge "<<i<<", corner_a="<<corner_a<<", corner_b="<<corner_b<<", face_a_active="<<face_a_active<<", face_b_active="<<face_b_active<<std::endl;
1381    }
1382
1383
1384    const osg::Polytope::PlaneList& planes = lightVolumePolytope.getPlaneList();
1385    for(unsigned int i=0; i<planes.size(); ++i)
1386    {
1387        OSG_INFO<<"      plane "<<planes[i]<<"  "<<((lightVolumePolytope.getResultMask() & (0x1<<i))?"on":"off")<<std::endl;
1388    }
1389
1390    return lightVolumePolytope;
1391}
1392
1393bool ViewDependentShadowMap::computeShadowCameraSettings(Frustum& frustum, LightData& positionedLight, osg::Matrixd& projectionMatrix, osg::Matrixd& viewMatrix)
1394{
1395    OSG_INFO<<"standardShadowMapCameraSettings()"<<std::endl;
1396
1397    osg::Vec3d lightSide;
1398
1399    const ShadowSettings* settings = getShadowedScene()->getShadowSettings();
1400
1401    double dotProduct_v = positionedLight.lightDir * frustum.frustumCenterLine;
1402    double gamma_v = acos(dotProduct_v);
1403    if (gamma_v<osg::DegreesToRadians(settings->getPerspectiveShadowMapCutOffAngle()) || gamma_v>osg::DegreesToRadians(180.0-settings->getPerspectiveShadowMapCutOffAngle()))
1404    {
1405        OSG_INFO<<"View direction and Light direction below tolerance"<<std::endl;
1406        osg::Vec3d viewSide = osg::Matrixd::transform3x3(frustum.modelViewMatrix, osg::Vec3d(1.0,0.0,0.0));
1407        lightSide = positionedLight.lightDir ^ (viewSide ^ positionedLight.lightDir);
1408        lightSide.normalize();
1409    }
1410    else
1411    {
1412        lightSide = positionedLight.lightDir ^ frustum.frustumCenterLine;
1413        lightSide.normalize();
1414    }
1415
1416    osg::Vec3d lightUp = lightSide ^ positionedLight.lightDir;
1417
1418#if 0
1419    OSG_NOTICE<<"positionedLight.lightDir="<<positionedLight.lightDir<<std::endl;
1420    OSG_NOTICE<<"lightSide="<<lightSide<<std::endl;
1421    OSG_NOTICE<<"lightUp="<<lightUp<<std::endl;
1422#endif
1423
1424
1425    if (positionedLight.directionalLight)
1426    {
1427        double xMin=0.0, xMax=0.0;
1428        double yMin=0.0, yMax=0.0;
1429        double zMin=0.0, zMax=0.0;
1430
1431        for(Frustum::Vertices::iterator itr = frustum.corners.begin();
1432            itr != frustum.corners.end();
1433            ++itr)
1434        {
1435            osg::Vec3d cornerDelta(*itr - frustum.center);
1436            osg::Vec3d cornerInLightCoords(cornerDelta*lightSide,
1437                                           cornerDelta*lightUp,
1438                                           cornerDelta*positionedLight.lightDir);
1439
1440            OSG_INFO<<"    corner ="<<*itr<<" in lightcoords "<<cornerInLightCoords<<std::endl;
1441
1442            xMin = osg::minimum( xMin, cornerInLightCoords.x());
1443            xMax = osg::maximum( xMax, cornerInLightCoords.x());
1444            yMin = osg::minimum( yMin, cornerInLightCoords.y());
1445            yMax = osg::maximum( yMax, cornerInLightCoords.y());
1446            zMin = osg::minimum( zMin, cornerInLightCoords.z());
1447            zMax = osg::maximum( zMax, cornerInLightCoords.z());
1448        }
1449
1450        OSG_INFO<<"before bs xMin="<<xMin<<", xMax="<<xMax<<", yMin="<<yMin<<", yMax="<<yMax<<", zMin="<<zMin<<", zMax="<<zMax<<std::endl;
1451
1452        osg::BoundingSphere bs = _shadowedScene->getBound();
1453        osg::Vec3d modelCenterRelativeFrustumCenter(bs.center()-frustum.center);
1454        osg::Vec3d modelCenterInLightCoords(modelCenterRelativeFrustumCenter*lightSide,
1455                                            modelCenterRelativeFrustumCenter*lightUp,
1456                                            modelCenterRelativeFrustumCenter*positionedLight.lightDir);
1457
1458        OSG_INFO<<"modelCenterInLight="<<modelCenterInLightCoords<<" radius="<<bs.radius()<<std::endl;
1459        double radius(bs.radius());
1460
1461        xMin = osg::maximum(xMin, modelCenterInLightCoords.x()-radius);
1462        xMax = osg::minimum(xMax, modelCenterInLightCoords.x()+radius);
1463        yMin = osg::maximum(yMin, modelCenterInLightCoords.y()-radius);
1464        yMax = osg::minimum(yMax, modelCenterInLightCoords.y()+radius);
1465        zMin = modelCenterInLightCoords.z()-radius;
1466        zMax = osg::minimum(zMax, modelCenterInLightCoords.z()+radius);
1467
1468        OSG_INFO<<"after bs xMin="<<xMin<<", xMax="<<xMax<<", yMin="<<yMin<<", yMax="<<yMax<<", zMin="<<zMin<<", zMax="<<zMax<<std::endl;
1469
1470        if (xMin>=xMax || yMin>=yMax || zMin>=zMax)
1471        {
1472            OSG_INFO<<"Warning nothing available to create shadows"<<zMax<<std::endl;
1473            return false;
1474        }
1475        else
1476        {
1477            projectionMatrix.makeOrtho(xMin,xMax, yMin, yMax,0.0,zMax-zMin);
1478            viewMatrix.makeLookAt(frustum.center+positionedLight.lightDir*zMin, frustum.center+positionedLight.lightDir*zMax, lightUp);
1479        }
1480    }
1481    else
1482    {
1483        double zMax=-DBL_MAX;
1484
1485        OSG_INFO<<"lightDir = "<<positionedLight.lightDir<<std::endl;
1486        OSG_INFO<<"lightPos3 = "<<positionedLight.lightPos3<<std::endl;
1487        for(Frustum::Vertices::iterator itr = frustum.corners.begin();
1488            itr != frustum.corners.end();
1489            ++itr)
1490        {
1491            osg::Vec3d cornerDelta(*itr - positionedLight.lightPos3);
1492            osg::Vec3d cornerInLightCoords(cornerDelta*lightSide,
1493                                           cornerDelta*lightUp,
1494                                           cornerDelta*positionedLight.lightDir);
1495
1496            OSG_INFO<<"   cornerInLightCoords= "<<cornerInLightCoords<<std::endl;
1497
1498            zMax = osg::maximum( zMax, cornerInLightCoords.z());
1499        }
1500
1501        OSG_INFO<<"zMax = "<<zMax<<std::endl;
1502
1503        if (zMax<0.0)
1504        {
1505            // view frustum entirely behind light
1506            return false;
1507        }
1508
1509        double minRatio = 0.0001;
1510        double zMin=zMax*minRatio;
1511
1512        double fov = positionedLight.light->getSpotCutoff() * 2.0;
1513        if(fov < 180.0)   // spotlight
1514        {
1515            projectionMatrix.makePerspective(fov, 1.0, zMin, zMax);
1516            viewMatrix.makeLookAt(positionedLight.lightPos3,
1517                                          positionedLight.lightPos3+positionedLight.lightDir, lightUp);
1518        }
1519        else
1520        {
1521            double fovMAX = 160.0f;
1522            fov = 0.0;
1523
1524            // calculate the max FOV from the corners of the frustum relative to the light position
1525            for(Frustum::Vertices::iterator itr = frustum.corners.begin();
1526                itr != frustum.corners.end();
1527                ++itr)
1528            {
1529                osg::Vec3d cornerDelta(*itr - positionedLight.lightPos3);
1530                double length = cornerDelta.length();
1531
1532                if (length==0.0) fov = osg::minimum(fov, 180.0);
1533                else
1534                {
1535                    double dotProduct = cornerDelta*positionedLight.lightDir;
1536                    double angle = 2.0*osg::RadiansToDegrees( acos(dotProduct/length) );
1537                    fov = osg::maximum(fov, angle);
1538                }
1539            }
1540
1541            OSG_INFO<<"Computed fov = "<<fov<<std::endl;
1542
1543            if (fov>fovMAX)
1544            {
1545                OSG_INFO<<"Clampping fov = "<<fov<<std::endl;
1546                fov=fovMAX;
1547            }
1548
1549            projectionMatrix.makePerspective(fov, 1.0, zMin, zMax);
1550            viewMatrix.makeLookAt(positionedLight.lightPos3,
1551                                  positionedLight.lightPos3+positionedLight.lightDir, lightUp);
1552
1553        }
1554    }
1555    return true;
1556}
1557
1558struct ConvexHull
1559{
1560    typedef std::vector<osg::Vec3d> Vertices;
1561    typedef std::pair< osg::Vec3d, osg::Vec3d > Edge;
1562    typedef std::list< Edge > Edges;
1563
1564    Edges _edges;
1565
1566    bool valid() const { return !_edges.empty(); }
1567
1568    void setToFrustum(ViewDependentShadowMap::Frustum& frustum)
1569    {
1570        _edges.push_back( Edge(frustum.corners[0],frustum.corners[1]) );
1571        _edges.push_back( Edge(frustum.corners[1],frustum.corners[2]) );
1572        _edges.push_back( Edge(frustum.corners[2],frustum.corners[3]) );
1573        _edges.push_back( Edge(frustum.corners[3],frustum.corners[0]) );
1574
1575        _edges.push_back( Edge(frustum.corners[4],frustum.corners[5]) );
1576        _edges.push_back( Edge(frustum.corners[5],frustum.corners[6]) );
1577        _edges.push_back( Edge(frustum.corners[6],frustum.corners[7]) );
1578        _edges.push_back( Edge(frustum.corners[7],frustum.corners[4]) );
1579
1580        _edges.push_back( Edge(frustum.corners[0],frustum.corners[4]) );
1581        _edges.push_back( Edge(frustum.corners[1],frustum.corners[5]) );
1582        _edges.push_back( Edge(frustum.corners[2],frustum.corners[6]) );
1583        _edges.push_back( Edge(frustum.corners[3],frustum.corners[7]) );
1584    }
1585
1586    void transform(const osg::Matrixd& m)
1587    {
1588        for(Edges::iterator itr = _edges.begin();
1589            itr != _edges.end();
1590            ++itr)
1591        {
1592            itr->first = itr->first * m;
1593            itr->second = itr->second * m;
1594        }
1595    }
1596
1597    void clip(const osg::Plane& plane)
1598    {
1599        Vertices intersections;
1600
1601        // OSG_NOTICE<<"clip("<<plane<<") edges.size()="<<_edges.size()<<std::endl;
1602        for(Edges::iterator itr = _edges.begin();
1603            itr != _edges.end();
1604            )
1605        {
1606            double d0 = plane.distance(itr->first);
1607            double d1 = plane.distance(itr->second);
1608            if (d0<0.0 && d1<0.0)
1609            {
1610                // OSG_NOTICE<<"  Edge completely outside, removing"<<std::endl;
1611                Edges::iterator to_delete_itr = itr;
1612                ++itr;
1613                _edges.erase(to_delete_itr);
1614            }
1615            else if (d0>=0.0 && d1>=0.0)
1616            {
1617                // OSG_NOTICE<<"  Edge completely inside"<<std::endl;
1618                ++itr;
1619            }
1620            else
1621            {
1622                osg::Vec3d& v0 = itr->first;
1623                osg::Vec3d& v1 = itr->second;
1624                osg::Vec3d intersection = v0 - (v1-v0)*(d0/(d1-d0));
1625                intersections.push_back(intersection);
1626                // OSG_NOTICE<<"  Edge across clip plane, v0="<<v0<<", v1="<<v1<<", intersection= "<<intersection<<std::endl;
1627                if (d0<0.0)
1628                {
1629                    // move first vertex on edge
1630                    v0 = intersection;
1631                }
1632                else
1633                {
1634                    // move second vertex on edge
1635                    v1 = intersection;
1636                }
1637
1638                ++itr;
1639            }
1640        }
1641        // OSG_NOTICE<<"After clipping, have "<<intersections.size()<<" to insert"<<std::endl;
1642
1643        if (intersections.size() < 2)
1644        {
1645            return;
1646        }
1647
1648        if (intersections.size() == 2)
1649        {
1650            _edges.push_back( Edge(intersections[0], intersections[1]) );
1651            return;
1652        }
1653
1654        if (intersections.size() == 3)
1655        {
1656            _edges.push_back( Edge(intersections[0], intersections[1]) );
1657            _edges.push_back( Edge(intersections[1], intersections[2]) );
1658            _edges.push_back( Edge(intersections[2], intersections[0]) );
1659            return;
1660        }
1661
1662        // more than 3 intersections so have to sort them in clockwise order so that
1663        // we can generate the edges correctly.
1664
1665        osg::Vec3d normal(plane.getNormal());
1666
1667        osg::Vec3d side_x = osg::Vec3d(1.0,0.0,0.0) ^ normal;
1668        osg::Vec3d side_y = osg::Vec3d(0.0,1.0,0.0) ^ normal;
1669        osg::Vec3d side = (side_x.length2()>=side_y.length2()) ? side_x : side_y;
1670        side.normalize();
1671
1672        osg::Vec3d up = side ^ normal;
1673        up.normalize();
1674
1675        osg::Vec3d center;
1676        for(Vertices::iterator itr = intersections.begin();
1677            itr != intersections.end();
1678            ++itr)
1679        {
1680            center += *itr;
1681        }
1682
1683        center /= double(intersections.size());
1684
1685        typedef std::map<double, osg::Vec3d> VertexMap;
1686        VertexMap vertexMap;
1687        for(Vertices::iterator itr = intersections.begin();
1688            itr != intersections.end();
1689            ++itr)
1690        {
1691            osg::Vec3d dv = (*itr-center);
1692            double h = dv * side;
1693            double v = dv * up;
1694            double angle = atan2(h,v);
1695            // OSG_NOTICE<<"angle = "<<osg::RadiansToDegrees(angle)<<", h="<<h<<" v= "<<v<<std::endl;
1696            vertexMap[angle] = *itr;
1697        }
1698
1699        osg::Vec3d previous_v = vertexMap.rbegin()->second;
1700        for(VertexMap::iterator itr = vertexMap.begin();
1701            itr != vertexMap.end();
1702            ++itr)
1703        {
1704            _edges.push_back(Edge(previous_v, itr->second));
1705            previous_v = itr->second;
1706        }
1707
1708        // OSG_NOTICE<<"  after clip("<<plane<<") edges.size()="<<_edges.size()<<std::endl;
1709    }
1710
1711    void clip(const osg::Polytope& polytope)
1712    {
1713        const osg::Polytope::PlaneList& planes = polytope.getPlaneList();
1714        for(osg::Polytope::PlaneList::const_iterator itr = planes.begin();
1715            itr != planes.end();
1716            ++itr)
1717        {
1718            clip(*itr);
1719        }
1720    }
1721
1722    double min(unsigned int index) const
1723    {
1724        double m = DBL_MAX;
1725        for(Edges::const_iterator itr = _edges.begin();
1726            itr != _edges.end();
1727            ++itr)
1728        {
1729            const Edge& edge = *itr;
1730            if (edge.first[index]<m) m = edge.first[index];
1731            if (edge.second[index]<m) m = edge.second[index];
1732        }
1733        return m;
1734    }
1735
1736    double max(unsigned int index) const
1737    {
1738        double m = -DBL_MAX;
1739        for(Edges::const_iterator itr = _edges.begin();
1740            itr != _edges.end();
1741            ++itr)
1742        {
1743            const Edge& edge = *itr;
1744            if (edge.first[index]>m) m = edge.first[index];
1745            if (edge.second[index]>m) m = edge.second[index];
1746        }
1747        return m;
1748    }
1749
1750    double minRatio(const osg::Vec3d& eye, unsigned int index) const
1751    {
1752        double m = DBL_MAX;
1753        osg::Vec3d delta;
1754        double ratio;
1755        for(Edges::const_iterator itr = _edges.begin();
1756            itr != _edges.end();
1757            ++itr)
1758        {
1759            const Edge& edge = *itr;
1760
1761            delta = edge.first-eye;
1762            ratio = delta[index]/delta[1];
1763            if (ratio<m) m = ratio;
1764
1765            delta = edge.second-eye;
1766            ratio = delta[index]/delta[1];
1767            if (ratio<m) m = ratio;
1768        }
1769        return m;
1770    }
1771
1772    double maxRatio(const osg::Vec3d& eye, unsigned int index) const
1773    {
1774        double m = -DBL_MAX;
1775        osg::Vec3d delta;
1776        double ratio;
1777        for(Edges::const_iterator itr = _edges.begin();
1778            itr != _edges.end();
1779            ++itr)
1780        {
1781            const Edge& edge = *itr;
1782
1783            delta = edge.first-eye;
1784            ratio = delta[index]/delta[1];
1785            if (ratio>m) m = ratio;
1786
1787            delta = edge.second-eye;
1788            ratio = delta[index]/delta[1];
1789            if (ratio>m) m = ratio;
1790        }
1791        return m;
1792    }
1793
1794    void output(std::ostream& out)
1795    {
1796        out<<"ConvexHull"<<std::endl;
1797        for(Edges::const_iterator itr = _edges.begin();
1798            itr != _edges.end();
1799            ++itr)
1800        {
1801            const Edge& edge = *itr;
1802            out<<"   edge ("<<edge.first<<") ("<<edge.second<<")"<<std::endl;
1803        }
1804    }
1805};
1806
1807
1808struct RenderLeafBounds
1809{
1810    RenderLeafBounds():
1811        computeRatios(false),
1812        numRenderLeaf(0),
1813        n(0.0),
1814        previous_modelview(0),
1815        clip_min_x(-1.0), clip_max_x(1.0),
1816        clip_min_y(-1.0), clip_max_y(1.0),
1817        clip_min_z(-1.0), clip_max_z(1.0),
1818        clip_min_x_ratio(-DBL_MAX), clip_max_x_ratio(DBL_MAX),
1819        clip_min_z_ratio(-DBL_MAX), clip_max_z_ratio(DBL_MAX),
1820        min_x_ratio(DBL_MAX), max_x_ratio(-DBL_MAX),
1821        min_z_ratio(DBL_MAX), max_z_ratio(-DBL_MAX),
1822        min_x(1.0), max_x(-1.0),
1823        min_y(1.0), max_y(-1.0),
1824        min_z(1.0), max_z(-1.0)
1825    {
1826        //OSG_NOTICE<<std::endl<<"RenderLeafBounds"<<std::endl;
1827    }
1828
1829    void set(const osg::Matrixd& p)
1830    {
1831        computeRatios = false;
1832        light_p = p;
1833        clip_min_x = -DBL_MAX; clip_max_x = DBL_MAX;
1834        clip_min_y = -DBL_MAX; clip_max_y = DBL_MAX;
1835        clip_min_z = -DBL_MAX; clip_max_z = DBL_MAX;
1836        min_x = DBL_MAX; max_x = -DBL_MAX;
1837        min_y = DBL_MAX; max_y = -DBL_MAX;
1838        min_z = DBL_MAX; max_z = -DBL_MAX;
1839    }
1840
1841    void set(const osg::Matrixd& p, osg::Vec3d& e_ls, double nr)
1842    {
1843        computeRatios = true;
1844        light_p = p;
1845        eye_ls = e_ls;
1846        n = nr;
1847    }
1848
1849    void operator() (const osgUtil::RenderLeaf* renderLeaf)
1850    {
1851        ++numRenderLeaf;
1852
1853        if (renderLeaf->_modelview.get()!=previous_modelview)
1854        {
1855            previous_modelview = renderLeaf->_modelview.get();
1856            if (previous_modelview)
1857            {
1858                light_mvp.mult(*renderLeaf->_modelview, light_p);
1859            }
1860            else
1861            {
1862                // no modelview matrix (such as when LightPointNode is in the scene graph) so assume
1863                // that modelview matrix is indentity.
1864                light_mvp = light_p;
1865            }
1866            // OSG_INFO<<"Computing new light_mvp "<<light_mvp<<std::endl;
1867        }
1868        else
1869        {
1870            // OSG_INFO<<"Reusing light_mvp "<<light_mvp<<std::endl;
1871        }
1872
1873        const osg::BoundingBox& bb = renderLeaf->_drawable->getBound();
1874        if (bb.valid())
1875        {
1876            // OSG_NOTICE<<"checked extents of "<<renderLeaf->_drawable->getName()<<std::endl;
1877            handle(osg::Vec3d(bb.xMin(),bb.yMin(),bb.zMin()));
1878            handle(osg::Vec3d(bb.xMax(),bb.yMin(),bb.zMin()));
1879            handle(osg::Vec3d(bb.xMin(),bb.yMax(),bb.zMin()));
1880            handle(osg::Vec3d(bb.xMax(),bb.yMax(),bb.zMin()));
1881            handle(osg::Vec3d(bb.xMin(),bb.yMin(),bb.zMax()));
1882            handle(osg::Vec3d(bb.xMax(),bb.yMin(),bb.zMax()));
1883            handle(osg::Vec3d(bb.xMin(),bb.yMax(),bb.zMax()));
1884            handle(osg::Vec3d(bb.xMax(),bb.yMax(),bb.zMax()));
1885        }
1886        else
1887        {
1888            OSG_INFO<<"bb invalid"<<std::endl;
1889        }
1890    }
1891
1892    void handle(const osg::Vec3d& v)
1893    {
1894        osg::Vec3d ls = v * light_mvp;
1895
1896        // OSG_NOTICE<<"   corner v="<<v<<", ls="<<ls<<std::endl;
1897
1898        if (computeRatios)
1899        {
1900            osg::Vec3d delta = ls-eye_ls;
1901
1902            double x_ratio, z_ratio;
1903            if (delta.y()>n)
1904            {
1905                x_ratio = delta.x()/delta.y();
1906                z_ratio = delta.z()/delta.y();
1907            }
1908            else
1909            {
1910                x_ratio = delta.x()/n;
1911                z_ratio = delta.z()/n;
1912            }
1913
1914            if (x_ratio<min_x_ratio) min_x_ratio = x_ratio;
1915            if (x_ratio>max_x_ratio) max_x_ratio = x_ratio;
1916            if (z_ratio<min_z_ratio) min_z_ratio = z_ratio;
1917            if (z_ratio>max_z_ratio) max_z_ratio = z_ratio;
1918        }
1919
1920        // clip to the light space
1921        if (ls.x()<clip_min_x) ls.x()=clip_min_x;
1922        if (ls.x()>clip_max_x) ls.x()=clip_max_x;
1923        if (ls.y()<clip_min_y) ls.y()=clip_min_y;
1924        if (ls.y()>clip_max_y) ls.y()=clip_max_y;
1925        if (ls.z()<clip_min_z) ls.z()=clip_min_z;
1926        if (ls.z()>clip_max_z) ls.z()=clip_max_z;
1927
1928        // compute the xyz range.
1929        if (ls.x()<min_x) min_x=ls.x();
1930        if (ls.x()>max_x) max_x=ls.x();
1931        if (ls.y()<min_y) min_y=ls.y();
1932        if (ls.y()>max_y) max_y=ls.y();
1933        if (ls.z()<min_z) { min_z=ls.z(); /* OSG_NOTICE<<" - ";*/ }
1934        if (ls.z()>max_z) { max_z=ls.z(); /* OSG_NOTICE<<" + ";*/ }
1935
1936        // OSG_NOTICE<<"   bb.z() in ls = "<<ls.z()<<std::endl;
1937
1938    }
1939
1940    bool                computeRatios;
1941
1942    unsigned int        numRenderLeaf;
1943
1944    osg::Matrixd        light_p;
1945    osg::Vec3d          eye_ls;
1946    double              n;
1947
1948    osg::Matrixd        light_mvp;
1949    osg::RefMatrix*     previous_modelview;
1950    unsigned int        numLeaves;
1951
1952    double clip_min_x, clip_max_x;
1953    double clip_min_y, clip_max_y;
1954    double clip_min_z, clip_max_z;
1955
1956    double clip_min_x_ratio, clip_max_x_ratio;
1957    double clip_min_z_ratio, clip_max_z_ratio;
1958
1959    double min_x_ratio, max_x_ratio;
1960    double min_z_ratio, max_z_ratio;
1961    double min_x, max_x;
1962    double min_y, max_y;
1963    double min_z, max_z;
1964};
1965
1966bool ViewDependentShadowMap::adjustPerspectiveShadowMapCameraSettings(osgUtil::RenderStage* renderStage, Frustum& frustum, LightData& /*positionedLight*/, osg::Camera* camera)
1967{
1968    const ShadowSettings* settings = getShadowedScene()->getShadowSettings();
1969
1970    //frustum.projectionMatrix;
1971    //frustum.modelViewMatrix;
1972
1973    osg::Matrixd light_p = camera->getProjectionMatrix();
1974    osg::Matrixd light_v = camera->getViewMatrix();
1975    osg::Matrixd light_vp = light_v * light_p;
1976    osg::Vec3d lightdir(0.0,0.0,-1.0);
1977
1978    // check whether this light space projection is perspective or orthographic.
1979    bool orthographicLightSpaceProjection = light_p(0,3)==0.0 && light_p(1,3)==0.0 && light_p(2,3)==0.0;
1980
1981    if (!orthographicLightSpaceProjection)
1982    {
1983        OSG_INFO<<"perspective light space projection not yet supported."<<std::endl;
1984        return false;
1985    }
1986
1987
1988    //OSG_NOTICE<<"light_v="<<light_v<<std::endl;
1989    //OSG_NOTICE<<"light_p="<<light_p<<std::endl;
1990
1991    ConvexHull convexHull;
1992    convexHull.setToFrustum(frustum);
1993
1994#if 0
1995    OSG_NOTICE<<"ws ConvexHull xMin="<<convexHull.min(0)<<", xMax="<<convexHull.max(0)<<std::endl;
1996    OSG_NOTICE<<"ws ConvexHull yMin="<<convexHull.min(1)<<", yMax="<<convexHull.max(1)<<std::endl;
1997    OSG_NOTICE<<"ws ConvexHull zMin="<<convexHull.min(2)<<", zMax="<<convexHull.max(2)<<std::endl;
1998
1999    convexHull.output(osg::notify(osg::NOTICE));
2000#endif
2001
2002    convexHull.transform(light_vp);
2003
2004#if 0
2005    convexHull.output(osg::notify(osg::NOTICE));
2006
2007    OSG_NOTICE<<"ls ConvexHull xMin="<<convexHull.min(0)<<", xMax="<<convexHull.max(0)<<std::endl;
2008    OSG_NOTICE<<"ls ConvexHull yMin="<<convexHull.min(1)<<", yMax="<<convexHull.max(1)<<std::endl;
2009    OSG_NOTICE<<"ls ConvexHull zMin="<<convexHull.min(2)<<", zMax="<<convexHull.max(2)<<std::endl;
2010#endif
2011
2012#if 0
2013    // only applicable when the light space contains the whole model contained in the view frustum.
2014    {
2015        convexHull.clip(osg::Plane(0.0,0.0,1,1.0)); // clip by near plane of light space.
2016        convexHull.clip(osg::Plane(0.0,0.0,-1,1.0));  // clip by far plane of light space.
2017    }
2018#endif
2019
2020#if 1
2021    if (renderStage)
2022    {
2023#if 1
2024        osg::ElapsedTime timer;
2025#endif
2026
2027        RenderLeafTraverser<RenderLeafBounds> rli;
2028        rli.set(light_p);
2029        rli.traverse(renderStage);
2030
2031        if (rli.numRenderLeaf==0)
2032        {
2033            return false;
2034        }
2035#if 0
2036        OSG_NOTICE<<"New Time for RenderLeafTraverser "<<timer.elapsedTime_m()<<"ms, number of render leaves "<<rli.numRenderLeaf<<std::endl;
2037        OSG_NOTICE<<"   scene bounds min_x="<<rli.min_x<<", max_x="<<rli.max_x<<std::endl;
2038        OSG_NOTICE<<"   scene bounds min_y="<<rli.min_y<<", max_y="<<rli.max_y<<std::endl;
2039        OSG_NOTICE<<"   scene bounds min_z="<<rli.min_z<<", max_z="<<rli.max_z<<std::endl;
2040#endif
2041
2042#if 0
2043        double widest_x = osg::maximum(fabs(rli.min_x), fabs(rli.max_x));
2044        double widest_y = osg::maximum(fabs(rli.min_y), fabs(rli.max_y));
2045        double widest_z = osg::maximum(fabs(rli.min_z), fabs(rli.max_z));
2046#endif
2047
2048#if 1
2049#if 1
2050        convexHull.clip(osg::Plane(1.0,0.0,0.0,-rli.min_x));
2051        convexHull.clip(osg::Plane(-1.0,0.0,0.0,rli.max_x));
2052#else
2053        convexHull.clip(osg::Plane(1.0,0.0,0.0,widest_x));
2054        convexHull.clip(osg::Plane(-1.0,0.0,0.0,widest_x));
2055#endif
2056#if 1
2057        convexHull.clip(osg::Plane(0.0,1.0,0.0,-rli.min_y));
2058        convexHull.clip(osg::Plane(0.0,-1.0,0.0,rli.max_y));
2059#endif
2060#endif
2061
2062#if 0
2063        convexHull.clip(osg::Plane(0.0,0.0,1.0,-rli.min_z));
2064        convexHull.clip(osg::Plane(0.0,0.0,-1.0,rli.max_z));
2065#else
2066        convexHull.clip(osg::Plane(0.0,0.0,1.0,1.0));
2067        convexHull.clip(osg::Plane(0.0,0.0,-1.0,1.0));
2068#endif
2069
2070#if 0
2071        OSG_NOTICE<<"widest_x = "<<widest_x<<std::endl;
2072        OSG_NOTICE<<"widest_y = "<<widest_y<<std::endl;
2073        OSG_NOTICE<<"widest_z = "<<widest_z<<std::endl;
2074#endif
2075    }
2076#endif
2077
2078#if 0
2079    convexHull.output(osg::notify(osg::NOTICE));
2080
2081    OSG_NOTICE<<"after clipped ls ConvexHull xMin="<<convexHull.min(0)<<", xMax="<<convexHull.max(0)<<std::endl;
2082    OSG_NOTICE<<"after clipped ls ConvexHull yMin="<<convexHull.min(1)<<", yMax="<<convexHull.max(1)<<std::endl;
2083    OSG_NOTICE<<"after clipped ls ConvexHull zMin="<<convexHull.min(2)<<", zMax="<<convexHull.max(2)<<std::endl;
2084#endif
2085
2086    double xMin=-1.0, xMax=1.0;
2087    double yMin=-1.0, yMax=1.0;
2088    double zMin=-1.0, zMax=1.0;
2089
2090    if (convexHull.valid())
2091    {
2092        double widest_x = osg::maximum(fabs(convexHull.min(0)), fabs(convexHull.max(0)));
2093        xMin = osg::maximum(-1.0,-widest_x);
2094        xMax = osg::minimum(1.0,widest_x);
2095        yMin = osg::maximum(-1.0,convexHull.min(1));
2096        yMax = osg::minimum(1.0,convexHull.max(1));
2097    }
2098    else
2099    {
2100        // clipping of convex hull has invalidated it, so reset it so later checks on it provide valid results.
2101        convexHull.setToFrustum(frustum);
2102        convexHull.transform(light_vp);
2103    }
2104
2105#if 0
2106    OSG_NOTICE<<"xMin = "<<xMin<<", \txMax = "<<xMax<<std::endl;
2107    OSG_NOTICE<<"yMin = "<<yMin<<", \tyMax = "<<yMax<<std::endl;
2108    OSG_NOTICE<<"zMin = "<<zMin<<", \tzMax = "<<zMax<<std::endl;
2109#endif
2110
2111#if 1
2112    // we always want the lightspace to include the computed near plane.
2113    zMin = -1.0;
2114    if (xMin!=-1.0 || yMin!=-1.0 || zMin!=-1.0 ||
2115        xMax!=1.0 || yMax!=1.0 || zMax!=1.0)
2116    {
2117        osg::Matrix m;
2118        m.makeTranslate(osg::Vec3d(-0.5*(xMax+xMin),
2119                                    -0.5*(yMax+yMin),
2120                                    -0.5*(zMax+zMin)));
2121
2122        m.postMultScale(osg::Vec3d(2.0/(xMax-xMin),
2123                                   2.0/(yMax-yMin),
2124                                   2.0/(zMax-zMin)));
2125
2126        convexHull.transform(m);
2127        light_p.postMult(m);
2128        light_vp = light_v * light_p;
2129
2130#if 0
2131        OSG_NOTICE<<"Adjusting projection matrix "<<m<<std::endl;
2132        convexHull.output(osg::notify(osg::NOTICE));
2133#endif
2134        camera->setProjectionMatrix(light_p);
2135    }
2136
2137#endif
2138
2139    osg::Vec3d eye_v = frustum.eye * light_v;
2140    //osg::Vec3d centerNearPlane_v = frustum.centerNearPlane * light_v;
2141    osg::Vec3d center_v = frustum.center * light_v;
2142    osg::Vec3d viewdir_v = center_v-eye_v; viewdir_v.normalize();
2143
2144    double dotProduct_v = lightdir * viewdir_v;
2145    double gamma_v = acos(dotProduct_v);
2146    if (gamma_v<osg::DegreesToRadians(settings->getPerspectiveShadowMapCutOffAngle()) || gamma_v>osg::DegreesToRadians(180-settings->getPerspectiveShadowMapCutOffAngle()))
2147    {
2148        // OSG_NOTICE<<"Light and view vectors near parrallel - use standard shadow map."<<std::endl;
2149        return true;
2150    }
2151
2152    //OSG_NOTICE<<"gamma="<<osg::RadiansToDegrees(gamma_v)<<std::endl;
2153    //OSG_NOTICE<<"eye_v="<<eye_v<<std::endl;
2154    //OSG_NOTICE<<"viewdir_v="<<viewdir_v<<std::endl;
2155
2156    osg::Vec3d eye_ls = frustum.eye * light_vp;
2157#if 0
2158    if (eye_ls.y()>-1.0)
2159    {
2160        OSG_NOTICE<<"Eye point within light space - use standard shadow map."<<std::endl;
2161        return true;
2162    }
2163#endif
2164
2165    //osg::Vec3d centerNearPlane_ls = frustum.centerNearPlane * light_vp;
2166    //osg::Vec3d centerFarPlane_ls = frustum.centerFarPlane * light_vp;
2167    osg::Vec3d center_ls = frustum.center * light_vp;
2168    osg::Vec3d viewdir_ls = center_ls-eye_ls; viewdir_ls.normalize();
2169
2170    osg::Vec3d side = lightdir ^ viewdir_ls; side.normalize();
2171    osg::Vec3d up = side ^ lightdir;
2172
2173    double d = 2.0;
2174
2175    double alpha = osg::DegreesToRadians(30.0);
2176    double n = tan(alpha)*tan(osg::PI_2-gamma_v)*tan(osg::PI_2-gamma_v);
2177    //double n = tan(alpha)*tan(osg::PI_2-gamma_v);
2178
2179    //OSG_NOTICE<<"n = "<<n<<", eye_ls.y()="<<eye_ls.y()<<", eye_v="<<eye_v<<", eye="<<frustum.eye<<std::endl;
2180    double min_n = osg::maximum(-1.0-eye_ls.y(), settings->getMinimumShadowMapNearFarRatio());
2181    if (n<min_n)
2182    {
2183        //OSG_NOTICE<<"Clamping n to eye point"<<std::endl;
2184        n=min_n;
2185    }
2186
2187    //n = min_n;
2188
2189    //n = 0.01;
2190
2191    //n = z_n;
2192
2193    double f = n+d;
2194
2195    double a = (f+n)/(f-n);
2196    double b = -2.0*f*n/(f-n);
2197
2198    osg::Vec3d virtual_eye(0.0,-1.0-n, eye_ls.z());
2199
2200    osg::Matrixd lightView;
2201    lightView.makeLookAt(virtual_eye, virtual_eye+lightdir, up);
2202
2203#if 0
2204    OSG_NOTICE<<"n = "<<n<<", f="<<f<<std::endl;
2205    OSG_NOTICE<<"eye_ls = "<<eye_ls<<", virtual_eye="<<virtual_eye<<std::endl;
2206    OSG_NOTICE<<"frustum.eyes="<<frustum.eye<<std::endl;
2207#endif
2208
2209    double min_x_ratio = 0.0;
2210    double max_x_ratio = 0.0;
2211    double min_z_ratio = FLT_MAX;
2212    double max_z_ratio = -FLT_MAX;
2213
2214    min_x_ratio = convexHull.valid() ? convexHull.minRatio(virtual_eye,0) : -DBL_MAX;
2215    max_x_ratio = convexHull.valid() ? convexHull.maxRatio(virtual_eye,0) : DBL_MAX;
2216    //min_z_ratio = convexHull.minRatio(virtual_eye,2);
2217    //max_z_ratio = convexHull.maxRatio(virtual_eye,2);
2218
2219#if 0
2220    OSG_NOTICE<<"convexHull min_x_ratio = "<<min_x_ratio<<std::endl;
2221    OSG_NOTICE<<"convexHull max_x_ratio = "<<max_x_ratio<<std::endl;
2222    OSG_NOTICE<<"convexHull min_z_ratio = "<<min_z_ratio<<std::endl;
2223    OSG_NOTICE<<"convexHull max_z_ratio = "<<max_z_ratio<<std::endl;
2224#endif
2225
2226    #if 1
2227    if (renderStage)
2228    {
2229#if 1
2230        osg::ElapsedTime timer;
2231#endif
2232
2233        RenderLeafTraverser<RenderLeafBounds> rli;
2234        rli.set(light_p, virtual_eye, n);
2235        rli.traverse(renderStage);
2236
2237        if (rli.numRenderLeaf==0)
2238        {
2239            return false;
2240        }
2241
2242#if 0
2243        OSG_NOTICE<<"Time for RenderLeafTraverser "<<timer.elapsedTime_m()<<"ms, number of render leaves "<<rli.numRenderLeaf<<std::endl;
2244        OSG_NOTICE<<"scene bounds min_x="<<rli.min_x<<", max_x="<<rli.max_x<<std::endl;
2245        OSG_NOTICE<<"scene bounds min_y="<<rli.min_y<<", max_y="<<rli.max_y<<std::endl;
2246        OSG_NOTICE<<"scene bounds min_z="<<rli.min_z<<", max_z="<<rli.max_z<<std::endl;
2247        OSG_NOTICE<<"min_x_ratio="<<rli.min_x_ratio<<", max_x_ratio="<<rli.max_x_ratio<<std::endl;
2248        OSG_NOTICE<<"min_z_ratio="<<rli.min_z_ratio<<", max_z_ratio="<<rli.max_z_ratio<<std::endl;
2249#endif
2250        if (rli.min_x_ratio>min_x_ratio) min_x_ratio = rli.min_x_ratio;
2251        if (rli.max_x_ratio<max_x_ratio) max_x_ratio = rli.max_x_ratio;
2252
2253        /*if (rli.min_z_ratio>min_z_ratio)*/ min_z_ratio = rli.min_z_ratio;
2254        /*if (rli.max_z_ratio<max_z_ratio)*/ max_z_ratio = rli.max_z_ratio;
2255    }
2256#endif
2257    double best_x_ratio = osg::maximum(fabs(min_x_ratio),fabs(max_x_ratio));
2258    double best_z_ratio = osg::maximum(fabs(min_z_ratio),fabs(max_z_ratio));
2259
2260    //best_z_ratio = osg::maximum(1.0, best_z_ratio);
2261#if 0
2262    OSG_NOTICE<<"min_x_ratio = "<<min_x_ratio<<std::endl;
2263    OSG_NOTICE<<"max_x_ratio = "<<max_x_ratio<<std::endl;
2264    OSG_NOTICE<<"best_x_ratio = "<<best_x_ratio<<std::endl;
2265    OSG_NOTICE<<"min_z_ratio = "<<min_z_ratio<<std::endl;
2266    OSG_NOTICE<<"max_z_ratio = "<<max_z_ratio<<std::endl;
2267    OSG_NOTICE<<"best_z_ratio = "<<best_z_ratio<<std::endl;
2268#endif
2269
2270    //best_z_ratio *= 10.0;
2271
2272    osg::Matrixd lightPerspective( 1.0/best_x_ratio,  0.0, 0.0,  0.0,
2273                                   0.0,  a,   0.0,  1.0,
2274                                   0.0,  0.0, 1.0/best_z_ratio,  0.0,
2275                                   0.0,  b,   0.0,  0.0 );
2276    osg::Matrixd light_persp = light_p * lightView * lightPerspective;
2277
2278#if 0
2279    OSG_NOTICE<<"light_p = "<<light_p<<std::endl;
2280    OSG_NOTICE<<"lightView = "<<lightView<<std::endl;
2281    OSG_NOTICE<<"lightPerspective = "<<lightPerspective<<std::endl;
2282    OSG_NOTICE<<"light_persp result = "<<light_persp<<std::endl;
2283#endif
2284    camera->setProjectionMatrix(light_persp);
2285
2286    return true;
2287}
2288
2289bool ViewDependentShadowMap::assignTexGenSettings(osgUtil::CullVisitor* cv, osg::Camera* camera, unsigned int textureUnit, osg::TexGen* texgen)
2290{
2291    OSG_INFO<<"assignTexGenSettings() textureUnit="<<textureUnit<<" texgen="<<texgen<<std::endl;
2292
2293    texgen->setMode(osg::TexGen::EYE_LINEAR);
2294
2295    // compute the matrix which takes a vertex from local coords into tex coords
2296    // We actually use two matrices one used to define texgen
2297    // and second that will be used as modelview when appling to OpenGL
2298    texgen->setPlanesFromMatrix( camera->getProjectionMatrix() *
2299                                 osg::Matrix::translate(1.0,1.0,1.0) *
2300                                 osg::Matrix::scale(0.5,0.5,0.5) );
2301
2302    // Place texgen with modelview which removes big offsets (making it float friendly)
2303    osg::ref_ptr<osg::RefMatrix> refMatrix =
2304        new osg::RefMatrix( camera->getInverseViewMatrix() * (*(cv->getModelViewMatrix())) );
2305
2306    osgUtil::RenderStage* currentStage = cv->getCurrentRenderBin()->getStage();
2307    currentStage->getPositionalStateContainer()->addPositionedTextureAttribute( textureUnit, refMatrix.get(), texgen );
2308    return true;
2309}
2310
2311void ViewDependentShadowMap::cullShadowReceivingScene(osgUtil::CullVisitor* cv) const
2312{
2313    OSG_INFO<<"cullShadowReceivingScene()"<<std::endl;
2314
2315    // record the traversal mask on entry so we can reapply it later.
2316    unsigned int traversalMask = cv->getTraversalMask();
2317
2318    cv->setTraversalMask( traversalMask & _shadowedScene->getShadowSettings()->getReceivesShadowTraversalMask() );
2319
2320    _shadowedScene->osg::Group::traverse(*cv);
2321
2322    cv->setTraversalMask( traversalMask );
2323
2324    return;
2325}
2326
2327void ViewDependentShadowMap::cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const
2328{
2329    OSG_INFO<<"cullShadowCastingScene()"<<std::endl;
2330
2331    // record the traversal mask on entry so we can reapply it later.
2332    unsigned int traversalMask = cv->getTraversalMask();
2333
2334    cv->setTraversalMask( traversalMask & _shadowedScene->getShadowSettings()->getCastsShadowTraversalMask() );
2335
2336        if (camera) camera->accept(*cv);
2337
2338    cv->setTraversalMask( traversalMask );
2339
2340    return;
2341}
2342
2343osg::StateSet* ViewDependentShadowMap::selectStateSetForRenderingShadow(ViewDependentData& vdd) const
2344{
2345    OSG_INFO<<"   selectStateSetForRenderingShadow() "<<vdd.getStateSet()<<std::endl;
2346
2347    osg::ref_ptr<osg::StateSet> stateset = vdd.getStateSet();
2348
2349    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_accessUnfiromsAndProgramMutex);
2350
2351    vdd.getStateSet()->clear();
2352
2353    vdd.getStateSet()->setTextureAttributeAndModes(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON);
2354
2355    for(Uniforms::const_iterator itr=_uniforms.begin();
2356        itr!=_uniforms.end();
2357        ++itr)
2358    {
2359        OSG_INFO<<"addUniform("<<(*itr)->getName()<<")"<<std::endl;
2360        stateset->addUniform(itr->get());
2361    }
2362
2363    if (_program.valid())
2364    {
2365        stateset->setAttribute(_program.get());
2366    }
2367
2368    LightDataList& pll = vdd.getLightDataList();
2369    for(LightDataList::iterator itr = pll.begin();
2370        itr != pll.end();
2371        ++itr)
2372    {
2373        // 3. create per light/per shadow map division of lightspace/frustum
2374        //    create a list of light/shadow map data structures
2375
2376        LightData& pl = (**itr);
2377
2378        // if no texture units have been activated for this light then no shadow state required.
2379        if (pl.textureUnits.empty()) continue;
2380
2381        for(LightData::ActiveTextureUnits::iterator atu_itr = pl.textureUnits.begin();
2382            atu_itr != pl.textureUnits.end();
2383            ++atu_itr)
2384        {
2385            OSG_INFO<<"   Need to assign state for "<<*atu_itr<<std::endl;
2386        }
2387
2388    }
2389
2390    const ShadowSettings* settings = getShadowedScene()->getShadowSettings();
2391    unsigned int shadowMapModeValue = settings->getUseOverrideForShadowMapTexture() ?
2392                                            osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE :
2393                                            osg::StateAttribute::ON;
2394
2395
2396    ShadowDataList& sdl = vdd.getShadowDataList();
2397    for(ShadowDataList::iterator itr = sdl.begin();
2398        itr != sdl.end();
2399        ++itr)
2400    {
2401        // 3. create per light/per shadow map division of lightspace/frustum
2402        //    create a list of light/shadow map data structures
2403
2404        ShadowData& sd = (**itr);
2405
2406        OSG_INFO<<"   ShadowData for "<<sd._textureUnit<<std::endl;
2407
2408        stateset->setTextureAttributeAndModes(sd._textureUnit, sd._texture.get(), shadowMapModeValue);
2409
2410        stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
2411        stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
2412        stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
2413        stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON);
2414    }
2415
2416    return vdd.getStateSet();
2417}
2418
2419void ViewDependentShadowMap::resizeGLObjectBuffers(unsigned int /*maxSize*/)
2420{
2421    // the way that ViewDependentData is mapped shouldn't
2422}
2423
2424void ViewDependentShadowMap::releaseGLObjects(osg::State* state) const
2425{
2426    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_viewDependentDataMapMutex);
2427    for(ViewDependentDataMap::const_iterator itr = _viewDependentDataMap.begin();
2428        itr != _viewDependentDataMap.end();
2429        ++itr)
2430    {
2431        ViewDependentData* vdd = itr->second.get();
2432        if (vdd)
2433        {
2434            vdd->releaseGLObjects(state);
2435        }
2436    }
2437}
Note: See TracBrowser for help on using the browser.