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

Revision 13110, 85.8 kB (checked in by robert, 13 minutes ago)

From Mattias Helsing, "Seems I was only half right given what you asked for. CMP0017 only
says that modules that are found and ran from cmake modules dir should
prefer cmake-provided modules. find_package() and include() still look
in CMAKE_MODULE_PATH first.

After some investigating I've come up with a proposal examplified in
the attached FindGDAL.cmake script. It simply calls the cmake provided
FindGDAL.cmake if it exists and returns if it succeeds in finding GDAL
using that, otherwise continue with our local cmake code.
Pro: Wont clutter our root CMakeLists.txt
Con: If we begin to write more advanced Findxxx modules (using
COMPONENTS, REQUIRED etc.) we may have to revise this scheme.
"

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 += 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    cv->getRenderStage()->getPositionalStateContainer()->addPositionedTextureAttribute( textureUnit, refMatrix.get(), texgen );
2307
2308
2309    return true;
2310}
2311
2312void ViewDependentShadowMap::cullShadowReceivingScene(osgUtil::CullVisitor* cv) const
2313{
2314    OSG_INFO<<"cullShadowReceivingScene()"<<std::endl;
2315
2316    // record the traversal mask on entry so we can reapply it later.
2317    unsigned int traversalMask = cv->getTraversalMask();
2318
2319    cv->setTraversalMask( traversalMask & _shadowedScene->getShadowSettings()->getReceivesShadowTraversalMask() );
2320
2321    _shadowedScene->osg::Group::traverse(*cv);
2322
2323    cv->setTraversalMask( traversalMask );
2324
2325    return;
2326}
2327
2328void ViewDependentShadowMap::cullShadowCastingScene(osgUtil::CullVisitor* cv, osg::Camera* camera) const
2329{
2330    OSG_INFO<<"cullShadowCastingScene()"<<std::endl;
2331
2332    // record the traversal mask on entry so we can reapply it later.
2333    unsigned int traversalMask = cv->getTraversalMask();
2334
2335    cv->setTraversalMask( traversalMask & _shadowedScene->getShadowSettings()->getCastsShadowTraversalMask() );
2336
2337        if (camera) camera->accept(*cv);
2338
2339    cv->setTraversalMask( traversalMask );
2340
2341    return;
2342}
2343
2344osg::StateSet* ViewDependentShadowMap::selectStateSetForRenderingShadow(ViewDependentData& vdd) const
2345{
2346    OSG_INFO<<"   selectStateSetForRenderingShadow() "<<vdd.getStateSet()<<std::endl;
2347
2348    osg::ref_ptr<osg::StateSet> stateset = vdd.getStateSet();
2349
2350    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_accessUnfiromsAndProgramMutex);
2351   
2352    vdd.getStateSet()->clear();
2353
2354    vdd.getStateSet()->setTextureAttributeAndModes(0, _fallbackBaseTexture.get(), osg::StateAttribute::ON);
2355
2356    for(Uniforms::const_iterator itr=_uniforms.begin();
2357        itr!=_uniforms.end();
2358        ++itr)
2359    {
2360        OSG_INFO<<"addUniform("<<(*itr)->getName()<<")"<<std::endl;
2361        stateset->addUniform(itr->get());
2362    }
2363
2364    if (_program.valid())
2365    {
2366        stateset->setAttribute(_program.get());
2367    }
2368
2369    LightDataList& pll = vdd.getLightDataList();
2370    for(LightDataList::iterator itr = pll.begin();
2371        itr != pll.end();
2372        ++itr)
2373    {
2374        // 3. create per light/per shadow map division of lightspace/frustum
2375        //    create a list of light/shadow map data structures
2376
2377        LightData& pl = (**itr);
2378
2379        // if no texture units have been activated for this light then no shadow state required.
2380        if (pl.textureUnits.empty()) continue;
2381
2382        for(LightData::ActiveTextureUnits::iterator atu_itr = pl.textureUnits.begin();
2383            atu_itr != pl.textureUnits.end();
2384            ++atu_itr)
2385        {
2386            OSG_INFO<<"   Need to assign state for "<<*atu_itr<<std::endl;
2387        }
2388
2389    }
2390
2391    const ShadowSettings* settings = getShadowedScene()->getShadowSettings();
2392    unsigned int shadowMapModeValue = settings->getUseOverrideForShadowMapTexture() ?
2393                                            osg::StateAttribute::ON | osg::StateAttribute::OVERRIDE :
2394                                            osg::StateAttribute::ON;
2395
2396
2397    ShadowDataList& sdl = vdd.getShadowDataList();
2398    for(ShadowDataList::iterator itr = sdl.begin();
2399        itr != sdl.end();
2400        ++itr)
2401    {
2402        // 3. create per light/per shadow map division of lightspace/frustum
2403        //    create a list of light/shadow map data structures
2404
2405        ShadowData& sd = (**itr);
2406
2407        OSG_INFO<<"   ShadowData for "<<sd._textureUnit<<std::endl;
2408
2409        stateset->setTextureAttributeAndModes(sd._textureUnit, sd._texture.get(), shadowMapModeValue);
2410
2411        stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_S,osg::StateAttribute::ON);
2412        stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_T,osg::StateAttribute::ON);
2413        stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_R,osg::StateAttribute::ON);
2414        stateset->setTextureMode(sd._textureUnit,GL_TEXTURE_GEN_Q,osg::StateAttribute::ON);
2415    }
2416
2417    return vdd.getStateSet();
2418}
2419
2420void ViewDependentShadowMap::resizeGLObjectBuffers(unsigned int maxSize)
2421{
2422    // the way that ViewDependentData is mapped shouldn't
2423}
2424
2425void ViewDependentShadowMap::releaseGLObjects(osg::State* state) const
2426{
2427    OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_viewDependentDataMapMutex);
2428    for(ViewDependentDataMap::const_iterator itr = _viewDependentDataMap.begin();
2429        itr != _viewDependentDataMap.end();
2430        ++itr)
2431    {
2432        ViewDependentData* vdd = itr->second.get();
2433        if (vdd)
2434        {
2435            vdd->releaseGLObjects(state);
2436        }
2437    }
2438}
Note: See TracBrowser for help on using the browser.