root/OpenSceneGraph/trunk/src/osgShadow/MinimalCullBoundsShadowMap.cpp @ 13041

Revision 13041, 12.2 kB (checked in by robert, 3 years ago)

Ran script to remove trailing spaces and tabs

  • Property svn:eol-style set to native
Line 
1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 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 * ViewDependentShadow codes Copyright (C) 2008 Wojciech Lewandowski
14 * Thanks to to my company http://www.ai.com.pl for allowing me free this work.
15*/
16
17
18#include <osgShadow/MinimalCullBoundsShadowMap>
19#include <osgUtil/RenderLeaf>
20#include <string.h>
21
22#define IGNORE_OBJECTS_LARGER_THAN_HEIGHT 0
23
24using namespace osgShadow;
25
26MinimalCullBoundsShadowMap::MinimalCullBoundsShadowMap(): BaseClass()
27{
28}
29
30MinimalCullBoundsShadowMap::MinimalCullBoundsShadowMap
31(const MinimalCullBoundsShadowMap& copy, const osg::CopyOp& copyop) :
32    BaseClass(copy,copyop)
33{
34}
35
36MinimalCullBoundsShadowMap::~MinimalCullBoundsShadowMap()
37{
38}
39
40void MinimalCullBoundsShadowMap::ViewData::init
41    ( ThisClass *st, osgUtil::CullVisitor *cv )
42{
43    BaseClass::ViewData::init( st, cv );
44    _frameShadowCastingCameraPasses = 2;
45}
46
47void MinimalCullBoundsShadowMap::ViewData::aimShadowCastingCamera
48                                             ( const osg::Light *light,
49                                               const osg::Vec4 &lightPos,
50                                               const osg::Vec3 &lightDir,
51                                               const osg::Vec3 &lightUp )
52{
53    MinimalShadowMap::ViewData::aimShadowCastingCamera
54           ( light, lightPos, lightDir, lightUp );
55
56    frameShadowCastingCamera
57            ( _cv->getCurrentRenderBin()->getStage()->getCamera(), _camera.get() );
58}
59
60void MinimalCullBoundsShadowMap::ViewData::cullShadowReceivingScene( )
61{
62    RenderLeafList rllOld, rllNew;
63
64    GetRenderLeaves( _cv->getRenderStage(), rllOld );
65
66    MinimalShadowMap::ViewData::cullShadowReceivingScene( );
67
68    GetRenderLeaves( _cv->getRenderStage(), rllNew );
69
70    RemoveOldRenderLeaves( rllNew, rllOld );
71    RemoveIgnoredRenderLeaves( rllNew );
72
73    osg::Matrix projectionToModelSpace =
74        osg::Matrix::inverse( *_modellingSpaceToWorldPtr *
75            *_cv->getModelViewMatrix() * *_cv->getProjectionMatrix() );
76
77    osg::BoundingBox bb;
78    if( *_cv->getProjectionMatrix() != _clampedProjection ) {
79
80        osg::Polytope polytope;
81#if 1
82        polytope.setToUnitFrustum();
83#else
84        polytope.add( osg::Plane( 0.0,0.0,-1.0,1.0 ) ); // only far plane
85#endif
86        polytope.transformProvidingInverse( *_modellingSpaceToWorldPtr *
87                                  *_cv->getModelViewMatrix() * _clampedProjection );
88
89        bb = ComputeRenderLeavesBounds( rllNew, projectionToModelSpace, polytope );
90    } else {
91        bb = ComputeRenderLeavesBounds( rllNew, projectionToModelSpace );
92    }
93
94    cutScenePolytope( *_modellingSpaceToWorldPtr,
95                      osg::Matrix::inverse( *_modellingSpaceToWorldPtr ), bb );
96}
97
98void MinimalCullBoundsShadowMap::ViewData::GetRenderLeaves
99    ( osgUtil::RenderBin *rb, RenderLeafList & rll )
100{
101    osgUtil::RenderBin::RenderBinList& bins = rb->getRenderBinList();
102    osgUtil::RenderBin::RenderBinList::const_iterator rbitr;
103
104    // scan pre render bins
105    for(rbitr = bins.begin(); rbitr!=bins.end() && rbitr->first<0; ++rbitr )
106       GetRenderLeaves( rbitr->second.get(), rll );
107
108    // scan fine grained ordering.
109    osgUtil::RenderBin::RenderLeafList& renderLeafList = rb->getRenderLeafList();
110    osgUtil::RenderBin::RenderLeafList::const_iterator rlitr;
111    for( rlitr= renderLeafList.begin(); rlitr!= renderLeafList.end(); ++rlitr )
112    {
113        rll.push_back( *rlitr );
114    }
115
116    // scan coarse grained ordering.
117    osgUtil::RenderBin::StateGraphList& stateGraphList = rb->getStateGraphList();
118    osgUtil::RenderBin::StateGraphList::const_iterator oitr;
119    for( oitr= stateGraphList.begin(); oitr!= stateGraphList.end(); ++oitr )
120    {
121        for( osgUtil::StateGraph::LeafList::const_iterator dw_itr =
122            (*oitr)->_leaves.begin(); dw_itr != (*oitr)->_leaves.end(); ++dw_itr)
123        {
124            rll.push_back( dw_itr->get() );
125        }
126    }
127
128    // scan post render bins
129    for(; rbitr!=bins.end(); ++rbitr )
130       GetRenderLeaves( rbitr->second.get(), rll );
131}
132
133class CompareRenderLeavesByMatrices {
134public:
135  bool operator()( const osgUtil::RenderLeaf *a, const osgUtil::RenderLeaf *b )
136  {
137      if ( !a ) return false; // NULL render leaf goes last
138      return !b ||
139             a->_projection < b->_projection ||
140             (a->_projection == b->_projection && a->_modelview < b->_modelview);
141  }
142};
143
144inline bool CheckAndMultiplyBoxIfWithinPolytope
145    ( osg::BoundingBox & bb, osg::Matrix & m, osg::Polytope &p )
146{
147    if( !bb.valid() ) return false;
148
149    osg::Vec3 o = bb._min * m, s[3];
150
151    for( int i = 0; i < 3; i ++ )
152        s[i] = osg::Vec3( m(i,0), m(i,1), m(i,2) ) * ( bb._max[i] - bb._min[i] );
153
154    for( osg::Polytope::PlaneList::iterator it = p.getPlaneList().begin();
155         it != p.getPlaneList().end();
156         ++it )
157    {
158        float dist = it->distance( o ), dist_min = dist, dist_max = dist;
159
160        for( int i = 0; i < 3; i ++ ) {
161            dist = it->dotProductNormal( s[i] );
162            if( dist < 0 ) dist_min += dist; else dist_max += dist;
163        }
164
165        if( dist_max < 0 )
166            return false;
167    }
168
169    bb._max = bb._min = o;
170#if 1
171    for( int i = 0; i < 3; i ++ )
172        for( int j = 0; j < 3; j ++ )
173            if( s[i][j] < 0 ) bb._min[j] += s[i][j]; else bb._max[j] += s[i][j];
174#else
175    b.expandBy( o + s[0] );
176    b.expandBy( o + s[1] );
177    b.expandBy( o + s[2] );
178    b.expandBy( o + s[0] + s[1] );
179    b.expandBy( o + s[0] + s[2] );
180    b.expandBy( o + s[1] + s[2] );
181    b.expandBy( o + s[0] + s[1] + s[2] );
182#endif
183
184#if ( IGNORE_OBJECTS_LARGER_THAN_HEIGHT > 0 )
185   if( bb._max[2] - bb._min[2] > IGNORE_OBJECTS_LARGER_THAN_HEIGHT ) // ignore huge objects
186       return false;
187#endif
188
189    return true;
190}
191
192unsigned MinimalCullBoundsShadowMap::ViewData::RemoveOldRenderLeaves
193    ( RenderLeafList &rllNew, RenderLeafList &rllOld )
194{
195    unsigned count = 0;
196
197    std::sort( rllOld.begin(), rllOld.end() );
198    RenderLeafList::iterator itNew, itOld;
199    for( itNew = rllNew.begin(); itNew != rllNew.end() && rllOld.size(); ++itNew )
200    {
201        itOld = std::lower_bound( rllOld.begin(), rllOld.end(), *itNew );
202
203        if( itOld == rllOld.end() || *itOld != *itNew ) continue;
204        // found !
205        rllOld.erase( itOld ); //remove it from old range to speed up search
206        *itNew = NULL; //its not new = invalidate it among new render leaves
207        count ++;
208    }
209
210    return count;
211}
212
213unsigned MinimalCullBoundsShadowMap::ViewData::RemoveIgnoredRenderLeaves
214    ( RenderLeafList &rll )
215{
216    unsigned count = 0;
217
218    for( RenderLeafList::iterator it = rll.begin(); it != rll.end(); ++it )
219    {
220        if( !*it ) continue;
221
222        const char * name = (*it)->_drawable->className();
223
224        // Its a dirty but quick test (not very future proof)
225        if( !name || name[0] != 'L' ) continue;
226
227        if( !strcmp( name, "LightPointDrawable" ) ||
228            !strcmp( name, "LightPointSpriteDrawable" ) )
229        {
230            *it = NULL; //ignored = invalidate this in new render leaves list
231            count++;
232        }
233    }
234
235    return count;
236}
237
238osg::BoundingBox MinimalCullBoundsShadowMap::ViewData::ComputeRenderLeavesBounds
239    ( RenderLeafList &rll, osg::Matrix & projectionToWorld )
240{
241    osg::BoundingBox bbResult;
242
243    if( rll.size() == 0 ) return bbResult;
244
245    std::sort( rll.begin(), rll.end(), CompareRenderLeavesByMatrices() );
246
247    osg::ref_ptr< osg::RefMatrix > modelview;
248    osg::ref_ptr< osg::RefMatrix > projection;
249    osg::Matrix viewToWorld, modelToWorld, *ptrProjection = NULL,
250                *ptrViewToWorld = &projectionToWorld, *ptrModelToWorld;
251
252    osg::BoundingBox bb;
253
254    // compute bounding boxes but skip old ones (placed at the end as NULLs)
255    for( RenderLeafList::iterator it = rll.begin(); ; ++it ) {
256        // we actually allow to pass one element behind end to flush bb queue
257        osgUtil::RenderLeaf *rl = ( it != rll.end() ? *it : NULL );
258
259        // Don't trust already computed bounds for cull generated drawables
260        // LightPointDrawable & LightPointSpriteDrawable are such examples
261        // they store wrong recorded bounds from very first pass
262        if( rl && rl->_modelview == NULL )
263            rl->_drawable->dirtyBound();
264
265        // Stay as long as possible in model space to minimize matrix ops
266        if( rl && rl->_modelview == modelview && rl->_projection == projection ){
267            bb.expandBy( rl->_drawable->getBound() );
268        } else {
269            if( bb.valid() ) {
270                // Conditions to avoid matrix multiplications
271                if( projection.valid() )
272                {
273                    if( projection.get() != ptrProjection )
274                    {
275                        ptrProjection = projection.get();
276                        viewToWorld = *ptrProjection * projectionToWorld;
277                    }
278                    ptrViewToWorld = &viewToWorld;
279                } else {
280                    ptrViewToWorld = &projectionToWorld;
281                }
282
283                if( modelview.valid() )
284                {
285                    modelToWorld = *modelview.get() * *ptrViewToWorld;
286                    ptrModelToWorld = &modelToWorld;
287                } else {
288                    ptrModelToWorld = ptrViewToWorld;
289                }
290
291                for( int i = 0; i < 8; i++ )
292                    bbResult.expandBy( bb.corner( i ) * *ptrModelToWorld );
293            }
294            if( !rl ) break;
295            bb = rl->_drawable->getBound();
296            modelview = rl->_modelview;
297            projection = rl->_projection;
298        }
299    }
300
301    rll.clear();
302
303    return bbResult;
304}
305
306osg::BoundingBox MinimalCullBoundsShadowMap::ViewData::ComputeRenderLeavesBounds
307    ( RenderLeafList &rll, osg::Matrix & projectionToWorld, osg::Polytope & p )
308{
309    osg::BoundingBox bbResult, bb;
310
311    if( rll.size() == 0 ) return bbResult;
312
313    std::sort( rll.begin(), rll.end(), CompareRenderLeavesByMatrices() );
314
315    osg::ref_ptr< osg::RefMatrix > modelview;
316    osg::ref_ptr< osg::RefMatrix > projection;
317    osg::Matrix viewToWorld, modelToWorld,
318                *ptrProjection = NULL,
319                *ptrViewToWorld = &projectionToWorld,
320                *ptrModelToWorld = NULL;
321
322    // compute bounding boxes but skip old ones (placed at the end as NULLs)
323    for( RenderLeafList::iterator it = rll.begin(); it != rll.end(); ++it ) {
324        // we actually allow to pass one element behind end to flush bb queue
325        osgUtil::RenderLeaf *rl = *it;
326        if( !rl ) break;
327
328        // Don't trust already computed bounds for cull generated drawables
329        // LightPointDrawable & LightPointSpriteDrawable are such examples
330        // they store wrong recorded bounds from very first pass
331        if(rl->_modelview == NULL )
332            rl->_drawable->dirtyBound();
333
334        bb = rl->_drawable->getBound();
335        if( !bb.valid() ) continue;
336
337        // Stay as long as possible in model space to minimize matrix ops
338        if( rl->_modelview != modelview || rl->_projection != projection ) {
339
340            projection = rl->_projection;
341            if( projection.valid() )
342            {
343               if( projection.get() != ptrProjection )
344               {
345                   ptrProjection = projection.get();
346                   viewToWorld = *ptrProjection * projectionToWorld;
347               }
348               ptrViewToWorld = &viewToWorld;
349            } else {
350               ptrViewToWorld = &projectionToWorld;
351            }
352
353            modelview = rl->_modelview;
354            if( modelview.valid() )
355            {
356                modelToWorld = *modelview.get() * *ptrViewToWorld;
357                ptrModelToWorld = &modelToWorld;
358            } else {
359                ptrModelToWorld = ptrViewToWorld;
360            }
361        }
362
363        if( CheckAndMultiplyBoxIfWithinPolytope( bb, *ptrModelToWorld, p ) )
364            bbResult.expandBy( bb );
365    }
366
367    rll.clear();
368
369    return bbResult;
370}
Note: See TracBrowser for help on using the browser.