root/OpenSceneGraph/trunk/src/osgUtil/CullVisitor.cpp @ 11127

Revision 11127, 45.7 kB (checked in by robert, 3 years ago)

From Paul Martz, "The changes are very similar to Magne's, except they now take the near plane into account. The changes are:

  • Change OcclusionQueryNode::getPassed to take a NodeVisitor? rather than the distance from BS center to the eye point. Change where CullVisitor? calls this method to use the new parameters.
  • getPassed now exits early and returns true to avoid blinking / blink-in of geometry for the first frame or for out-of-range LOD children coming back into view.
  • getPassed now considers the distance from the near plane to the bounding sphere (rather than eye point to bounding sphere) when determining if the viewer is "inside" the bounding sphere or not."
  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
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#include <osg/Transform>
14#include <osg/Projection>
15#include <osg/Geode>
16#include <osg/LOD>
17#include <osg/Billboard>
18#include <osg/LightSource>
19#include <osg/ClipNode>
20#include <osg/TexGenNode>
21#include <osg/OccluderNode>
22#include <osg/OcclusionQueryNode>
23#include <osg/Notify>
24#include <osg/TexEnv>
25#include <osg/AlphaFunc>
26#include <osg/LineSegment>
27#include <osg/TriangleFunctor>
28#include <osg/Geometry>
29#include <osg/io_utils>
30
31#include <osgUtil/CullVisitor>
32
33#include <float.h>
34#include <algorithm>
35
36#include <osg/Timer>
37
38using namespace osg;
39using namespace osgUtil;
40
41inline float MAX_F(float a, float b)
42    { return a>b?a:b; }
43inline int EQUAL_F(float a, float b)
44    { return a == b || fabsf(a-b) <= MAX_F(fabsf(a),fabsf(b))*1e-3f; }
45
46
47CullVisitor::CullVisitor():
48    NodeVisitor(CULL_VISITOR,TRAVERSE_ACTIVE_CHILDREN),
49    _currentStateGraph(NULL),
50    _currentRenderBin(NULL),
51    _computed_znear(FLT_MAX),
52    _computed_zfar(-FLT_MAX),
53    _currentReuseRenderLeafIndex(0),
54    _numberOfEncloseOverrideRenderBinDetails(0)
55{
56}
57
58CullVisitor::CullVisitor(const CullVisitor& rhs):
59    NodeVisitor(rhs),
60    CullStack(rhs),
61    _currentStateGraph(NULL),
62    _currentRenderBin(NULL),
63    _computed_znear(FLT_MAX),
64    _computed_zfar(-FLT_MAX),
65    _currentReuseRenderLeafIndex(0),
66    _numberOfEncloseOverrideRenderBinDetails(0)
67{
68}
69
70CullVisitor::~CullVisitor()
71{
72    reset();
73}
74
75osg::ref_ptr<CullVisitor>& CullVisitor::prototype()
76{
77    static osg::ref_ptr<CullVisitor> s_CullVisitor = new CullVisitor;
78    return s_CullVisitor;
79}
80
81CullVisitor* CullVisitor::create()
82{
83    return CullVisitor::prototype().valid() ?
84           CullVisitor::prototype()->clone() :
85           new CullVisitor;
86}
87
88
89void CullVisitor::reset()
90{
91    //
92    // first unref all referenced objects and then empty the containers.
93    //
94   
95    CullStack::reset();
96   
97    _renderBinStack.clear();
98
99    _numberOfEncloseOverrideRenderBinDetails = 0;
100
101    // reset the traversal number
102    _traversalNumber = 0;
103
104    // reset the calculated near far planes.
105    _computed_znear = FLT_MAX;
106    _computed_zfar = -FLT_MAX;
107   
108   
109    osg::Vec3 lookVector(0.0,0.0,-1.0);
110   
111    _bbCornerFar = (lookVector.x()>=0?1:0) |
112                   (lookVector.y()>=0?2:0) |
113                   (lookVector.z()>=0?4:0);
114
115    _bbCornerNear = (~_bbCornerFar)&7;
116   
117    // Only reset the RenderLeaf objects used last frame.
118    for(RenderLeafList::iterator itr=_reuseRenderLeafList.begin(),
119        iter_end=_reuseRenderLeafList.begin()+_currentReuseRenderLeafIndex;
120        itr!=iter_end;
121        ++itr)
122    {
123        (*itr)->reset();
124    }
125   
126    // reset the resuse lists.
127    _currentReuseRenderLeafIndex = 0;
128
129    _nearPlaneCandidateMap.clear();
130}
131
132float CullVisitor::getDistanceToEyePoint(const Vec3& pos, bool withLODScale) const
133{
134    if (withLODScale) return (pos-getEyeLocal()).length()*getLODScale();
135    else return (pos-getEyeLocal()).length();
136}
137
138float CullVisitor::getDistanceToViewPoint(const Vec3& pos, bool withLODScale) const
139{
140    if (withLODScale) return (pos-getViewPointLocal()).length()*getLODScale();
141    else return (pos-getViewPointLocal()).length();
142}
143
144inline CullVisitor::value_type distance(const osg::Vec3& coord,const osg::Matrix& matrix)
145{
146    return -((CullVisitor::value_type)coord[0]*(CullVisitor::value_type)matrix(0,2)+(CullVisitor::value_type)coord[1]*(CullVisitor::value_type)matrix(1,2)+(CullVisitor::value_type)coord[2]*(CullVisitor::value_type)matrix(2,2)+matrix(3,2));
147}
148
149float CullVisitor::getDistanceFromEyePoint(const osg::Vec3& pos, bool withLODScale) const
150{
151    const Matrix& matrix = *_modelviewStack.back();
152    float dist = distance(pos,matrix);
153   
154    if (withLODScale) return dist*getLODScale();
155    else return dist;
156}
157
158void CullVisitor::computeNearPlane()
159{
160    if (!_nearPlaneCandidateMap.empty())
161    {
162   
163        // osg::Timer_t start_t = osg::Timer::instance()->tick();
164       
165        // update near from defferred list of drawables
166        unsigned int numTests = 0;
167        for(DistanceMatrixDrawableMap::iterator itr=_nearPlaneCandidateMap.begin();
168            itr!=_nearPlaneCandidateMap.end() && itr->first<_computed_znear;
169            ++itr)
170        {
171            ++numTests;
172            // OSG_NOTIFY(osg::WARN)<<"testing computeNearestPointInFrustum with d_near = "<<itr->first<<std::endl;
173            value_type d_near = computeNearestPointInFrustum(itr->second._matrix, itr->second._planes,*(itr->second._drawable));
174            if (d_near<_computed_znear)
175            {
176                _computed_znear = d_near;
177                // OSG_NOTIFY(osg::WARN)<<"updating znear to "<<_computed_znear<<std::endl;
178            }
179        }
180
181        // osg::Timer_t end_t = osg::Timer::instance()->tick();
182        // OSG_NOTIFY(osg::NOTICE)<<"Took "<<osg::Timer::instance()->delta_m(start_t,end_t)<<"ms to test "<<numTests<<" out of "<<_nearPlaneCandidateMap.size()<<std::endl;
183
184        _nearPlaneCandidateMap.clear();
185    }
186}
187
188void CullVisitor::popProjectionMatrix()
189{
190    computeNearPlane();
191
192    if (_computeNearFar && _computed_zfar>=_computed_znear)
193    {
194
195        //OSG_NOTIFY(osg::INFO)<<"clamping "<< "znear="<<_computed_znear << " zfar="<<_computed_zfar<<std::endl;
196
197
198        // adjust the projection matrix so that it encompases the local coords.
199        // so it doesn't cull them out.
200        osg::Matrix& projection = *_projectionStack.back();
201       
202        value_type tmp_znear = _computed_znear;
203        value_type tmp_zfar = _computed_zfar;
204       
205        clampProjectionMatrix(projection, tmp_znear, tmp_zfar);
206    }
207    else
208    {
209        //OSG_NOTIFY(osg::INFO)<<"Not clamping "<< "znear="<<_computed_znear << " zfar="<<_computed_zfar<<std::endl;
210    }
211
212    CullStack::popProjectionMatrix();
213}
214
215template<class matrix_type, class value_type>
216bool _clampProjectionMatrix(matrix_type& projection, double& znear, double& zfar, value_type nearFarRatio)
217{
218    double epsilon = 1e-6;
219    if (zfar<znear-epsilon)
220    {
221        OSG_NOTIFY(osg::INFO)<<"_clampProjectionMatrix not applied, invalid depth range, znear = "<<znear<<"  zfar = "<<zfar<<std::endl;
222        return false;
223    }
224   
225    if (zfar<znear+epsilon)
226    {
227        // znear and zfar are too close together and could cause divide by zero problems
228        // late on in the clamping code, so move the znear and zfar apart.
229        double average = (znear+zfar)*0.5;
230        znear = average-epsilon;
231        zfar = average+epsilon;
232        // OSG_NOTIFY(osg::INFO) << "_clampProjectionMatrix widening znear and zfar to "<<znear<<" "<<zfar<<std::endl;
233    }
234
235    if (fabs(projection(0,3))<epsilon  && fabs(projection(1,3))<epsilon  && fabs(projection(2,3))<epsilon )
236    {
237        // OSG_NOTIFY(osg::INFO) << "Orthographic matrix before clamping"<<projection<<std::endl;
238
239        value_type delta_span = (zfar-znear)*0.02;
240        if (delta_span<1.0) delta_span = 1.0;
241        value_type desired_znear = znear - delta_span;
242        value_type desired_zfar = zfar + delta_span;
243
244        // assign the clamped values back to the computed values.
245        znear = desired_znear;
246        zfar = desired_zfar;
247
248        projection(2,2)=-2.0f/(desired_zfar-desired_znear);
249        projection(3,2)=-(desired_zfar+desired_znear)/(desired_zfar-desired_znear);
250
251        // OSG_NOTIFY(osg::INFO) << "Orthographic matrix after clamping "<<projection<<std::endl;
252    }
253    else
254    {
255
256        // OSG_NOTIFY(osg::INFO) << "Persepective matrix before clamping"<<projection<<std::endl;
257
258        //std::cout << "_computed_znear"<<_computed_znear<<std::endl;
259        //std::cout << "_computed_zfar"<<_computed_zfar<<std::endl;
260
261        value_type zfarPushRatio = 1.02;
262        value_type znearPullRatio = 0.98;
263
264        //znearPullRatio = 0.99;
265
266        value_type desired_znear = znear * znearPullRatio;
267        value_type desired_zfar = zfar * zfarPushRatio;
268
269        // near plane clamping.
270        double min_near_plane = zfar*nearFarRatio;
271        if (desired_znear<min_near_plane) desired_znear=min_near_plane;
272
273        // assign the clamped values back to the computed values.
274        znear = desired_znear;
275        zfar = desired_zfar;
276
277        value_type trans_near_plane = (-desired_znear*projection(2,2)+projection(3,2))/(-desired_znear*projection(2,3)+projection(3,3));
278        value_type trans_far_plane = (-desired_zfar*projection(2,2)+projection(3,2))/(-desired_zfar*projection(2,3)+projection(3,3));
279
280        value_type ratio = fabs(2.0/(trans_near_plane-trans_far_plane));
281        value_type center = -(trans_near_plane+trans_far_plane)/2.0;
282
283        projection.postMult(osg::Matrix(1.0f,0.0f,0.0f,0.0f,
284                                        0.0f,1.0f,0.0f,0.0f,
285                                        0.0f,0.0f,ratio,0.0f,
286                                        0.0f,0.0f,center*ratio,1.0f));
287
288        // OSG_NOTIFY(osg::INFO) << "Persepective matrix after clamping"<<projection<<std::endl;
289    }
290    return true;
291}
292
293
294bool CullVisitor::clampProjectionMatrixImplementation(osg::Matrixf& projection, double& znear, double& zfar) const
295{
296    return _clampProjectionMatrix( projection, znear, zfar, _nearFarRatio );
297}
298
299bool CullVisitor::clampProjectionMatrixImplementation(osg::Matrixd& projection, double& znear, double& zfar) const
300{
301    return _clampProjectionMatrix( projection, znear, zfar, _nearFarRatio );
302}
303
304struct ComputeNearestPointFunctor
305{
306
307    ComputeNearestPointFunctor():
308        _planes(0) {}
309
310    void set(CullVisitor::value_type znear, const osg::Matrix& matrix, const osg::Polytope::PlaneList* planes)
311    {
312        _znear = znear;
313        _matrix = matrix;
314        _planes = planes;
315    }
316
317    typedef std::pair<float, osg::Vec3>  DistancePoint;
318    typedef std::vector<DistancePoint>  Polygon;
319
320    CullVisitor::value_type         _znear;
321    osg::Matrix                     _matrix;
322    const osg::Polytope::PlaneList* _planes;
323    Polygon                         _polygonOriginal;
324    Polygon                         _polygonNew;
325   
326    Polygon                         _pointCache;
327
328    inline void operator() ( const osg::Vec3 &v1, const osg::Vec3 &v2, const osg::Vec3 &v3, bool)
329    {
330        CullVisitor::value_type n1 = distance(v1,_matrix);
331        CullVisitor::value_type n2 = distance(v2,_matrix);
332        CullVisitor::value_type n3 = distance(v3,_matrix);
333
334        // check if triangle is total behind znear, if so disguard
335        if (n1 >= _znear &&
336            n2 >= _znear &&
337            n3 >= _znear)
338        {
339            //OSG_NOTIFY(osg::NOTICE)<<"Triangle totally beyond znear"<<std::endl;
340            return;
341        }
342     
343       
344        if (n1 < 0.0 &&
345            n2 < 0.0 &&
346            n3 < 0.0)
347        {
348            // OSG_NOTIFY(osg::NOTICE)<<"Triangle totally behind eye point"<<std::endl;
349            return;
350        }
351
352        // check which planes the points
353        osg::Polytope::ClippingMask selector_mask = 0x1;
354        osg::Polytope::ClippingMask active_mask = 0x0;
355
356        osg::Polytope::PlaneList::const_iterator pitr;
357        for(pitr = _planes->begin();
358            pitr != _planes->end();
359            ++pitr)
360        {
361            const osg::Plane& plane = *pitr;
362            float d1 = plane.distance(v1);
363            float d2 = plane.distance(v2);
364            float d3 = plane.distance(v3);
365
366            unsigned int numOutside = ((d1<0.0)?1:0) + ((d2<0.0)?1:0) + ((d3<0.0)?1:0);
367            if (numOutside==3)
368            {
369                //OSG_NOTIFY(osg::NOTICE)<<"Triangle totally outside frustum "<<d1<<"\t"<<d2<<"\t"<<d3<<std::endl;
370                return;
371            }
372            unsigned int numInside = ((d1>=0.0)?1:0) + ((d2>=0.0)?1:0) + ((d3>=0.0)?1:0);
373            if (numInside<3)
374            {
375                active_mask = active_mask | selector_mask;
376            }
377           
378            //OSG_NOTIFY(osg::NOTICE)<<"Triangle ok w.r.t plane "<<d1<<"\t"<<d2<<"\t"<<d3<<std::endl;
379
380            selector_mask <<= 1;
381        }       
382   
383        if (active_mask==0)
384        {
385            _znear = osg::minimum(_znear,n1);
386            _znear = osg::minimum(_znear,n2);
387            _znear = osg::minimum(_znear,n3);
388            // OSG_NOTIFY(osg::NOTICE)<<"Triangle all inside frustum "<<n1<<"\t"<<n2<<"\t"<<n3<<" number of plane="<<_planes->size()<<std::endl;
389            return;
390        }
391       
392        //return;
393   
394        // numPartiallyInside>0) so we have a triangle cutting an frustum wall,
395        // this means that use brute force methods for deviding up triangle.
396       
397        //OSG_NOTIFY(osg::NOTICE)<<"Using brute force method of triangle cutting frustum walls"<<std::endl;
398        _polygonOriginal.clear();
399        _polygonOriginal.push_back(DistancePoint(0,v1));
400        _polygonOriginal.push_back(DistancePoint(0,v2));
401        _polygonOriginal.push_back(DistancePoint(0,v3));
402       
403        selector_mask = 0x1;
404       
405
406        for(pitr = _planes->begin();
407            pitr != _planes->end() && !_polygonOriginal.empty();
408            ++pitr)
409        {
410            if (active_mask & selector_mask)
411            {   
412                // polygon bisects plane so need to divide it up.
413                const osg::Plane& plane = *pitr;
414                _polygonNew.clear();
415
416                // assign the distance from the current plane.
417                for(Polygon::iterator polyItr = _polygonOriginal.begin();
418                    polyItr != _polygonOriginal.end();
419                    ++polyItr)
420                {
421                    polyItr->first = plane.distance(polyItr->second);
422                }
423               
424                // create the new polygon by clamping against the
425                unsigned int psize = _polygonOriginal.size();
426
427                for(unsigned int ci = 0; ci < psize; ++ci)
428                {
429                    unsigned int ni = (ci+1)%psize;
430                    bool computeIntersection = false;
431                    if (_polygonOriginal[ci].first>=0.0f)
432                    {
433                        _polygonNew.push_back(_polygonOriginal[ci]);
434                       
435                        if (_polygonOriginal[ni].first<0.0f) computeIntersection = true;
436                    }
437                    else if (_polygonOriginal[ni].first>0.0f) computeIntersection = true;
438
439
440                    if (computeIntersection)
441                    {
442                        // segment intersects with the plane, compute new position.
443                        float r = _polygonOriginal[ci].first/(_polygonOriginal[ci].first-_polygonOriginal[ni].first);
444                        _polygonNew.push_back(DistancePoint(0.0f,_polygonOriginal[ci].second*(1.0f-r) + _polygonOriginal[ni].second*r));
445                    }
446                }
447                _polygonOriginal.swap(_polygonNew);
448            }
449            selector_mask <<= 1;
450        }
451
452        // now take the nearst points to the eye point.
453        for(Polygon::iterator polyItr = _polygonOriginal.begin();
454            polyItr != _polygonOriginal.end();
455            ++polyItr)
456        {
457            CullVisitor::value_type dist = distance(polyItr->second,_matrix);
458            if (dist < _znear)
459            {
460                _znear = dist;
461                //OSG_NOTIFY(osg::NOTICE)<<"Near plane updated "<<_znear<<std::endl;
462            }
463        }
464    }
465};
466
467CullVisitor::value_type CullVisitor::computeNearestPointInFrustum(const osg::Matrix& matrix, const osg::Polytope::PlaneList& planes,const osg::Drawable& drawable)
468{
469    // OSG_NOTIFY(osg::WARN)<<"CullVisitor::computeNearestPointInFrustum("<<getTraversalNumber()<<"\t"<<planes.size()<<std::endl;
470
471    osg::TriangleFunctor<ComputeNearestPointFunctor> cnpf;
472    cnpf.set(_computed_znear, matrix, &planes);
473   
474    drawable.accept(cnpf);
475
476    return cnpf._znear;
477}
478
479bool CullVisitor::updateCalculatedNearFar(const osg::Matrix& matrix,const osg::BoundingBox& bb)
480{
481    // efficient computation of near and far, only taking into account the nearest and furthest
482    // corners of the bounding box.
483    value_type d_near = distance(bb.corner(_bbCornerNear),matrix);
484    value_type d_far = distance(bb.corner(_bbCornerFar),matrix);
485
486    if (d_near>d_far)
487    {
488        std::swap(d_near,d_far);
489        if ( !EQUAL_F(d_near, d_far) )
490        {
491            OSG_NOTIFY(osg::WARN)<<"Warning: CullVisitor::updateCalculatedNearFar(.) near>far in range calculation,"<< std::endl;
492            OSG_NOTIFY(osg::WARN)<<"         correcting by swapping values d_near="<<d_near<<" dfar="<<d_far<< std::endl;
493        }
494    }
495
496    if (d_far<0.0)
497    {
498        // whole object behind the eye point so disguard
499        return false;
500    }
501
502    if (d_near<_computed_znear) _computed_znear = d_near;
503    if (d_far>_computed_zfar) _computed_zfar = d_far;
504
505    return true;
506}
507
508bool CullVisitor::updateCalculatedNearFar(const osg::Matrix& matrix,const osg::Drawable& drawable, bool isBillboard)
509{
510    const osg::BoundingBox& bb = drawable.getBound();
511
512    value_type d_near, d_far;
513
514    if (isBillboard)
515    {
516   
517#ifdef TIME_BILLBOARD_NEAR_FAR_CALCULATION   
518        static unsigned int lastFrameNumber = getTraversalNumber();
519        static unsigned int numBillboards = 0;
520        static double elapsed_time = 0.0;
521        if (lastFrameNumber != getTraversalNumber())
522        {
523            OSG_NOTIFY(osg::NOTICE)<<"Took "<<elapsed_time<<"ms to test "<<numBillboards<<" billboards"<<std::endl;
524            numBillboards = 0;
525            elapsed_time = 0.0;
526            lastFrameNumber = getTraversalNumber();
527        }
528        osg::Timer_t start_t = osg::Timer::instance()->tick();
529#endif
530       
531        osg::Vec3 lookVector(-matrix(0,2),-matrix(1,2),-matrix(2,2));
532
533        unsigned int bbCornerFar = (lookVector.x()>=0?1:0) +
534                       (lookVector.y()>=0?2:0) +
535                       (lookVector.z()>=0?4:0);
536
537        unsigned int bbCornerNear = (~bbCornerFar)&7;
538
539        d_near = distance(bb.corner(bbCornerNear),matrix);
540        d_far = distance(bb.corner(bbCornerFar),matrix);
541
542        OSG_NOTIFY(osg::NOTICE).precision(15);
543
544        if (false)
545        {
546
547            OSG_NOTIFY(osg::NOTICE)<<"TESTING Billboard near/far computation"<<std::endl;
548
549             // OSG_NOTIFY(osg::WARN)<<"Checking corners of billboard "<<std::endl;
550            // deprecated brute force way, use all corners of the bounding box.
551            value_type nd_near, nd_far;
552            nd_near = nd_far = distance(bb.corner(0),matrix);
553            for(unsigned int i=0;i<8;++i)
554            {
555                value_type d = distance(bb.corner(i),matrix);
556                if (d<nd_near) nd_near = d;
557                if (d>nd_far) nd_far = d;
558                OSG_NOTIFY(osg::NOTICE)<<"\ti="<<i<<"\td="<<d<<std::endl;
559            }
560
561            if (nd_near==d_near && nd_far==d_far)
562            {
563                OSG_NOTIFY(osg::NOTICE)<<"\tBillboard near/far computation correct "<<std::endl;
564            }
565            else
566            {
567                OSG_NOTIFY(osg::NOTICE)<<"\tBillboard near/far computation ERROR\n\t\t"<<d_near<<"\t"<<nd_near
568                                        <<"\n\t\t"<<d_far<<"\t"<<nd_far<<std::endl;
569            }
570
571        }
572
573#ifdef TIME_BILLBOARD_NEAR_FAR_CALCULATION   
574        osg::Timer_t end_t = osg::Timer::instance()->tick();
575       
576        elapsed_time += osg::Timer::instance()->delta_m(start_t,end_t);
577        ++numBillboards;
578#endif
579    }
580    else
581    {
582        // efficient computation of near and far, only taking into account the nearest and furthest
583        // corners of the bounding box.
584        d_near = distance(bb.corner(_bbCornerNear),matrix);
585        d_far = distance(bb.corner(_bbCornerFar),matrix);
586    }
587   
588    if (d_near>d_far)
589    {
590        std::swap(d_near,d_far);
591        if ( !EQUAL_F(d_near, d_far) )
592        {
593            OSG_NOTIFY(osg::WARN)<<"Warning: CullVisitor::updateCalculatedNearFar(.) near>far in range calculation,"<< std::endl;
594            OSG_NOTIFY(osg::WARN)<<"         correcting by swapping values d_near="<<d_near<<" dfar="<<d_far<< std::endl;
595        }
596    }
597
598    if (d_far<0.0)
599    {
600        // whole object behind the eye point so discard
601        return false;
602    }
603
604    if (d_near<_computed_znear)
605    {
606        if (_computeNearFar==COMPUTE_NEAR_FAR_USING_PRIMITIVES)
607        {
608            osg::Polytope& frustum = getCurrentCullingSet().getFrustum();
609            if (frustum.getResultMask())
610            {
611                if (isBillboard)
612                {
613                    // OSG_NOTIFY(osg::WARN)<<"Adding billboard into deffered list"<<std::endl;
614               
615                    osg::Polytope transformed_frustum;
616                    transformed_frustum.setAndTransformProvidingInverse(getProjectionCullingStack().back().getFrustum(),matrix);
617               
618                    // insert drawable into the deferred list of drawables which will be handled at the popProjectionMatrix().
619                    _nearPlaneCandidateMap.insert(
620                        DistanceMatrixDrawableMap::value_type(d_near,MatrixPlanesDrawables(matrix,&drawable,transformed_frustum)) );
621                }
622                else
623                {
624                    // insert drawable into the deferred list of drawables which will be handled at the popProjectionMatrix().
625                    _nearPlaneCandidateMap.insert(
626                        DistanceMatrixDrawableMap::value_type(d_near,MatrixPlanesDrawables(matrix,&drawable,frustum)) );
627                }
628
629                // use the far point if its nearer than current znear as this is a conservative estimate of the znear
630                // while the final computation for this drawable is deferred.
631                if (d_far<_computed_znear)
632                {
633                    if (d_far>=0.0) _computed_znear = d_far;
634                    else OSG_NOTIFY(osg::WARN)<<"       1)  sett near with dnear="<<d_near<<"  dfar="<<d_far<< std::endl;
635                }
636            }
637            else
638            {
639                if (d_near>=0.0) _computed_znear = d_near;
640                else OSG_NOTIFY(osg::WARN)<<"        2) sett near with d_near="<<d_near<< std::endl;
641            }
642        }
643        else
644        {
645            //if (d_near<0.0) OSG_NOTIFY(osg::WARN)<<"         3) set near with d_near="<<d_near<< std::endl;
646            _computed_znear = d_near;
647        }
648    }
649
650    if (d_far>_computed_zfar) _computed_zfar = d_far;
651
652
653/*
654    // deprecated brute force way, use all corners of the bounding box.
655    updateCalculatedNearFar(bb.corner(0));
656    updateCalculatedNearFar(bb.corner(1));
657    updateCalculatedNearFar(bb.corner(2));
658    updateCalculatedNearFar(bb.corner(3));
659    updateCalculatedNearFar(bb.corner(4));
660    updateCalculatedNearFar(bb.corner(5));
661    updateCalculatedNearFar(bb.corner(6));
662    updateCalculatedNearFar(bb.corner(7));
663*/
664
665    return true;
666
667}
668void CullVisitor::updateCalculatedNearFar(const osg::Vec3& pos)
669{
670    float d;
671    if (!_modelviewStack.empty())
672    {
673        const osg::Matrix& matrix = *(_modelviewStack.back());
674        d = distance(pos,matrix);
675    }
676    else
677    {
678        d = -pos.z();
679    }
680
681    if (d<_computed_znear)
682    {
683       _computed_znear = d;
684       if (d<0.0) OSG_NOTIFY(osg::WARN)<<"Alerting billboard ="<<d<< std::endl;
685    }
686    if (d>_computed_zfar) _computed_zfar = d;
687}   
688
689void CullVisitor::apply(Node& node)
690{
691    if (isCulled(node)) return;
692
693    // push the culling mode.
694    pushCurrentMask();
695   
696    // push the node's state.
697    StateSet* node_state = node.getStateSet();
698    if (node_state) pushStateSet(node_state);
699
700    handle_cull_callbacks_and_traverse(node);
701
702    // pop the node's state off the geostate stack.   
703    if (node_state) popStateSet();
704   
705    // pop the culling mode.
706    popCurrentMask();
707}
708
709
710void CullVisitor::apply(Geode& node)
711{
712    if (isCulled(node)) return;
713
714    // push the node's state.
715    StateSet* node_state = node.getStateSet();
716    if (node_state) pushStateSet(node_state);
717
718    // traverse any call callbacks and traverse any children.
719    handle_cull_callbacks_and_traverse(node);
720
721    RefMatrix& matrix = *getModelViewMatrix();
722    for(unsigned int i=0;i<node.getNumDrawables();++i)
723    {
724        Drawable* drawable = node.getDrawable(i);
725        const BoundingBox &bb =drawable->getBound();
726
727        if( drawable->getCullCallback() )
728        {
729            if( drawable->getCullCallback()->cull( this, drawable, &_renderInfo ) == true )
730            continue;
731        }
732       
733        //else
734        {
735            if (node.isCullingActive() && isCulled(bb)) continue;
736        }
737
738
739        if (_computeNearFar && bb.valid())
740        {
741            if (!updateCalculatedNearFar(matrix,*drawable,false)) continue;
742        }
743
744        // need to track how push/pops there are, so we can unravel the stack correctly.
745        unsigned int numPopStateSetRequired = 0;
746
747        // push the geoset's state on the geostate stack.   
748        StateSet* stateset = drawable->getStateSet();
749        if (stateset)
750        {
751            ++numPopStateSetRequired;
752            pushStateSet(stateset);
753        }
754
755        CullingSet& cs = getCurrentCullingSet();
756        if (!cs.getStateFrustumList().empty())
757        {
758            osg::CullingSet::StateFrustumList& sfl = cs.getStateFrustumList();
759            for(osg::CullingSet::StateFrustumList::iterator itr = sfl.begin();
760                itr != sfl.end();
761                ++itr)
762            {
763                if (itr->second.contains(bb))
764                {
765                    ++numPopStateSetRequired;
766                    pushStateSet(itr->first.get());
767                }
768            }
769        }
770
771        float depth = bb.valid() ? distance(bb.center(),matrix) : 0.0f;
772       
773        if (osg::isNaN(depth))
774        {
775            OSG_NOTIFY(osg::NOTICE)<<"CullVisitor::apply(Geode&) detected NaN,"<<std::endl
776                                    <<"    depth="<<depth<<", center=("<<bb.center()<<"),"<<std::endl
777                                    <<"    matrix="<<matrix<<std::endl;
778            OSG_NOTIFY(osg::DEBUG_INFO) << "    NodePath:" << std::endl;
779            for (NodePath::const_iterator i = getNodePath().begin(); i != getNodePath().end(); ++i)
780            {
781                OSG_NOTIFY(osg::DEBUG_INFO) << "        \"" << (*i)->getName() << "\"" << std::endl;
782            }
783        }
784        else
785        {       
786            addDrawableAndDepth(drawable,&matrix,depth);
787        }
788
789        for(unsigned int i=0;i< numPopStateSetRequired; ++i)
790        {
791            popStateSet();
792        }
793
794    }
795
796    // pop the node's state off the geostate stack.   
797    if (node_state) popStateSet();
798
799}
800
801
802void CullVisitor::apply(Billboard& node)
803{
804    if (isCulled(node)) return;
805
806    // push the node's state.
807    StateSet* node_state = node.getStateSet();
808    if (node_state) pushStateSet(node_state);
809
810    // traverse any call callbacks and traverse any children.
811    handle_cull_callbacks_and_traverse(node);
812
813    const Vec3& eye_local = getEyeLocal();
814    const RefMatrix& modelview = *getModelViewMatrix();
815
816    for(unsigned int i=0;i<node.getNumDrawables();++i)
817    {
818        const Vec3& pos = node.getPosition(i);
819
820        Drawable* drawable = node.getDrawable(i);
821        // need to modify isCulled to handle the billboard offset.
822        // if (isCulled(drawable->getBound())) continue;
823
824        if( drawable->getCullCallback() )
825        {
826            if( drawable->getCullCallback()->cull( this, drawable, &_renderInfo ) == true )
827                continue;
828        }
829
830        RefMatrix* billboard_matrix = createOrReuseMatrix(modelview);
831
832        node.computeMatrix(*billboard_matrix,eye_local,pos);
833
834
835        if (_computeNearFar && drawable->getBound().valid()) updateCalculatedNearFar(*billboard_matrix,*drawable,true);
836        float depth = distance(pos,modelview);
837/*
838        if (_computeNearFar)
839        {
840            if (d<_computed_znear)
841            {
842                if (d<0.0) OSG_NOTIFY(osg::WARN)<<"Alerting billboard handling ="<<d<< std::endl;
843                _computed_znear = d;
844            }
845            if (d>_computed_zfar) _computed_zfar = d;
846        }
847*/
848        StateSet* stateset = drawable->getStateSet();
849        if (stateset) pushStateSet(stateset);
850       
851        if (osg::isNaN(depth))
852        {
853            OSG_NOTIFY(osg::NOTICE)<<"CullVisitor::apply(Billboard&) detected NaN,"<<std::endl
854                                    <<"    depth="<<depth<<", pos=("<<pos<<"),"<<std::endl
855                                    <<"    *billboard_matrix="<<*billboard_matrix<<std::endl;
856            OSG_NOTIFY(osg::DEBUG_INFO) << "    NodePath:" << std::endl;
857            for (NodePath::const_iterator i = getNodePath().begin(); i != getNodePath().end(); ++i)
858            {
859                OSG_NOTIFY(osg::DEBUG_INFO) << "        \"" << (*i)->getName() << "\"" << std::endl;
860            }
861        }
862        else
863        {       
864            addDrawableAndDepth(drawable,billboard_matrix,depth);
865        }
866
867        if (stateset) popStateSet();
868
869    }
870
871    // pop the node's state off the geostate stack.   
872    if (node_state) popStateSet();
873
874}
875
876
877void CullVisitor::apply(LightSource& node)
878{
879    // push the node's state.
880    StateSet* node_state = node.getStateSet();
881    if (node_state) pushStateSet(node_state);
882
883    StateAttribute* light = node.getLight();
884    if (light)
885    {
886        if (node.getReferenceFrame()==osg::LightSource::RELATIVE_RF)
887        {
888            RefMatrix& matrix = *getModelViewMatrix();
889            addPositionedAttribute(&matrix,light);
890        }
891        else
892        {
893            // relative to absolute.
894            addPositionedAttribute(0,light);
895        }
896    }
897
898    handle_cull_callbacks_and_traverse(node);
899
900    // pop the node's state off the geostate stack.   
901    if (node_state) popStateSet();
902}
903
904void CullVisitor::apply(ClipNode& node)
905{
906    // push the node's state.
907    StateSet* node_state = node.getStateSet();
908    if (node_state) pushStateSet(node_state);
909
910    RefMatrix& matrix = *getModelViewMatrix();
911
912    const ClipNode::ClipPlaneList& planes = node.getClipPlaneList();
913    for(ClipNode::ClipPlaneList::const_iterator itr=planes.begin();
914        itr!=planes.end();
915        ++itr)
916    {
917        if (node.getReferenceFrame()==osg::ClipNode::RELATIVE_RF)
918        {
919            addPositionedAttribute(&matrix,itr->get());
920        }
921        else
922        {
923            addPositionedAttribute(0,itr->get());
924        }
925    }
926
927    handle_cull_callbacks_and_traverse(node);
928
929    // pop the node's state off the geostate stack.   
930    if (node_state) popStateSet();
931}
932
933void CullVisitor::apply(TexGenNode& node)
934{
935    // push the node's state.
936    StateSet* node_state = node.getStateSet();
937    if (node_state) pushStateSet(node_state);
938
939
940    if (node.getReferenceFrame()==osg::TexGenNode::RELATIVE_RF)
941    {
942        RefMatrix& matrix = *getModelViewMatrix();
943        addPositionedTextureAttribute(node.getTextureUnit(), &matrix ,node.getTexGen());
944    }
945    else
946    {
947        addPositionedTextureAttribute(node.getTextureUnit(), 0 ,node.getTexGen());
948    }
949   
950    handle_cull_callbacks_and_traverse(node);
951
952    // pop the node's state off the geostate stack.   
953    if (node_state) popStateSet();
954}
955
956void CullVisitor::apply(Group& node)
957{
958    if (isCulled(node)) return;
959
960    // push the culling mode.
961    pushCurrentMask();
962
963    // push the node's state.
964    StateSet* node_state = node.getStateSet();
965    if (node_state) pushStateSet(node_state);
966
967    handle_cull_callbacks_and_traverse(node);
968
969    // pop the node's state off the render graph stack.   
970    if (node_state) popStateSet();
971
972    // pop the culling mode.
973    popCurrentMask();
974}
975
976void CullVisitor::apply(Transform& node)
977{
978    if (isCulled(node)) return;
979
980    // push the culling mode.
981    pushCurrentMask();
982
983    // push the node's state.
984    StateSet* node_state = node.getStateSet();
985    if (node_state) pushStateSet(node_state);
986
987    ref_ptr<RefMatrix> matrix = createOrReuseMatrix(*getModelViewMatrix());
988    node.computeLocalToWorldMatrix(*matrix,this);
989    pushModelViewMatrix(matrix.get(), node.getReferenceFrame());
990   
991    handle_cull_callbacks_and_traverse(node);
992
993    popModelViewMatrix();
994
995    // pop the node's state off the render graph stack.   
996    if (node_state) popStateSet();
997
998    // pop the culling mode.
999    popCurrentMask();
1000}
1001
1002void CullVisitor::apply(Projection& node)
1003{
1004
1005    // push the culling mode.
1006    pushCurrentMask();
1007
1008    // push the node's state.
1009    StateSet* node_state = node.getStateSet();
1010    if (node_state) pushStateSet(node_state);
1011
1012
1013    // record previous near and far values.
1014    float previous_znear = _computed_znear;
1015    float previous_zfar = _computed_zfar;
1016   
1017    // take a copy of the current near plane candidates
1018    DistanceMatrixDrawableMap  previousNearPlaneCandidateMap;
1019    previousNearPlaneCandidateMap.swap(_nearPlaneCandidateMap);
1020
1021    _computed_znear = FLT_MAX;
1022    _computed_zfar = -FLT_MAX;
1023
1024
1025    ref_ptr<RefMatrix> matrix = createOrReuseMatrix(node.getMatrix());
1026    pushProjectionMatrix(matrix.get());
1027   
1028    //OSG_NOTIFY(osg::INFO)<<"Push projection "<<*matrix<<std::endl;
1029   
1030    // note do culling check after the frustum has been updated to ensure
1031    // that the node is not culled prematurely.
1032    if (!isCulled(node))
1033    {
1034        handle_cull_callbacks_and_traverse(node);
1035    }
1036
1037    popProjectionMatrix();
1038
1039    //OSG_NOTIFY(osg::INFO)<<"Pop projection "<<*matrix<<std::endl;
1040
1041    _computed_znear = previous_znear;
1042    _computed_zfar = previous_zfar;
1043
1044    // swap back the near plane candidates
1045    previousNearPlaneCandidateMap.swap(_nearPlaneCandidateMap);
1046
1047    // pop the node's state off the render graph stack.   
1048    if (node_state) popStateSet();
1049
1050    // pop the culling mode.
1051    popCurrentMask();
1052}
1053
1054void CullVisitor::apply(Switch& node)
1055{
1056    apply((Group&)node);
1057}
1058
1059
1060void CullVisitor::apply(LOD& node)
1061{
1062    if (isCulled(node)) return;
1063
1064    // push the culling mode.
1065    pushCurrentMask();
1066
1067    // push the node's state.
1068    StateSet* node_state = node.getStateSet();
1069    if (node_state) pushStateSet(node_state);
1070
1071    handle_cull_callbacks_and_traverse(node);
1072
1073    // pop the node's state off the render graph stack.   
1074    if (node_state) popStateSet();
1075
1076    // pop the culling mode.
1077    popCurrentMask();
1078}
1079
1080void CullVisitor::apply(osg::ClearNode& node)
1081{
1082    // simply override the current earth sky.
1083    if (node.getRequiresClear())
1084    {
1085      getCurrentRenderBin()->getStage()->setClearColor(node.getClearColor());
1086      getCurrentRenderBin()->getStage()->setClearMask(node.getClearMask());
1087    }
1088    else
1089    {
1090      // we have an earth sky implementation to do the work for us
1091      // so we don't need to clear.
1092      getCurrentRenderBin()->getStage()->setClearMask(0);
1093    }
1094
1095    // push the node's state.
1096    StateSet* node_state = node.getStateSet();
1097    if (node_state) pushStateSet(node_state);
1098
1099    handle_cull_callbacks_and_traverse(node);
1100
1101    // pop the node's state off the render graph stack.   
1102    if (node_state) popStateSet();
1103
1104}
1105
1106namespace osgUtil
1107{
1108
1109class RenderStageCache : public osg::Object
1110{
1111    public:
1112   
1113        RenderStageCache() {}
1114        RenderStageCache(const RenderStageCache&, const osg::CopyOp&) {}
1115       
1116        META_Object(osgUtil, RenderStageCache);
1117       
1118        void setRenderStage(CullVisitor* cv, RenderStage* rs)
1119        {
1120            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
1121            _renderStageMap[cv] = rs;
1122        }       
1123
1124        RenderStage* getRenderStage(osgUtil::CullVisitor* cv)
1125        {
1126            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex);
1127            return _renderStageMap[cv].get();
1128        }
1129       
1130        typedef std::map<CullVisitor*, osg::ref_ptr<RenderStage> > RenderStageMap;
1131       
1132        OpenThreads::Mutex  _mutex;
1133        RenderStageMap      _renderStageMap;
1134};
1135
1136}
1137
1138void CullVisitor::apply(osg::Camera& camera)
1139{
1140    // push the node's state.
1141    StateSet* node_state = camera.getStateSet();
1142    if (node_state) pushStateSet(node_state);
1143
1144//#define DEBUG_CULLSETTINGS
1145
1146#ifdef DEBUG_CULLSETTINGS
1147    if (osg::isNotifyEnabled(osg::NOTICE))
1148    {
1149        notify(osg::NOTICE)<<std::endl<<std::endl<<"CullVisitor, before : ";
1150        write(osg::notify(osg::NOTICE));
1151    }
1152#endif
1153
1154    // Save current cull settings
1155    CullSettings saved_cull_settings(*this);
1156
1157#ifdef DEBUG_CULLSETTINGS
1158    if (osg::isNotifyEnabled(osg::NOTICE))
1159    {
1160        osg::notify(osg::NOTICE)<<"CullVisitor, saved_cull_settings : ";
1161        saved_cull_settings.write(osg::notify(osg::NOTICE));
1162    }
1163#endif
1164
1165#if 1
1166    // set cull settings from this Camera
1167    setCullSettings(camera);
1168
1169#ifdef DEBUG_CULLSETTINGS
1170    osg::notify(osg::NOTICE)<<"CullVisitor, after setCullSettings(camera) : ";
1171    write(osg::notify(osg::NOTICE));
1172#endif
1173    // inherit the settings from above
1174    inheritCullSettings(saved_cull_settings, camera.getInheritanceMask());
1175
1176#ifdef DEBUG_CULLSETTINGS
1177    osg::notify(osg::NOTICE)<<"CullVisitor, after inheritCullSettings(saved_cull_settings,"<<camera.getInheritanceMask()<<") : ";
1178    write(osg::notify(osg::NOTICE));
1179#endif
1180
1181#else
1182    // activate all active cull settings from this Camera
1183    inheritCullSettings(camera);
1184#endif
1185
1186    // set the cull mask.
1187    unsigned int savedTraversalMask = getTraversalMask();
1188    bool mustSetCullMask = (camera.getInheritanceMask() & osg::CullSettings::CULL_MASK) == 0;
1189    if (mustSetCullMask) setTraversalMask(camera.getCullMask());
1190
1191    RefMatrix& originalModelView = *getModelViewMatrix();
1192
1193    osg::RefMatrix* projection = 0;
1194    osg::RefMatrix* modelview = 0;
1195
1196    if (camera.getReferenceFrame()==osg::Transform::RELATIVE_RF)
1197    {
1198        if (camera.getTransformOrder()==osg::Camera::POST_MULTIPLY)
1199        {
1200            projection = createOrReuseMatrix(*getProjectionMatrix()*camera.getProjectionMatrix());
1201            modelview = createOrReuseMatrix(*getModelViewMatrix()*camera.getViewMatrix());
1202        }
1203        else // pre multiply
1204        {
1205            projection = createOrReuseMatrix(camera.getProjectionMatrix()*(*getProjectionMatrix()));
1206            modelview = createOrReuseMatrix(camera.getViewMatrix()*(*getModelViewMatrix()));
1207        }
1208    }
1209    else
1210    {
1211        // an absolute reference frame
1212        projection = createOrReuseMatrix(camera.getProjectionMatrix());
1213        modelview = createOrReuseMatrix(camera.getViewMatrix());
1214    }
1215
1216
1217    if (camera.getViewport()) pushViewport(camera.getViewport());
1218
1219    // record previous near and far values.
1220    float previous_znear = _computed_znear;
1221    float previous_zfar = _computed_zfar;
1222   
1223    // take a copy of the current near plane candidates
1224    DistanceMatrixDrawableMap  previousNearPlaneCandidateMap;
1225    previousNearPlaneCandidateMap.swap(_nearPlaneCandidateMap);
1226
1227    _computed_znear = FLT_MAX;
1228    _computed_zfar = -FLT_MAX;
1229
1230    pushProjectionMatrix(projection);
1231    pushModelViewMatrix(modelview, camera.getReferenceFrame());   
1232
1233
1234    if (camera.getRenderOrder()==osg::Camera::NESTED_RENDER)
1235    {
1236        handle_cull_callbacks_and_traverse(camera);
1237    }
1238    else
1239    {
1240        // set up lighting.
1241        // currently ignore lights in the scene graph itself..
1242        // will do later.
1243        osgUtil::RenderStage* previous_stage = getCurrentRenderBin()->getStage();
1244
1245//        unsigned int contextID = getState() ? getState()->getContextID() : 0;
1246
1247        // use render to texture stage.
1248        // create the render to texture stage.
1249        osg::ref_ptr<osgUtil::RenderStageCache> rsCache = dynamic_cast<osgUtil::RenderStageCache*>(camera.getRenderingCache());
1250        if (!rsCache)
1251        {
1252            rsCache = new osgUtil::RenderStageCache;
1253            camera.setRenderingCache(rsCache.get());
1254        }
1255       
1256        osg::ref_ptr<osgUtil::RenderStage> rtts = rsCache->getRenderStage(this);
1257        if (!rtts)
1258        {
1259            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*(camera.getDataChangeMutex()));
1260       
1261            rtts = new osgUtil::RenderStage;
1262            rsCache->setRenderStage(this,rtts.get());
1263
1264            rtts->setCamera(&camera);
1265
1266            if ( camera.getInheritanceMask() & DRAW_BUFFER )
1267            {
1268                // inherit draw buffer from above.
1269                rtts->setDrawBuffer(previous_stage->getDrawBuffer(),previous_stage->getDrawBufferApplyMask());
1270            }
1271            else
1272            {
1273                rtts->setDrawBuffer(camera.getDrawBuffer());
1274            }
1275           
1276            if ( camera.getInheritanceMask() & READ_BUFFER )
1277            {
1278                // inherit read buffer from above.
1279                rtts->setReadBuffer(previous_stage->getReadBuffer(), previous_stage->getReadBufferApplyMask());
1280            }
1281            else
1282            {
1283                rtts->setReadBuffer(camera.getReadBuffer());
1284            }
1285        }
1286        else
1287        {
1288            // reusing render to texture stage, so need to reset it to empty it from previous frames contents.
1289            rtts->reset();
1290        }
1291
1292        // set up clera masks/values       
1293        rtts->setClearDepth(camera.getClearDepth());
1294        rtts->setClearAccum(camera.getClearAccum());
1295        rtts->setClearStencil(camera.getClearStencil());
1296        rtts->setClearMask(camera.getClearMask());
1297
1298
1299        // set up the background color and clear mask.
1300        if (camera.getInheritanceMask() & CLEAR_COLOR)
1301        {
1302            rtts->setClearColor(previous_stage->getClearColor());
1303        }
1304        else
1305        {
1306            rtts->setClearColor(camera.getClearColor());
1307        }
1308        if (camera.getInheritanceMask() & CLEAR_MASK)
1309        {
1310            rtts->setClearMask(previous_stage->getClearMask());
1311        }
1312        else
1313        {
1314            rtts->setClearMask(camera.getClearMask());
1315        }
1316
1317       
1318        // set the color mask.
1319        osg::ColorMask* colorMask = camera.getColorMask()!=0 ? camera.getColorMask() : previous_stage->getColorMask();
1320        rtts->setColorMask(colorMask);
1321
1322        // set up the viewport.
1323        osg::Viewport* viewport = camera.getViewport()!=0 ? camera.getViewport() : previous_stage->getViewport();
1324        rtts->setViewport( viewport );
1325       
1326
1327
1328        // set up to charge the same PositionalStateContainer is the parent previous stage.
1329        osg::Matrix inheritedMVtolocalMV;
1330        inheritedMVtolocalMV.invert(originalModelView);
1331        inheritedMVtolocalMV.postMult(*getModelViewMatrix());
1332        rtts->setInheritedPositionalStateContainerMatrix(inheritedMVtolocalMV);
1333        rtts->setInheritedPositionalStateContainer(previous_stage->getPositionalStateContainer());
1334
1335        // record the render bin, to be restored after creation
1336        // of the render to text
1337        osgUtil::RenderBin* previousRenderBin = getCurrentRenderBin();
1338
1339        // set the current renderbin to be the newly created stage.
1340        setCurrentRenderBin(rtts.get());
1341
1342        // traverse the subgraph
1343        {
1344            handle_cull_callbacks_and_traverse(camera);
1345        }
1346
1347        // restore the previous renderbin.
1348        setCurrentRenderBin(previousRenderBin);
1349     
1350
1351        if (rtts->getStateGraphList().size()==0 && rtts->getRenderBinList().size()==0)
1352        {
1353            // getting to this point means that all the subgraph has been
1354            // culled by small feature culling or is beyond LOD ranges.
1355        }
1356
1357
1358        // and the render to texture stage to the current stages
1359        // dependancy list.
1360        switch(camera.getRenderOrder())
1361        {
1362            case osg::Camera::PRE_RENDER:
1363                getCurrentRenderBin()->getStage()->addPreRenderStage(rtts.get(),camera.getRenderOrderNum());
1364                break;
1365            default:
1366                getCurrentRenderBin()->getStage()->addPostRenderStage(rtts.get(),camera.getRenderOrderNum());
1367                break;
1368        }
1369
1370    }
1371   
1372    // restore the previous model view matrix.
1373    popModelViewMatrix();
1374
1375    // restore the previous model view matrix.
1376    popProjectionMatrix();
1377
1378
1379    // restore the original near and far values
1380    _computed_znear = previous_znear;
1381    _computed_zfar = previous_zfar;
1382
1383    // swap back the near plane candidates
1384    previousNearPlaneCandidateMap.swap(_nearPlaneCandidateMap);
1385
1386
1387    if (camera.getViewport()) popViewport();
1388
1389    // restore the previous traversal mask settings
1390    if (mustSetCullMask) setTraversalMask(savedTraversalMask);
1391
1392    // restore the previous cull settings
1393    setCullSettings(saved_cull_settings);
1394
1395    // pop the node's state off the render graph stack.   
1396    if (node_state) popStateSet();
1397
1398}
1399
1400void CullVisitor::apply(osg::OccluderNode& node)
1401{
1402    // need to check if occlusion node is in the occluder
1403    // list, if so disable the appropriate ShadowOccluderVolume
1404    disableAndPushOccludersCurrentMask(_nodePath);
1405   
1406
1407    if (isCulled(node))
1408    {
1409        popOccludersCurrentMask(_nodePath);
1410        return;
1411    }
1412
1413    // push the culling mode.
1414    pushCurrentMask();
1415
1416    // push the node's state.
1417    StateSet* node_state = node.getStateSet();
1418    if (node_state) pushStateSet(node_state);
1419
1420
1421
1422    handle_cull_callbacks_and_traverse(node);
1423
1424    // pop the node's state off the render graph stack.   
1425    if (node_state) popStateSet();
1426
1427    // pop the culling mode.
1428    popCurrentMask();
1429
1430    // pop the current mask for the disabled occluder
1431    popOccludersCurrentMask(_nodePath);
1432}
1433
1434void CullVisitor::apply(osg::OcclusionQueryNode& node)
1435{
1436    if (isCulled(node)) return;
1437
1438    // push the culling mode.
1439    pushCurrentMask();
1440
1441    // push the node's state.
1442    StateSet* node_state = node.getStateSet();
1443    if (node_state) pushStateSet(node_state);
1444
1445
1446    osg::Camera* camera = getCurrentCamera();
1447   
1448    // If previous query indicates visible, then traverse as usual.
1449    if (node.getPassed( camera, *this ))
1450        handle_cull_callbacks_and_traverse(node);
1451
1452    // Traverse the query subtree if OcclusionQueryNode needs to issue another query.
1453    node.traverseQuery( camera, *this );
1454
1455    // Traverse the debug bounding geometry, if enabled.
1456    node.traverseDebug( *this );
1457
1458
1459    // pop the node's state off the render graph stack.   
1460    if (node_state) popStateSet();
1461
1462    // pop the culling mode.
1463    popCurrentMask();
1464}
Note: See TracBrowser for help on using the browser.