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

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