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

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

played around with pvs. now using pvs without vfc or anything. using function that allows to skip tree at some point

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 && !IsNodeVisible(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.