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

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

Ran script to remove trailing spaces and tabs

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