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

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

Convert NOTIFY to OSG_NOTIFY to avoid problems with polution of users apps with the NOTIFY macro

  • 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, getDistanceToEyePoint( node.getBound()._center, false ) ))
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.