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

Revision 3258, 7.0 KB checked in by mattausch, 15 years ago (diff)

worked on new method

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
30                                mIQueue.push_back(node);
31                                node->SetLastQueriedFrame(mFrameId);
32                        }
33                }
34                else // query successful: update classifications
35                {
36                        for (size_t i = 0; i < query->GetSize(); ++ i)
37                        {
38                                BvhNode *node = query->GetNodes()[i];
39                                node->IncTimesTestedInvisible();
40                                node->SetVisible(false);
41                                node->SetLastQueriedFrame(mFrameId);
42                        }
43
44                        mStats.mNumQueryCulledNodes += query->GetSize();
45                }
46        }
47        else // single query
48        {
49                BvhNode *node = query->GetFrontNode();
50
51                node->SetLastQueriedFrame(mFrameId);
52
53                // failed query: query individual nodes
54                if (visible)
55                {
56                        // node was previously invisible
57                        if (!node->IsVisible())
58                        {
59                                // reset flag
60                                node->SetTimesTestedInvisible(0);
61                                node->SetAssumedVisibleFrameId(mFrameId + mAssumedVisibleFrames);
62                        }
63                        else
64                        {       // randomize first invokation
65                                node->SetAssumedVisibleFrameId(mFrameId + Random(mAssumedVisibleFrames + 1));
66                        }
67
68                        mBvh->MakeParentsVisible(node);
69                        TraverseNode(node);
70                }
71                else
72                {
73                        node->IncTimesTestedInvisible();
74                        ++ mStats.mNumQueryCulledNodes;
75                }
76
77                node->SetVisible(visible);
78        }
79}
80
81
82void CHCPlusPlusTraverser::Traverse()
83{
84        int waitedForQueries = 0;
85        int returnedQueries = 0;
86
87        //-- PART 1: process finished occlusion queries
88        while (!mDistanceQueue.empty() || !mQueryQueue.empty())
89        {
90                bool resultAvailable = false;
91
92                while (!mQueryQueue.empty() &&
93                           (mDistanceQueue.empty() || (resultAvailable = mQueryQueue.front()->ResultAvailable())))
94                {
95                        while (!resultAvailable && !mVQueue.empty())
96                        {
97                                BvhNode *node = mVQueue.front();
98                                mVQueue.pop();
99                               
100                                OcclusionQuery *query = IssueOcclusionQuery(node);
101
102                                mQueryQueue.push(query);
103                                resultAvailable = mQueryQueue.front()->ResultAvailable();
104                        }
105                       
106                        //++ returnedQueries; if (!resultAvailable) ++ waitedForQueries;
107                       
108                        OcclusionQuery *query = mQueryQueue.front();
109                        mQueryQueue.pop();
110
111                        // waiting for query result
112                        HandleQueryResult(query);
113                }       
114
115                //-- PART 2: hierarchical traversal
116                if (!mDistanceQueue.empty())
117                {
118                        BvhNode *node = mDistanceQueue.top();
119                        mDistanceQueue.pop();
120       
121                        if (1 && !IsNodeGeometryVisible(node, 10))
122                        {
123                                node->SetVisible(false);
124                                continue;
125                        }
126                       
127                        if (mBvh->IsWithinViewFrustum(node))
128                        {
129                                // for near plane intersecting bounding box possible
130                                // wrong results => skip occlusion query
131                                if (mBvh->IntersectsNearPlane(node))
132                                {
133                                        // update node's visited flag
134                                        node->SetLastVisitedFrame(mFrameId);
135                                        node->SetVisible(true);
136                                        mBvh->MakeParentsVisible(node);
137
138                                        TraverseNode(node);
139                                }
140                                else
141                                {               
142                                        // identify previously visible nodes
143                                        const bool wasVisible = node->IsVisible() && (node->GetLastVisitedFrame() == mFrameId - 1);
144                                       
145                                        // identify nodes that we cannot skip queries for
146                                        const bool queryFeasible = (!wasVisible || (node->IsVirtualLeaf() &&
147                                                (node->GetAssumedVisibleFrameId() <= mFrameId)));
148
149                                        // node was not recently tested => reset flag
150                                        if (node->GetLastVisitedFrame() != mFrameId - 1)
151                                        {
152                                                node->SetTimesTestedInvisible(0);
153                                        }
154
155                                        // update node's visited flag
156                                        node->SetLastVisitedFrame(mFrameId);
157                                       
158                                        // skip testing previously visible interior nodes
159                                        if (queryFeasible)
160                                        {
161                                                if (!wasVisible)
162                                                {
163                                                        QueryPreviouslyInvisibleNodes(node);
164                                                }
165                                                else
166                                                {
167                                                        mVQueue.push(node);
168                                                }
169                                        }
170                                        else
171                                        {
172                                                // node is leaf => set to visible
173                                                if (node->IsVirtualLeaf())
174                                                {
175                                                        node->SetVisible(true);
176                                                        mBvh->MakeParentsVisible(node);
177                                                }
178                                                else // reset visibility classification
179                                                {
180                                                        node->SetVisible(false);
181                                                }
182                                        }
183                                       
184                                        // always traverse a node if it was previously visible
185                                        if (wasVisible)
186                                        {
187                                                TraverseNode(node);
188                                        }
189                                }
190                        }
191                        else
192                        {
193                                // for stats
194                                ++ mStats.mNumFrustumCulledNodes;
195                        }
196                }
197
198                // distance queue empty: feed the remaining multiqueries to
199                // be able to proceed traversal
200                if (mDistanceQueue.empty())
201                {
202                        IssueMultiQueries();
203                }
204        }
205
206        // render the rest of the objects
207        if (mUseRenderQueue) ApplyRenderQueue();
208
209
210        //////////////
211        //-- issue remaining previously visible node queries
212
213        while (!mVQueue.empty())
214        {
215                BvhNode *node = mVQueue.front();
216                mVQueue.pop();
217
218                OcclusionQuery *query = IssueOcclusionQuery(node);
219                mQueryQueue.push(query);
220        }
221
222        while (!mQueryQueue.empty())
223        {
224                OcclusionQuery *query = mQueryQueue.front();
225                mQueryQueue.pop();
226
227                HandleQueryResult(query);
228        }
229
230        //cout << "returned queries: " << returnedQueries << " waited for queries: " << waitedForQueries << " (=" << 100.0f * waitedForQueries / returnedQueries << "%)" << endl;
231}
232
233
234void CHCPlusPlusTraverser::QueryPreviouslyInvisibleNodes(BvhNode *node)
235{
236        mIQueue.push_back(node);
237
238        if (mIQueue.size() > mMaxBatchSize)
239        {
240                IssueMultiQueries();
241        }
242}
243
244
245OcclusionQuery * CHCPlusPlusTraverser::GetNextMultiQuery(BvhNodeContainer &iqueue)
246{
247        OcclusionQuery *query = mQueryHandler.RequestQuery();
248
249        float pFail = 1.0f;
250        float maxBatchVal = 0.0f;
251        float newPBatch = 1.0f;
252        float newBatchVal;
253
254        // issue next query
255        while (!iqueue.empty())
256        {
257                BvhNode *node = iqueue.back();
258
259                // node was already part of a mulitquery => avoid recursion
260                if (node->GetLastQueriedFrame() == mFrameId)
261                        newPBatch = 0;
262                else
263                        newPBatch *= mVisibilityPredictor.GetProbability(node);
264
265                if (query->GetNodes().empty())
266                {
267                        // single node will never cause a wasted query
268                        newBatchVal = 1.0f;
269                }
270                else
271                {
272                        int newSize = query->GetSize() + 1;
273                        newBatchVal = newSize / (1.0f + (1.0f - newPBatch) * newSize);
274                }
275
276                if (newBatchVal <= maxBatchVal)
277                        break;
278
279                iqueue.pop_back();
280                query->AddNode(node);
281
282                maxBatchVal = newBatchVal;
283        }
284
285        //cout <<"size: " << query->GetSize() << endl;
286        IssueOcclusionQuery(*query);
287
288        return query;
289}
290
291
292static inline bool lt(BvhNode *a, BvhNode *b)
293{
294        return a->GetTimesTestedInvisible() < b->GetTimesTestedInvisible();
295}
296
297
298void CHCPlusPlusTraverser::IssueMultiQueries()
299{
300        if (mUseMultiQueries)
301        {
302                // sort queries by #times invisible
303                sort(mIQueue.begin(), mIQueue.end(), lt);
304
305                while (!mIQueue.empty())
306                        mQueryQueue.push(GetNextMultiQuery(mIQueue));
307        }
308        else
309        {
310                BvhNodeContainer::const_iterator it, it_end = mIQueue.end();
311
312                for (it = mIQueue.begin(); it != it_end; ++ it)
313                        mQueryQueue.push(IssueOcclusionQuery(*it));
314
315                mIQueue.clear();
316        }
317}
318
319
320}
Note: See TracBrowser for help on using the repository browser.