source: GTP/trunk/App/Demos/Vis/FriendlyCulling/src/CHCPlusPlusTraverser.cpp @ 2782

Revision 2782, 6.2 KB checked in by mattausch, 16 years ago (diff)
Line 
1#include "CHCPlusPlusTraverser.h"
2#include "RenderState.h"
3
4using namespace std;
5
6namespace CHCDemoEngine
7{
8
9
10CHCPlusPlusTraverser::CHCPlusPlusTraverser()
11{
12}
13
14
15void CHCPlusPlusTraverser::HandleQueryResult(OcclusionQuery *query)
16{
17        // wait until result available
18        const int visible = query->GetQueryResult() > mVisibilityThreshold;
19
20        // multiquery
21        if (query->GetSize() > 1)
22        {
23                // failed query: query individual nodes
24                if (visible)
25                {
26                        for (size_t i = 0; i < query->GetSize(); ++ i)
27                        {
28                                BvhNode *node = query->GetNodes()[i];
29                                OcclusionQuery *q = IssueOcclusionQuery(node, false);
30                                mQueryQueue.push(q);
31                        }
32                }
33                else // query successful: update classifications
34                {
35                        for (size_t i = 0; i < query->GetSize(); ++ i)
36                        {
37                                BvhNode *node = query->GetNodes()[i];
38                                node->IncTimesTestedInvisible();
39                                node->SetVisible(false);
40                        }
41
42                        mStats.mNumQueryCulledNodes += query->GetSize();
43                }
44        }
45        else // single query
46        {
47                BvhNode *node = query->GetFrontNode();
48
49                // failed query: query individual nodes
50                if (visible)
51                {
52                        // node was previously invisible
53                        if (!node->IsVisible())
54                        {
55                                // reset flag
56                                node->SetTimesTestedInvisible(0);
57                                node->SetAssumedVisibleFrameId(mFrameId + mAssumedVisibleFrames);
58                        }
59                        else
60                        {       // randomize first invokation
61                                node->SetAssumedVisibleFrameId(mFrameId + Random(mAssumedVisibleFrames + 1));
62                        }
63
64                        mBvh->MakeParentsVisible(node);
65                        TraverseNode(node);
66                }
67                else
68                {
69                        node->IncTimesTestedInvisible();
70                        ++ mStats.mNumQueryCulledNodes;
71                }
72
73                node->SetVisible(visible);
74        }
75}
76
77
78void CHCPlusPlusTraverser::Traverse()
79{
80        //-- PART 1: process finished occlusion queries
81        while (!mDistanceQueue.empty() || !mQueryQueue.empty())
82        {
83                bool resultAvailable = false;
84                while (!mQueryQueue.empty() &&
85                           (mDistanceQueue.empty() || (resultAvailable = mQueryQueue.front()->ResultAvailable())))
86                {
87                        while (!resultAvailable && !mVQueue.empty())
88                        {
89                                BvhNode *node = mVQueue.front();
90                                mVQueue.pop();
91                               
92                                OcclusionQuery *query = IssueOcclusionQuery(node, true);
93
94                                mQueryQueue.push(query);
95                                resultAvailable = mQueryQueue.front()->ResultAvailable();
96                        }
97                       
98                        OcclusionQuery *query = mQueryQueue.front();
99                        mQueryQueue.pop();
100
101                        HandleQueryResult(query);
102                }       
103
104                //-- PART 2: hierarchical traversal
105                if (!mDistanceQueue.empty())
106                {
107                        BvhNode *node = mDistanceQueue.top();
108                        mDistanceQueue.pop();
109       
110                        if (mBvh->IsWithinViewFrustum(node))
111                        {
112                                // for near plane intersecting bounding box possible
113                                // wrong results => skip occlusion query
114                                if (IntersectsNearPlane(node))
115                                {
116                                        // update node's visited flag
117                                        node->SetLastVisitedFrame(mFrameId);
118                                        node->SetVisible(true);
119                                        mBvh->MakeParentsVisible(node);
120
121                                        TraverseNode(node);
122                                }
123                                else
124                                {               
125                                        // identify previously visible nodes
126                                        const bool wasVisible = node->IsVisible() && (node->GetLastVisitedFrame() == mFrameId - 1);
127                                       
128                                        // identify nodes that we cannot skip queries for
129                                        const bool testFeasible = (!wasVisible || (node->IsVirtualLeaf() &&
130                                                (node->GetAssumedVisibleFrameId() <= mFrameId)));
131
132                                        // node was not recently tested => reset flag
133                                        if (node->GetLastVisitedFrame() != mFrameId - 1)
134                                                node->SetTimesTestedInvisible(0);
135
136                                        // update node's visited flag
137                                        node->SetLastVisitedFrame(mFrameId);
138                                       
139                                        // skip testing previously visible interior nodes
140                                        if (testFeasible)
141                                        {
142                                                if (!wasVisible)
143                                                {
144                                                        QueryPreviouslyInvisibleNodes(node);
145                                                }
146                                                else
147                                                {
148                                                        mVQueue.push(node);
149                                                }
150                                        }
151                                        else
152                                        {
153                                                if (node->IsVirtualLeaf())
154                                                {
155                                                        node->SetVisible(true);
156                                                        mBvh->MakeParentsVisible(node);
157                                                }
158                                                else // reset visibility classification
159                                                {
160                                                        node->SetVisible(false);
161                                                }
162                                        }
163                                       
164                                        // always traverse a node if it was previously visible
165                                        if (wasVisible)
166                                                TraverseNode(node);
167                                }
168                        }
169                        else
170                        {
171                                // for stats
172                                ++ mStats.mNumFrustumCulledNodes;
173                        }
174                }
175
176                // distance queue empty: feed the remaining multiqueries to
177                // be able to proceed traversal
178                if (mDistanceQueue.empty())
179                {
180                        IssueMultiQueries();
181                }
182        }
183
184        // render the rest of the objects
185        if (mUseRenderQueue)
186        {
187                if (mRenderState->SetState(RenderState::RENDER))
188                        ++ mStats.mNumStateChanges;
189
190                mRenderQueue.Render();
191                mRenderQueue.Clear();
192        }
193
194
195        //////////////
196        //-- issue remaining previously visible node queries
197
198        while (!mVQueue.empty())
199        {
200                BvhNode *node = mVQueue.front();
201                mVQueue.pop();
202
203                OcclusionQuery *query = IssueOcclusionQuery(node, true);
204                mQueryQueue.push(query);
205        }
206
207        while (!mQueryQueue.empty())
208        {
209                OcclusionQuery *query = mQueryQueue.front();
210                mQueryQueue.pop();
211
212                HandleQueryResult(query);
213        }
214}
215
216
217
218void CHCPlusPlusTraverser::QueryPreviouslyInvisibleNodes(BvhNode *node)
219{
220        mIQueue.push(node);
221
222        if (mIQueue.size() > mMaxBatchSize)
223        {
224                IssueMultiQueries();
225        }
226}
227
228
229OcclusionQuery * CHCPlusPlusTraverser::GetNextMultiQuery(BvhNodeQueue &iqueue)
230{
231        OcclusionQuery *query = mQueryHandler.RequestQuery();
232
233        float pFail = 1.0f;
234        float maxBatchVal = 0.0f;
235        float newPBatch = 1.0f;
236        float newBatchVal;
237
238        // issue next query
239        while (!iqueue.empty())
240        {
241                BvhNode *node = iqueue.front();
242                newPBatch *= mVisibilityPredictor.GetProbability(node);
243
244                if (query->GetNodes().empty())
245                {
246                        // single node will anever cause a wasted query
247                        newBatchVal = 1.0f;
248                }
249                else
250                {
251                        int newSize = query->GetSize() + 1;
252                        newBatchVal = newSize / (1.0f + (1.0f - newPBatch) * newSize);
253                }
254
255                if (newBatchVal <= maxBatchVal)
256                        break;
257
258                iqueue.pop();
259                query->AddNode(node);
260
261                maxBatchVal = newBatchVal;
262        }
263
264        //cout <<"size: " << query->GetSize() << endl;
265        IssueOcclusionQuery(*query, false);
266
267        return query;
268}
269
270
271void CHCPlusPlusTraverser::IssueMultiQueries()
272{
273        while (!mIQueue.empty())
274        {
275                OcclusionQuery *query;
276
277                if (mUseMultiQueries)
278                {
279                        query = GetNextMultiQuery(mIQueue);
280                }
281                else
282                {
283                        BvhNode *node = mIQueue.front();
284                        mIQueue.pop();
285                        query = IssueOcclusionQuery(node, false);
286                }
287
288                mQueryQueue.push(query);
289        }
290}
291
292
293}
Note: See TracBrowser for help on using the repository browser.