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

Revision 11127, 45.7 kB (checked in by robert, 5 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
RevLine 
[5328]1/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
[1529]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*/
[10]13#include <osg/Transform>
[493]14#include <osg/Projection>
[10]15#include <osg/Geode>
16#include <osg/LOD>
17#include <osg/Billboard>
18#include <osg/LightSource>
[673]19#include <osg/ClipNode>
[3062]20#include <osg/TexGenNode>
[730]21#include <osg/OccluderNode>
[7731]22#include <osg/OcclusionQueryNode>
[10]23#include <osg/Notify>
24#include <osg/TexEnv>
25#include <osg/AlphaFunc>
[217]26#include <osg/LineSegment>
[2924]27#include <osg/TriangleFunctor>
28#include <osg/Geometry>
[4509]29#include <osg/io_utils>
[217]30
[523]31#include <osgUtil/CullVisitor>
[10]32
33#include <float.h>
34#include <algorithm>
35
[522]36#include <osg/Timer>
37
[10]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
[952]47CullVisitor::CullVisitor():
[1030]48    NodeVisitor(CULL_VISITOR,TRAVERSE_ACTIVE_CHILDREN),
[4589]49    _currentStateGraph(NULL),
[952]50    _currentRenderBin(NULL),
51    _computed_znear(FLT_MAX),
52    _computed_zfar(-FLT_MAX),
[5280]53    _currentReuseRenderLeafIndex(0),
54    _numberOfEncloseOverrideRenderBinDetails(0)
[217]55{
[10]56}
57
[7205]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}
[10]69
[523]70CullVisitor::~CullVisitor()
[10]71{
72    reset();
73}
74
[7205]75osg::ref_ptr<CullVisitor>& CullVisitor::prototype()
76{
77    static osg::ref_ptr<CullVisitor> s_CullVisitor = new CullVisitor;
78    return s_CullVisitor;
79}
[10]80
[7205]81CullVisitor* CullVisitor::create()
82{
83    return CullVisitor::prototype().valid() ?
84           CullVisitor::prototype()->clone() :
85           new CullVisitor;
86}
87
88
[523]89void CullVisitor::reset()
[10]90{
91    //
92    // first unref all referenced objects and then empty the containers.
93    //
[749]94   
95    CullStack::reset();
[8455]96   
97    _renderBinStack.clear();
[522]98
[5280]99    _numberOfEncloseOverrideRenderBinDetails = 0;
100
[10275]101    // reset the traversal number
102    _traversalNumber = 0;
103
[10]104    // reset the calculated near far planes.
[614]105    _computed_znear = FLT_MAX;
106    _computed_zfar = -FLT_MAX;
[10]107   
108   
[522]109    osg::Vec3 lookVector(0.0,0.0,-1.0);
[10]110   
[522]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   
[5178]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;
[217]121        ++itr)
[10]122    {
[217]123        (*itr)->reset();
[10]124    }
125   
[5178]126    // reset the resuse lists.
127    _currentReuseRenderLeafIndex = 0;
[2924]128
129    _nearPlaneCandidateMap.clear();
[10]130}
131
[1307]132float CullVisitor::getDistanceToEyePoint(const Vec3& pos, bool withLODScale) const
[1192]133{
[1307]134    if (withLODScale) return (pos-getEyeLocal()).length()*getLODScale();
[1192]135    else return (pos-getEyeLocal()).length();
136}
[10]137
[5821]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
[2228]144inline CullVisitor::value_type distance(const osg::Vec3& coord,const osg::Matrix& matrix)
[1192]145{
[2228]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));
[1192]147}
148
[1307]149float CullVisitor::getDistanceFromEyePoint(const osg::Vec3& pos, bool withLODScale) const
[1192]150{
151    const Matrix& matrix = *_modelviewStack.back();
152    float dist = distance(pos,matrix);
153   
[1307]154    if (withLODScale) return dist*getLODScale();
[1573]155    else return dist;
[1192]156}
157
[6676]158void CullVisitor::computeNearPlane()
[10]159{
[2924]160    if (!_nearPlaneCandidateMap.empty())
161    {
162   
[7375]163        // osg::Timer_t start_t = osg::Timer::instance()->tick();
[2924]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;
[11046]172            // OSG_NOTIFY(osg::WARN)<<"testing computeNearestPointInFrustum with d_near = "<<itr->first<<std::endl;
[2924]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;
[11046]177                // OSG_NOTIFY(osg::WARN)<<"updating znear to "<<_computed_znear<<std::endl;
[2924]178            }
179        }
180
[7375]181        // osg::Timer_t end_t = osg::Timer::instance()->tick();
[11046]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;
[6676]183
184        _nearPlaneCandidateMap.clear();
[2924]185    }
[6676]186}
[2924]187
[6676]188void CullVisitor::popProjectionMatrix()
189{
190    computeNearPlane();
191
[3015]192    if (_computeNearFar && _computed_zfar>=_computed_znear)
[614]193    {
194
[11046]195        //OSG_NOTIFY(osg::INFO)<<"clamping "<< "znear="<<_computed_znear << " zfar="<<_computed_zfar<<std::endl;
[2924]196
[3015]197
[614]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();
[3015]201       
[3265]202        value_type tmp_znear = _computed_znear;
203        value_type tmp_zfar = _computed_zfar;
[3236]204       
205        clampProjectionMatrix(projection, tmp_znear, tmp_zfar);
[2542]206    }
[3015]207    else
208    {
[11046]209        //OSG_NOTIFY(osg::INFO)<<"Not clamping "<< "znear="<<_computed_znear << " zfar="<<_computed_zfar<<std::endl;
[3015]210    }
[2542]211
212    CullStack::popProjectionMatrix();
213}
214
[2568]215template<class matrix_type, class value_type>
[3015]216bool _clampProjectionMatrix(matrix_type& projection, double& znear, double& zfar, value_type nearFarRatio)
[2542]217{
[4940]218    double epsilon = 1e-6;
219    if (zfar<znear-epsilon)
[2542]220    {
[11046]221        OSG_NOTIFY(osg::INFO)<<"_clampProjectionMatrix not applied, invalid depth range, znear = "<<znear<<"  zfar = "<<zfar<<std::endl;
[4940]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;
[11046]232        // OSG_NOTIFY(osg::INFO) << "_clampProjectionMatrix widening znear and zfar to "<<znear<<" "<<zfar<<std::endl;
[4940]233    }
[2542]234
[4940]235    if (fabs(projection(0,3))<epsilon  && fabs(projection(1,3))<epsilon  && fabs(projection(2,3))<epsilon )
236    {
[11046]237        // OSG_NOTIFY(osg::INFO) << "Orthographic matrix before clamping"<<projection<<std::endl;
[2137]238
[4940]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;
[2137]243
[4940]244        // assign the clamped values back to the computed values.
245        znear = desired_znear;
246        zfar = desired_zfar;
[2137]247
[4940]248        projection(2,2)=-2.0f/(desired_zfar-desired_znear);
249        projection(3,2)=-(desired_zfar+desired_znear)/(desired_zfar-desired_znear);
[3015]250
[11046]251        // OSG_NOTIFY(osg::INFO) << "Orthographic matrix after clamping "<<projection<<std::endl;
[4940]252    }
253    else
254    {
[2137]255
[11046]256        // OSG_NOTIFY(osg::INFO) << "Persepective matrix before clamping"<<projection<<std::endl;
[614]257
[4940]258        //std::cout << "_computed_znear"<<_computed_znear<<std::endl;
259        //std::cout << "_computed_zfar"<<_computed_zfar<<std::endl;
[614]260
[4940]261        value_type zfarPushRatio = 1.02;
262        value_type znearPullRatio = 0.98;
[614]263
[4940]264        //znearPullRatio = 0.99;
[2221]265
[4940]266        value_type desired_znear = znear * znearPullRatio;
267        value_type desired_zfar = zfar * zfarPushRatio;
[614]268
[4940]269        // near plane clamping.
270        double min_near_plane = zfar*nearFarRatio;
271        if (desired_znear<min_near_plane) desired_znear=min_near_plane;
[1938]272
[4940]273        // assign the clamped values back to the computed values.
274        znear = desired_znear;
275        zfar = desired_zfar;
[1938]276
[4940]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));
[3015]279
[4940]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
[11046]288        // OSG_NOTIFY(osg::INFO) << "Persepective matrix after clamping"<<projection<<std::endl;
[614]289    }
[4940]290    return true;
[10]291}
292
[217]293
[3015]294bool CullVisitor::clampProjectionMatrixImplementation(osg::Matrixf& projection, double& znear, double& zfar) const
[2568]295{
296    return _clampProjectionMatrix( projection, znear, zfar, _nearFarRatio );
297}
298
[3015]299bool CullVisitor::clampProjectionMatrixImplementation(osg::Matrixd& projection, double& znear, double& zfar) const
[2568]300{
301    return _clampProjectionMatrix( projection, znear, zfar, _nearFarRatio );
302}
303
[2924]304struct ComputeNearestPointFunctor
[10]305{
[614]306
[2924]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        {
[11046]339            //OSG_NOTIFY(osg::NOTICE)<<"Triangle totally beyond znear"<<std::endl;
[2924]340            return;
341        }
342     
343       
344        if (n1 < 0.0 &&
345            n2 < 0.0 &&
346            n3 < 0.0)
347        {
[11046]348            // OSG_NOTIFY(osg::NOTICE)<<"Triangle totally behind eye point"<<std::endl;
[2924]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);
[11043]365
[2924]366            unsigned int numOutside = ((d1<0.0)?1:0) + ((d2<0.0)?1:0) + ((d3<0.0)?1:0);
367            if (numOutside==3)
368            {
[11046]369                //OSG_NOTIFY(osg::NOTICE)<<"Triangle totally outside frustum "<<d1<<"\t"<<d2<<"\t"<<d3<<std::endl;
[2924]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           
[11046]378            //OSG_NOTIFY(osg::NOTICE)<<"Triangle ok w.r.t plane "<<d1<<"\t"<<d2<<"\t"<<d3<<std::endl;
[2924]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);
[11046]388            // OSG_NOTIFY(osg::NOTICE)<<"Triangle all inside frustum "<<n1<<"\t"<<n2<<"\t"<<n3<<" number of plane="<<_planes->size()<<std::endl;
[2924]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       
[11046]397        //OSG_NOTIFY(osg::NOTICE)<<"Using brute force method of triangle cutting frustum walls"<<std::endl;
[2924]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;
[11046]461                //OSG_NOTIFY(osg::NOTICE)<<"Near plane updated "<<_znear<<std::endl;
[2924]462            }
463        }
464    }
465};
466
467CullVisitor::value_type CullVisitor::computeNearestPointInFrustum(const osg::Matrix& matrix, const osg::Polytope::PlaneList& planes,const osg::Drawable& drawable)
468{
[11046]469    // OSG_NOTIFY(osg::WARN)<<"CullVisitor::computeNearestPointInFrustum("<<getTraversalNumber()<<"\t"<<planes.size()<<std::endl;
[2924]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{
[2228]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
[2924]486    if (d_near>d_far)
[2228]487    {
[2924]488        std::swap(d_near,d_far);
489        if ( !EQUAL_F(d_near, d_far) )
490        {
[11046]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;
[2924]493        }
[2228]494    }
[2924]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        {
[11046]523            OSG_NOTIFY(osg::NOTICE)<<"Took "<<elapsed_time<<"ms to test "<<numBillboards<<" billboards"<<std::endl;
[2924]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
[3122]537        unsigned int bbCornerNear = (~bbCornerFar)&7;
[2924]538
539        d_near = distance(bb.corner(bbCornerNear),matrix);
540        d_far = distance(bb.corner(bbCornerFar),matrix);
541
[11046]542        OSG_NOTIFY(osg::NOTICE).precision(15);
[2924]543
544        if (false)
545        {
546
[11046]547            OSG_NOTIFY(osg::NOTICE)<<"TESTING Billboard near/far computation"<<std::endl;
[2924]548
[11046]549             // OSG_NOTIFY(osg::WARN)<<"Checking corners of billboard "<<std::endl;
[2924]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;
[11046]558                OSG_NOTIFY(osg::NOTICE)<<"\ti="<<i<<"\td="<<d<<std::endl;
[2924]559            }
560
561            if (nd_near==d_near && nd_far==d_far)
562            {
[11046]563                OSG_NOTIFY(osg::NOTICE)<<"\tBillboard near/far computation correct "<<std::endl;
[2924]564            }
565            else
566            {
[11046]567                OSG_NOTIFY(osg::NOTICE)<<"\tBillboard near/far computation ERROR\n\t\t"<<d_near<<"\t"<<nd_near
[2924]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    }
[2228]580    else
581    {
[2924]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);
[2228]591        if ( !EQUAL_F(d_near, d_far) )
592        {
[11046]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;
[2228]595        }
596    }
[2924]597
[4871]598    if (d_far<0.0)
[2924]599    {
[4863]600        // whole object behind the eye point so discard
[2924]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();
[10170]609            if (frustum.getResultMask())
[2924]610            {
611                if (isBillboard)
612                {
[11046]613                    // OSG_NOTIFY(osg::WARN)<<"Adding billboard into deffered list"<<std::endl;
[2924]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                }
[11043]628
[2924]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                {
[11043]633                    if (d_far>=0.0) _computed_znear = d_far;
[11046]634                    else OSG_NOTIFY(osg::WARN)<<"       1)  sett near with dnear="<<d_near<<"  dfar="<<d_far<< std::endl;
[2924]635                }
636            }
637            else
638            {
[11043]639                if (d_near>=0.0) _computed_znear = d_near;
[11046]640                else OSG_NOTIFY(osg::WARN)<<"        2) sett near with d_near="<<d_near<< std::endl;
[2924]641            }
642        }
643        else
644        {
[11046]645            //if (d_near<0.0) OSG_NOTIFY(osg::WARN)<<"         3) set near with d_near="<<d_near<< std::endl;
[2924]646            _computed_znear = d_near;
647        }
[11043]648    }
[2924]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
[10]667}
[523]668void CullVisitor::updateCalculatedNearFar(const osg::Vec3& pos)
[10]669{
670    float d;
[522]671    if (!_modelviewStack.empty())
[10]672    {
[522]673        const osg::Matrix& matrix = *(_modelviewStack.back());
674        d = distance(pos,matrix);
[10]675    }
676    else
677    {
[522]678        d = -pos.z();
[10]679    }
680
[2924]681    if (d<_computed_znear)
682    {
683       _computed_znear = d;
[11046]684       if (d<0.0) OSG_NOTIFY(osg::WARN)<<"Alerting billboard ="<<d<< std::endl;
[2924]685    }
[614]686    if (d>_computed_zfar) _computed_zfar = d;
[10]687}   
688
[523]689void CullVisitor::apply(Node& node)
[10]690{
[724]691    if (isCulled(node)) return;
[10]692
693    // push the culling mode.
[724]694    pushCurrentMask();
[10]695   
696    // push the node's state.
697    StateSet* node_state = node.getStateSet();
698    if (node_state) pushStateSet(node_state);
699
[563]700    handle_cull_callbacks_and_traverse(node);
[10]701
702    // pop the node's state off the geostate stack.   
703    if (node_state) popStateSet();
704   
705    // pop the culling mode.
[724]706    popCurrentMask();
[10]707}
708
709
[523]710void CullVisitor::apply(Geode& node)
[10]711{
[724]712    if (isCulled(node)) return;
[10]713
714    // push the node's state.
715    StateSet* node_state = node.getStateSet();
716    if (node_state) pushStateSet(node_state);
717
[2240]718    // traverse any call callbacks and traverse any children.
719    handle_cull_callbacks_and_traverse(node);
720
[6248]721    RefMatrix& matrix = *getModelViewMatrix();
[914]722    for(unsigned int i=0;i<node.getNumDrawables();++i)
[10]723    {
724        Drawable* drawable = node.getDrawable(i);
725        const BoundingBox &bb =drawable->getBound();
726
[449]727        if( drawable->getCullCallback() )
728        {
[5573]729            if( drawable->getCullCallback()->cull( this, drawable, &_renderInfo ) == true )
[449]730            continue;
731        }
[2924]732       
733        //else
[449]734        {
[2800]735            if (node.isCullingActive() && isCulled(bb)) continue;
[449]736        }
[10]737
[217]738
[2924]739        if (_computeNearFar && bb.valid())
740        {
741            if (!updateCalculatedNearFar(matrix,*drawable,false)) continue;
742        }
[217]743
[4509]744        // need to track how push/pops there are, so we can unravel the stack correctly.
745        unsigned int numPopStateSetRequired = 0;
746
[10]747        // push the geoset's state on the geostate stack.   
748        StateSet* stateset = drawable->getStateSet();
[4509]749        if (stateset)
750        {
751            ++numPopStateSetRequired;
752            pushStateSet(stateset);
753        }
[449]754
[4509]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
[8383]771        float depth = bb.valid() ? distance(bb.center(),matrix) : 0.0f;
772       
773        if (osg::isNaN(depth))
774        {
[11046]775            OSG_NOTIFY(osg::NOTICE)<<"CullVisitor::apply(Geode&) detected NaN,"<<std::endl
[8383]776                                    <<"    depth="<<depth<<", center=("<<bb.center()<<"),"<<std::endl
777                                    <<"    matrix="<<matrix<<std::endl;
[11046]778            OSG_NOTIFY(osg::DEBUG_INFO) << "    NodePath:" << std::endl;
[10095]779            for (NodePath::const_iterator i = getNodePath().begin(); i != getNodePath().end(); ++i)
780            {
[11046]781                OSG_NOTIFY(osg::DEBUG_INFO) << "        \"" << (*i)->getName() << "\"" << std::endl;
[10095]782            }
[8383]783        }
[8384]784        else
785        {       
786            addDrawableAndDepth(drawable,&matrix,depth);
787        }
[10]788
[4509]789        for(unsigned int i=0;i< numPopStateSetRequired; ++i)
790        {
791            popStateSet();
792        }
[1156]793
[10]794    }
795
796    // pop the node's state off the geostate stack.   
797    if (node_state) popStateSet();
798
799}
800
801
[523]802void CullVisitor::apply(Billboard& node)
[10]803{
[724]804    if (isCulled(node)) return;
[10]805
806    // push the node's state.
807    StateSet* node_state = node.getStateSet();
808    if (node_state) pushStateSet(node_state);
809
[2240]810    // traverse any call callbacks and traverse any children.
811    handle_cull_callbacks_and_traverse(node);
812
[310]813    const Vec3& eye_local = getEyeLocal();
[6248]814    const RefMatrix& modelview = *getModelViewMatrix();
[10]815
[914]816    for(unsigned int i=0;i<node.getNumDrawables();++i)
[10]817    {
[3068]818        const Vec3& pos = node.getPosition(i);
[10]819
820        Drawable* drawable = node.getDrawable(i);
821        // need to modify isCulled to handle the billboard offset.
822        // if (isCulled(drawable->getBound())) continue;
823
[7051]824        if( drawable->getCullCallback() )
825        {
826            if( drawable->getCullCallback()->cull( this, drawable, &_renderInfo ) == true )
827                continue;
828        }
829
[1463]830        RefMatrix* billboard_matrix = createOrReuseMatrix(modelview);
[10]831
[2517]832        node.computeMatrix(*billboard_matrix,eye_local,pos);
[311]833
[583]834
[2924]835        if (_computeNearFar && drawable->getBound().valid()) updateCalculatedNearFar(*billboard_matrix,*drawable,true);
[8383]836        float depth = distance(pos,modelview);
[2924]837/*
[614]838        if (_computeNearFar)
839        {
[2924]840            if (d<_computed_znear)
841            {
[11046]842                if (d<0.0) OSG_NOTIFY(osg::WARN)<<"Alerting billboard handling ="<<d<< std::endl;
[2924]843                _computed_znear = d;
844            }
[614]845            if (d>_computed_zfar) _computed_zfar = d;
846        }
[2924]847*/
[10]848        StateSet* stateset = drawable->getStateSet();
[1156]849        if (stateset) pushStateSet(stateset);
[10]850       
[8383]851        if (osg::isNaN(depth))
852        {
[11046]853            OSG_NOTIFY(osg::NOTICE)<<"CullVisitor::apply(Billboard&) detected NaN,"<<std::endl
[8384]854                                    <<"    depth="<<depth<<", pos=("<<pos<<"),"<<std::endl
855                                    <<"    *billboard_matrix="<<*billboard_matrix<<std::endl;
[11046]856            OSG_NOTIFY(osg::DEBUG_INFO) << "    NodePath:" << std::endl;
[10095]857            for (NodePath::const_iterator i = getNodePath().begin(); i != getNodePath().end(); ++i)
858            {
[11046]859                OSG_NOTIFY(osg::DEBUG_INFO) << "        \"" << (*i)->getName() << "\"" << std::endl;
[10095]860            }
[8383]861        }
[8384]862        else
863        {       
864            addDrawableAndDepth(drawable,billboard_matrix,depth);
865        }
[10]866
[1156]867        if (stateset) popStateSet();
868
[10]869    }
870
871    // pop the node's state off the geostate stack.   
872    if (node_state) popStateSet();
873
874}
875
876
[523]877void CullVisitor::apply(LightSource& node)
[10]878{
879    // push the node's state.
880    StateSet* node_state = node.getStateSet();
881    if (node_state) pushStateSet(node_state);
882
[777]883    StateAttribute* light = node.getLight();
[10]884    if (light)
885    {
[3528]886        if (node.getReferenceFrame()==osg::LightSource::RELATIVE_RF)
[1493]887        {
[6248]888            RefMatrix& matrix = *getModelViewMatrix();
[1493]889            addPositionedAttribute(&matrix,light);
890        }
891        else
892        {
893            // relative to absolute.
894            addPositionedAttribute(0,light);
895        }
[10]896    }
897
[1069]898    handle_cull_callbacks_and_traverse(node);
899
[10]900    // pop the node's state off the geostate stack.   
901    if (node_state) popStateSet();
902}
903
[673]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);
[10]909
[6248]910    RefMatrix& matrix = *getModelViewMatrix();
[673]911
912    const ClipNode::ClipPlaneList& planes = node.getClipPlaneList();
913    for(ClipNode::ClipPlaneList::const_iterator itr=planes.begin();
914        itr!=planes.end();
915        ++itr)
916    {
[9411]917        if (node.getReferenceFrame()==osg::ClipNode::RELATIVE_RF)
918        {
919            addPositionedAttribute(&matrix,itr->get());
920        }
921        else
922        {
923            addPositionedAttribute(0,itr->get());
924        }
[673]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
[3062]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
[4387]940    if (node.getReferenceFrame()==osg::TexGenNode::RELATIVE_RF)
941    {
[6248]942        RefMatrix& matrix = *getModelViewMatrix();
[4387]943        addPositionedTextureAttribute(node.getTextureUnit(), &matrix ,node.getTexGen());
944    }
945    else
946    {
947        addPositionedTextureAttribute(node.getTextureUnit(), 0 ,node.getTexGen());
948    }
949   
[3062]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
[523]956void CullVisitor::apply(Group& node)
[10]957{
[724]958    if (isCulled(node)) return;
[10]959
960    // push the culling mode.
[724]961    pushCurrentMask();
[10]962
963    // push the node's state.
964    StateSet* node_state = node.getStateSet();
965    if (node_state) pushStateSet(node_state);
966
[563]967    handle_cull_callbacks_and_traverse(node);
[10]968
969    // pop the node's state off the render graph stack.   
970    if (node_state) popStateSet();
971
972    // pop the culling mode.
[724]973    popCurrentMask();
[10]974}
975
[523]976void CullVisitor::apply(Transform& node)
[10]977{
[724]978    if (isCulled(node)) return;
[10]979
980    // push the culling mode.
[724]981    pushCurrentMask();
[10]982
983    // push the node's state.
984    StateSet* node_state = node.getStateSet();
985    if (node_state) pushStateSet(node_state);
986
[6248]987    ref_ptr<RefMatrix> matrix = createOrReuseMatrix(*getModelViewMatrix());
[2517]988    node.computeLocalToWorldMatrix(*matrix,this);
[6109]989    pushModelViewMatrix(matrix.get(), node.getReferenceFrame());
[493]990   
[563]991    handle_cull_callbacks_and_traverse(node);
[10]992
[522]993    popModelViewMatrix();
[493]994
995    // pop the node's state off the render graph stack.   
996    if (node_state) popStateSet();
997
998    // pop the culling mode.
[724]999    popCurrentMask();
[493]1000}
1001
[523]1002void CullVisitor::apply(Projection& node)
[493]1003{
1004
1005    // push the culling mode.
[724]1006    pushCurrentMask();
[493]1007
1008    // push the node's state.
1009    StateSet* node_state = node.getStateSet();
1010    if (node_state) pushStateSet(node_state);
1011
[614]1012
1013    // record previous near and far values.
1014    float previous_znear = _computed_znear;
1015    float previous_zfar = _computed_zfar;
1016   
[2924]1017    // take a copy of the current near plane candidates
1018    DistanceMatrixDrawableMap  previousNearPlaneCandidateMap;
1019    previousNearPlaneCandidateMap.swap(_nearPlaneCandidateMap);
1020
[614]1021    _computed_znear = FLT_MAX;
1022    _computed_zfar = -FLT_MAX;
1023
[2924]1024
[5125]1025    ref_ptr<RefMatrix> matrix = createOrReuseMatrix(node.getMatrix());
[522]1026    pushProjectionMatrix(matrix.get());
[396]1027   
[11046]1028    //OSG_NOTIFY(osg::INFO)<<"Push projection "<<*matrix<<std::endl;
[3015]1029   
[2950]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    }
[10]1036
[522]1037    popProjectionMatrix();
[10]1038
[11046]1039    //OSG_NOTIFY(osg::INFO)<<"Pop projection "<<*matrix<<std::endl;
[3015]1040
[614]1041    _computed_znear = previous_znear;
1042    _computed_zfar = previous_zfar;
1043
[2924]1044    // swap back the near plane candidates
1045    previousNearPlaneCandidateMap.swap(_nearPlaneCandidateMap);
[614]1046
[10]1047    // pop the node's state off the render graph stack.   
1048    if (node_state) popStateSet();
1049
1050    // pop the culling mode.
[724]1051    popCurrentMask();
[10]1052}
1053
[523]1054void CullVisitor::apply(Switch& node)
[10]1055{
1056    apply((Group&)node);
1057}
1058
1059
[523]1060void CullVisitor::apply(LOD& node)
[10]1061{
[724]1062    if (isCulled(node)) return;
[10]1063
1064    // push the culling mode.
[724]1065    pushCurrentMask();
[10]1066
1067    // push the node's state.
1068    StateSet* node_state = node.getStateSet();
1069    if (node_state) pushStateSet(node_state);
1070
[1192]1071    handle_cull_callbacks_and_traverse(node);
[10]1072
1073    // pop the node's state off the render graph stack.   
1074    if (node_state) popStateSet();
1075
1076    // pop the culling mode.
[724]1077    popCurrentMask();
[10]1078}
1079
[1053]1080void CullVisitor::apply(osg::ClearNode& node)
[42]1081{
1082    // simply override the current earth sky.
[7652]1083    if (node.getRequiresClear())
1084    {
1085      getCurrentRenderBin()->getStage()->setClearColor(node.getClearColor());
1086      getCurrentRenderBin()->getStage()->setClearMask(node.getClearMask());
1087    }
1088    else
1089    {
[10504]1090      // we have an earth sky implementation to do the work for us
[7652]1091      // so we don't need to clear.
1092      getCurrentRenderBin()->getStage()->setClearMask(0);
1093    }
[42]1094
1095    // push the node's state.
1096    StateSet* node_state = node.getStateSet();
1097    if (node_state) pushStateSet(node_state);
1098
[563]1099    handle_cull_callbacks_and_traverse(node);
[42]1100
1101    // pop the node's state off the render graph stack.   
1102    if (node_state) popStateSet();
1103
1104}
1105
[6086]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
[5757]1138void CullVisitor::apply(osg::Camera& camera)
[4332]1139{
1140    // push the node's state.
1141    StateSet* node_state = camera.getStateSet();
1142    if (node_state) pushStateSet(node_state);
[4426]1143
[8138]1144//#define DEBUG_CULLSETTINGS
1145
1146#ifdef DEBUG_CULLSETTINGS
[11043]1147    if (osg::isNotifyEnabled(osg::NOTICE))
1148    {
1149        notify(osg::NOTICE)<<std::endl<<std::endl<<"CullVisitor, before : ";
1150        write(osg::notify(osg::NOTICE));
1151    }
[8138]1152#endif
1153
[5691]1154    // Save current cull settings
1155    CullSettings saved_cull_settings(*this);
1156
[8138]1157#ifdef DEBUG_CULLSETTINGS
[11043]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    }
[8138]1163#endif
1164
[7912]1165#if 1
1166    // set cull settings from this Camera
1167    setCullSettings(camera);
1168
[8138]1169#ifdef DEBUG_CULLSETTINGS
1170    osg::notify(osg::NOTICE)<<"CullVisitor, after setCullSettings(camera) : ";
1171    write(osg::notify(osg::NOTICE));
1172#endif
[7912]1173    // inherit the settings from above
1174    inheritCullSettings(saved_cull_settings, camera.getInheritanceMask());
[8138]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
[7912]1181#else
[5757]1182    // activate all active cull settings from this Camera
[5691]1183    inheritCullSettings(camera);
[7912]1184#endif
[5691]1185
[7177]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());
[6509]1190
[6248]1191    RefMatrix& originalModelView = *getModelViewMatrix();
[4332]1192
[5821]1193    osg::RefMatrix* projection = 0;
1194    osg::RefMatrix* modelview = 0;
1195
[6109]1196    if (camera.getReferenceFrame()==osg::Transform::RELATIVE_RF)
[4332]1197    {
[6109]1198        if (camera.getTransformOrder()==osg::Camera::POST_MULTIPLY)
1199        {
[6248]1200            projection = createOrReuseMatrix(*getProjectionMatrix()*camera.getProjectionMatrix());
1201            modelview = createOrReuseMatrix(*getModelViewMatrix()*camera.getViewMatrix());
[6109]1202        }
1203        else // pre multiply
1204        {
[6248]1205            projection = createOrReuseMatrix(camera.getProjectionMatrix()*(*getProjectionMatrix()));
1206            modelview = createOrReuseMatrix(camera.getViewMatrix()*(*getModelViewMatrix()));
[6109]1207        }
1208    }
1209    else
1210    {
1211        // an absolute reference frame
[5821]1212        projection = createOrReuseMatrix(camera.getProjectionMatrix());
1213        modelview = createOrReuseMatrix(camera.getViewMatrix());
[4333]1214    }
1215
[4426]1216
[6224]1217    if (camera.getViewport()) pushViewport(camera.getViewport());
1218
[6688]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
[5821]1230    pushProjectionMatrix(projection);
[6224]1231    pushModelViewMatrix(modelview, camera.getReferenceFrame());   
[5821]1232
1233
[5757]1234    if (camera.getRenderOrder()==osg::Camera::NESTED_RENDER)
[4333]1235    {
1236        handle_cull_callbacks_and_traverse(camera);
1237    }
1238    else
1239    {
[4438]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
[7375]1245//        unsigned int contextID = getState() ? getState()->getContextID() : 0;
[4438]1246
[4333]1247        // use render to texture stage.
[4332]1248        // create the render to texture stage.
[7177]1249        osg::ref_ptr<osgUtil::RenderStageCache> rsCache = dynamic_cast<osgUtil::RenderStageCache*>(camera.getRenderingCache());
[6086]1250        if (!rsCache)
1251        {
1252            rsCache = new osgUtil::RenderStageCache;
[7177]1253            camera.setRenderingCache(rsCache.get());
[6086]1254        }
1255       
1256        osg::ref_ptr<osgUtil::RenderStage> rtts = rsCache->getRenderStage(this);
[4340]1257        if (!rtts)
1258        {
[4834]1259            OpenThreads::ScopedLock<OpenThreads::Mutex> lock(*(camera.getDataChangeMutex()));
[4831]1260       
[4438]1261            rtts = new osgUtil::RenderStage;
[6086]1262            rsCache->setRenderStage(this,rtts.get());
1263
[5757]1264            rtts->setCamera(&camera);
[4438]1265
[10547]1266            if ( camera.getInheritanceMask() & DRAW_BUFFER )
[4438]1267            {
[10547]1268                // inherit draw buffer from above.
1269                rtts->setDrawBuffer(previous_stage->getDrawBuffer(),previous_stage->getDrawBufferApplyMask());
[4438]1270            }
1271            else
1272            {
[10547]1273                rtts->setDrawBuffer(camera.getDrawBuffer());
[4438]1274            }
[10547]1275           
1276            if ( camera.getInheritanceMask() & READ_BUFFER )
[4438]1277            {
[10547]1278                // inherit read buffer from above.
1279                rtts->setReadBuffer(previous_stage->getReadBuffer(), previous_stage->getReadBufferApplyMask());
[4438]1280            }
1281            else
1282            {
[10547]1283                rtts->setReadBuffer(camera.getReadBuffer());
[4438]1284            }
[4340]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        }
[4332]1291
[8335]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());
[4395]1297
[8335]1298
[4332]1299        // set up the background color and clear mask.
[5620]1300        if (camera.getInheritanceMask() & CLEAR_COLOR)
1301        {
[8335]1302            rtts->setClearColor(previous_stage->getClearColor());
[5620]1303        }
1304        else
1305        {
[8335]1306            rtts->setClearColor(camera.getClearColor());
[5620]1307        }
[10838]1308        if (camera.getInheritanceMask() & CLEAR_MASK)
1309        {
1310            rtts->setClearMask(previous_stage->getClearMask());
1311        }
1312        else
1313        {
1314            rtts->setClearMask(camera.getClearMask());
1315        }
[10547]1316
[4395]1317       
1318        // set the color mask.
1319        osg::ColorMask* colorMask = camera.getColorMask()!=0 ? camera.getColorMask() : previous_stage->getColorMask();
1320        rtts->setColorMask(colorMask);
[4332]1321
[4395]1322        // set up the viewport.
[4340]1323        osg::Viewport* viewport = camera.getViewport()!=0 ? camera.getViewport() : previous_stage->getViewport();
1324        rtts->setViewport( viewport );
[4332]1325       
[4438]1326
[8335]1327
[4492]1328        // set up to charge the same PositionalStateContainer is the parent previous stage.
[8665]1329        osg::Matrix inheritedMVtolocalMV;
1330        inheritedMVtolocalMV.invert(originalModelView);
1331        inheritedMVtolocalMV.postMult(*getModelViewMatrix());
1332        rtts->setInheritedPositionalStateContainerMatrix(inheritedMVtolocalMV);
[4492]1333        rtts->setInheritedPositionalStateContainer(previous_stage->getPositionalStateContainer());
[4332]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);
[4395]1349     
[4332]1350
[4589]1351        if (rtts->getStateGraphList().size()==0 && rtts->getRenderBinList().size()==0)
[4332]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        {
[5757]1362            case osg::Camera::PRE_RENDER:
[5524]1363                getCurrentRenderBin()->getStage()->addPreRenderStage(rtts.get(),camera.getRenderOrderNum());
[4332]1364                break;
[5524]1365            default:
1366                getCurrentRenderBin()->getStage()->addPostRenderStage(rtts.get(),camera.getRenderOrderNum());
[4332]1367                break;
[4340]1368        }
[4332]1369
1370    }
[5821]1371   
[4333]1372    // restore the previous model view matrix.
1373    popModelViewMatrix();
1374
1375    // restore the previous model view matrix.
1376    popProjectionMatrix();
1377
[6688]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
[6224]1387    if (camera.getViewport()) popViewport();
1388
[7177]1389    // restore the previous traversal mask settings
1390    if (mustSetCullMask) setTraversalMask(savedTraversalMask);
1391
[5691]1392    // restore the previous cull settings
1393    setCullSettings(saved_cull_settings);
[4426]1394
[4332]1395    // pop the node's state off the render graph stack.   
1396    if (node_state) popStateSet();
1397
1398}
1399
[730]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
[772]1404    disableAndPushOccludersCurrentMask(_nodePath);
[730]1405   
[42]1406
[772]1407    if (isCulled(node))
1408    {
1409        popOccludersCurrentMask(_nodePath);
1410        return;
1411    }
[747]1412
[730]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();
[772]1429
1430    // pop the current mask for the disabled occluder
1431    popOccludersCurrentMask(_nodePath);
[730]1432}
1433
[7731]1434void CullVisitor::apply(osg::OcclusionQueryNode& node)
1435{
1436    if (isCulled(node)) return;
[730]1437
[7731]1438    // push the culling mode.
1439    pushCurrentMask();
[730]1440
[7731]1441    // push the node's state.
1442    StateSet* node_state = node.getStateSet();
1443    if (node_state) pushStateSet(node_state);
1444
1445
[8674]1446    osg::Camera* camera = getCurrentCamera();
1447   
[7731]1448    // If previous query indicates visible, then traverse as usual.
[11127]1449    if (node.getPassed( camera, *this ))
[7731]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.