root/OpenSceneGraph/trunk/src/osg/CollectOccludersVisitor.cpp @ 13041

Revision 13041, 7.9 kB (checked in by robert, 2 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/CollectOccludersVisitor>
14#include <osg/Transform>
15#include <osg/Switch>
16#include <osg/LOD>
17#include <osg/OccluderNode>
18#include <osg/Projection>
19
20#include <algorithm>
21
22using namespace osg;
23
24CollectOccludersVisitor::CollectOccludersVisitor():
25    NodeVisitor(COLLECT_OCCLUDER_VISITOR,TRAVERSE_ACTIVE_CHILDREN)
26{
27
28    setCullingMode(VIEW_FRUSTUM_CULLING|
29                   NEAR_PLANE_CULLING|
30                   FAR_PLANE_CULLING|
31                   SMALL_FEATURE_CULLING);
32
33    _minimumShadowOccluderVolume = 0.005f;
34    _maximumNumberOfActiveOccluders = 10;
35    _createDrawables = false;
36
37}
38
39CollectOccludersVisitor::~CollectOccludersVisitor()
40{
41}
42
43void CollectOccludersVisitor::reset()
44{
45    CullStack::reset();
46    _occluderSet.clear();
47}
48
49float CollectOccludersVisitor::getDistanceToEyePoint(const Vec3& pos, bool withLODScale) const
50{
51    if (withLODScale) return (pos-getEyeLocal()).length()*getLODScale();
52    else return (pos-getEyeLocal()).length();
53}
54
55float CollectOccludersVisitor::getDistanceToViewPoint(const Vec3& pos, bool withLODScale) const
56{
57    if (withLODScale) return (pos-getViewPointLocal()).length()*getLODScale();
58    else return (pos-getViewPointLocal()).length();
59}
60
61float CollectOccludersVisitor::getDistanceFromEyePoint(const Vec3& pos, bool withLODScale) const
62{
63    const Matrix& matrix = *_modelviewStack.back();
64    float dist = -(pos[0]*matrix(0,2)+pos[1]*matrix(1,2)+pos[2]*matrix(2,2)+matrix(3,2));
65
66    if (withLODScale) return dist*getLODScale();
67    else return dist*getLODScale();
68}
69
70void CollectOccludersVisitor::apply(osg::Node& node)
71{
72    if (isCulled(node)) return;
73
74    // push the culling mode.
75    pushCurrentMask();
76
77    handle_cull_callbacks_and_traverse(node);
78
79    // pop the culling mode.
80    popCurrentMask();
81}
82
83void CollectOccludersVisitor::apply(osg::Transform& node)
84{
85    if (isCulled(node)) return;
86
87    // push the culling mode.
88    pushCurrentMask();
89
90    ref_ptr<osg::RefMatrix> matrix = createOrReuseMatrix(*getModelViewMatrix());
91    node.computeLocalToWorldMatrix(*matrix,this);
92    pushModelViewMatrix(matrix.get(), node.getReferenceFrame());
93
94    handle_cull_callbacks_and_traverse(node);
95
96    popModelViewMatrix();
97
98    // pop the culling mode.
99    popCurrentMask();
100}
101
102void CollectOccludersVisitor::apply(osg::Projection& node)
103{
104    if (isCulled(node)) return;
105
106    // push the culling mode.
107    pushCurrentMask();
108
109    ref_ptr<osg::RefMatrix> matrix = createOrReuseMatrix(node.getMatrix());
110    pushProjectionMatrix(matrix.get());
111
112    handle_cull_callbacks_and_traverse(node);
113
114    popProjectionMatrix();
115
116    // pop the culling mode.
117    popCurrentMask();
118}
119
120void CollectOccludersVisitor::apply(osg::Switch& node)
121{
122    apply((Group&)node);
123}
124
125void CollectOccludersVisitor::apply(osg::LOD& node)
126{
127    if (isCulled(node)) return;
128
129    // push the culling mode.
130    pushCurrentMask();
131
132    handle_cull_callbacks_and_traverse(node);
133
134    // pop the culling mode.
135    popCurrentMask();
136}
137
138void CollectOccludersVisitor::apply(osg::OccluderNode& node)
139{
140    // need to check if occlusion node is in the occluder
141    // list, if so disable the appropriate ShadowOccluderVolume
142    disableAndPushOccludersCurrentMask(_nodePath);
143
144
145    if (isCulled(node))
146    {
147        popOccludersCurrentMask(_nodePath);
148        return;
149    }
150
151//    std::cout<<"CollectOccludersVisitor:: We have found an Occlusion node in frustum"<<&node<<std::endl;
152
153    // push the culling mode.
154    pushCurrentMask();
155
156
157    if (node.getOccluder())
158    {
159        // computeOccluder will check if the occluder is the view frustum,
160        // if it ins't then the it will return false, when in it will
161        // clip the occluder's polygons in clip space, then create occluder
162        // planes, all with their normals facing inward towards the volume,
163        // and then transform them back into projection space.
164        ShadowVolumeOccluder svo;
165        if (svo.computeOccluder(_nodePath, *node.getOccluder(), *this,_createDrawables))
166        {
167
168            if (svo.getVolume()>_minimumShadowOccluderVolume)
169            {
170                // need to test occluder against view frustum.
171                //std::cout << "    adding in Occluder"<<std::endl;
172                _occluderSet.insert(svo);
173            }
174            else
175            {
176                //std::cout << "    rejecting Occluder as its volume is too small "<<svo.getVolume()<<std::endl;
177            }
178        }
179    }
180
181    handle_cull_callbacks_and_traverse(node);
182
183    // pop the culling mode.
184    popCurrentMask();
185
186    // pop the current mask for the disabled occluder
187    popOccludersCurrentMask(_nodePath);
188}
189
190void CollectOccludersVisitor::removeOccludedOccluders()
191{
192    if (_occluderSet.empty()) return;
193
194    ShadowVolumeOccluderSet::iterator occludeeItr=_occluderSet.begin();
195
196    // skip the first element as this can't be occluded by anything else.
197    occludeeItr++;
198
199    // step through the rest of the occluders, remove occluders which are themselves occluded.
200    for(;
201        occludeeItr!=_occluderSet.end();
202        ++occludeeItr)
203    {
204
205        // search for any occluders that occlude the current occluder,
206        // we only need to test any occluder near the front of the set since
207        // you can't be occluder by something smaller than you.
208        ShadowVolumeOccluder& occludee = const_cast<ShadowVolumeOccluder&>(*occludeeItr);
209        ShadowVolumeOccluder::HoleList& holeList = occludee.getHoleList();
210
211        for(ShadowVolumeOccluderSet::iterator occluderItr=_occluderSet.begin();
212            occluderItr!=occludeeItr;
213            ++occluderItr)
214        {
215            // cast away constness of the std::set element since ShadowVolumeOccluder::contains() is non const,
216            // and the std::set is a const, just for the invariance of the operator <!! Ahhhhh. oh well the below
217            // should be robust since contains won't change the getVolume which is used by the operator <.  Honest,  :-)
218            ShadowVolumeOccluder* occluder = const_cast<ShadowVolumeOccluder*>(&(*occluderItr));
219            if (occluder->contains(occludee.getOccluder().getReferenceVertexList()))
220            {
221                // erase occluder from set.
222                // take a copy of the iterator then rewind it one element so to prevent invalidating the occludeeItr.
223                ShadowVolumeOccluderSet::iterator eraseItr = occludeeItr--;
224                _occluderSet.erase(eraseItr);
225                break;
226            }
227
228            // now check all the holes in the occludee against the occluder,
229            // do so in reverse order so that the iterators remain valid.
230            for(ShadowVolumeOccluder::HoleList::reverse_iterator holeItr=holeList.rbegin();
231                holeItr!=holeList.rend();
232                )
233            {
234                if (occluder->contains((*holeItr).getReferenceVertexList()))
235                {
236                    holeList.erase((++holeItr).base());
237                }
238                else
239                {
240                    ++holeItr;
241                }
242
243            }
244
245        }
246    }
247
248
249    if (_occluderSet.size()<=_maximumNumberOfActiveOccluders) return;
250
251    // move the iterator to the _maximumNumberOfActiveOccluders th occluder.
252    occludeeItr = _occluderSet.begin();
253    for(unsigned int i=0;i<_maximumNumberOfActiveOccluders;++i)
254        ++occludeeItr;
255
256    // discard last occluders.
257    _occluderSet.erase(occludeeItr,_occluderSet.end());
258
259}
Note: See TracBrowser for help on using the browser.