source: GTP/trunk/App/Demos/Vis/CHC_revisited/CHCPlusPlusTraverser.cpp @ 2774

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