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

Revision 11046, 45.7 kB (checked in by robert, 5 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
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.
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.