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

Revision 2850, 6.6 KB checked in by mattausch, 16 years ago (diff)

debug version before siggraph

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