source: GTP/trunk/Lib/Vis/OnlineCullingCHC/src/CoherentHierarchicalCullingPlusPlusManager.cpp @ 2561

Revision 2561, 11.5 KB checked in by mattausch, 17 years ago (diff)
Line 
1#include "CoherentHierarchicalCullingPlusPlusManager.h"
2#include "CullingLogManager.h"
3
4#include <time.h>
5#include <sstream>
6
7
8
9namespace GtpVisibility {
10
11
12static const bool CULL_INVALID_NODES = true;
13//static const bool CULL_INVALID_NODES = false;
14static const int MAX_INVISIBLE_NODES_SIZE = 20;
15
16//-----------------------------------------------------------------------
17CoherentHierarchicalCullingPlusPlusManager::CoherentHierarchicalCullingPlusPlusManager():
18mAssumedVisibility(0), mMaxInvisibleNodesSize(MAX_INVISIBLE_NODES_SIZE)
19{
20}
21//-----------------------------------------------------------------------
22CoherentHierarchicalCullingPlusPlusManager::CoherentHierarchicalCullingPlusPlusManager(
23                                                                                                                const unsigned int assumedVisibility):
24mAssumedVisibility(assumedVisibility), mMaxInvisibleNodesSize(MAX_INVISIBLE_NODES_SIZE)
25{
26}
27//-----------------------------------------------------------------------
28void CoherentHierarchicalCullingPlusPlusManager::AssignAssumedVisibility(GtpVisibility::HierarchyNode *node)
29{
30        if (!mHierarchyInterface->IsNodeVisible(node))
31                // previously invisible nodes: give random offset just for the first test after
32                // becoming visible to avoid that all nodes are tested in the same frame
33                mHierarchyInterface->SetNodeAssumedVisible(node, rand() * mAssumedVisibility / RAND_MAX);
34        else
35                mHierarchyInterface->SetNodeAssumedVisible(node, mAssumedVisibility);
36}
37//-----------------------------------------------------------------------
38void CoherentHierarchicalCullingPlusPlusManager::RenderScene()
39{
40        if (0) CullingLogManager::GetSingleton()->LogMessage("chc++");
41       
42        unsigned int visiblePixels = 0;
43
44        /////////////
45        //-- PART 1: process finished occlusion queries
46
47        while (!mHierarchyInterface->GetQueue()->empty() || !mQueryQueue.empty()
48                   || !mInvisibleNodes.empty()
49                   //|| !mVisibleNodes.empty()
50                   )
51        {
52                //////////
53                //-- only wait for result if there are no nodes to process
54                bool resultAvailable = false;
55
56                while (
57                           !mQueryQueue.empty() &&
58                           (NodeInvalid(mQueryQueue.front().first) ||
59                           mHierarchyInterface->GetQueue()->empty() ||
60                           (resultAvailable = mQueryQueue.front().second->GetQueryResult(visiblePixels, false)))
61                           )
62                {
63                        HierarchyNode *node = mQueryQueue.front().first;
64
65                        // parent was tested invisible => remove children from queue
66                        // "invalid nodes" happen for hierarchies where interiors store geometry
67                        if (NodeInvalid(node)) {mQueryQueue.pop(); continue;}
68
69                        // during the wait time we issue nodes from visible queue
70                        while (!mVisibleNodes.empty() && !resultAvailable)
71                        {
72                                HierarchyNode *vn = mVisibleNodes.front();
73                                mVisibleNodes.pop();
74                                IssueQuery(vn, false);
75
76                                // check if result is already availalbe
77                                resultAvailable = mQueryQueue.front().second->GetQueryResult(visiblePixels, false);
78                        }
79
80                        if (!resultAvailable)
81                                mQueryQueue.front().second->GetQueryResult(visiblePixels, true);
82
83                        resultAvailable = false;
84                mQueryQueue.pop();
85
86                        // tested visible
87                        if (visiblePixels > mVisibilityThreshold)
88                        {
89                                // assing the #frames the node is assumed to stay visible
90                                AssignAssumedVisibility(node);
91
92                                // traverse node if not already traversed in this frame
93                                // (i.e., the visible flag is not set)
94                                // note: it is necessary to do this test because we query
95                                // previously visible interior node containing geometry without
96                                // waiting for the result
97                                if (!mHierarchyInterface->IsNodeVisible(node))
98                                        mHierarchyInterface->TraverseNode2(node);
99
100                                mHierarchyInterface->PullUpVisibility(node);
101                        }
102                        else
103                        {       
104                                mHierarchyInterface->SetNodeVisible(node, false);
105
106                                ++ mNumQueryCulledNodes;
107                               
108                                if (mVisualizeCulledNodes)
109                                        mHierarchyInterface->VisualizeCulledNode(node, QUERY_CULLED);
110                        }
111                       
112                        // update node's visited flag
113                        mHierarchyInterface->SetLastVisited(node, mHierarchyInterface->GetFrameId());   
114                }
115               
116                ////////////////
117                //-- PART 2: hierarchical traversal
118
119                if (!mHierarchyInterface->GetQueue()->empty())
120                {
121                        HierarchyNode *node = mHierarchyInterface->GetQueue()->top();
122                        mHierarchyInterface->GetQueue()->pop();
123                               
124                        // parent was tested invisible => remove children from queue
125                        if (NodeInvalid(node)) continue;
126
127                        bool intersects = false;
128
129                        if (!mHierarchyInterface->CheckFrustumVisible(node, intersects))
130                        {
131                                ++ mNumFrustumCulledNodes;
132                               
133                                if (mVisualizeCulledNodes)
134                                        mHierarchyInterface->VisualizeCulledNode(node, FRUSTUM_CULLED);
135                        }
136                        else if (intersects)
137                        {
138                                //-- if node intersects near plane, skip query because wrong results possible
139                                SkipQuery(node);
140                        }
141                        else
142                        {
143                                // identify previously visible nodes
144                                bool wasVisible = mHierarchyInterface->IsNodeVisible(node) &&
145                                        (mHierarchyInterface->LastVisited(node) == mHierarchyInterface->GetFrameId() - 1);
146                               
147                                // if we assume node to be visible in this frame => skip query
148                                const bool skipQuery = wasVisible &&
149                                                                           DecideVisible(node) &&
150                                                                           mHierarchyInterface->HasGeometry(node);
151
152                                if (skipQuery)
153                                {
154                                        SkipQuery(node);
155                                        continue;
156                                }
157
158                // identify nodes that we cannot skip queries for
159                                // geometry not only in leaves => test for renderable geometry
160                                const bool issueQuery = !wasVisible || mHierarchyInterface->HasGeometry(node);
161                                                       
162                                // set node's visibility classification
163                                // we identify previously visible / invisible nodes in the query queue
164                                mHierarchyInterface->SetNodeVisible(node, wasVisible && issueQuery);
165
166                                if (issueQuery)
167                                {
168                                        ++ mNumQueriesIssued;
169
170                                        if (!wasVisible)
171                                        {
172                                                mInvisibleNodes.push_back(node);
173
174                                                if ((int)mInvisibleNodes.size() >= mMaxInvisibleNodesSize)
175                                                {
176                                                        mHierarchyInterface->RenderQueue();
177                                                        // issue the batched queries
178                                                        IssueBatchedQuery(mInvisibleNodes);
179                                                }
180                                        }
181                                        else
182                                        {
183                                                // mVisibleNodes.push(node);
184                                                IssueQuery(node, false);
185                                        }
186                                }
187                                else
188                                {
189                                        // skip testing previously visible nodes without geometry
190                    // just update node's visited flag
191                                        mHierarchyInterface->SetLastVisited(node, mHierarchyInterface->GetFrameId());
192                                }
193                               
194                                // always traverse a node if it was visible
195                                if (wasVisible)
196                                {
197                                        mHierarchyInterface->TraverseNode2(node);
198                                }
199                        }
200                }
201
202                  // issue rest of nodes from nodes from invisible queue
203                if (mHierarchyInterface->GetQueue()->empty() && !mInvisibleNodes.empty())
204                {
205                        if (0)
206                        {
207                                std::stringstream d;
208                                d << "inv nodes: " << (int)mInvisibleNodes.size();
209                                CullingLogManager::GetSingleton()->LogMessage(d.str());
210                        }
211                       
212                        mHierarchyInterface->RenderQueue();
213                        IssueBatchedQuery(mInvisibleNodes);
214                }
215
216        // issue rest of nodes from nodes from visible queue
217                if (0 &&
218                        mHierarchyInterface->GetQueue()->empty() && mQueryQueue.empty() && !mVisibleNodes.empty())
219                {
220                        while (!mVisibleNodes.empty())
221                        {
222                                IssueQuery(mVisibleNodes.front(), false);
223                                mVisibleNodes.pop();
224                        }
225                }
226        }
227       
228    // render what is left in the render queue
229        mHierarchyInterface->RenderQueue();
230
231        // issue rest of nodes from nodes from visible queue
232        while (!mVisibleNodes.empty())
233        {
234                IssueQuery(mVisibleNodes.front(), false);
235                mVisibleNodes.pop();
236        }
237
238        int i = 0;
239
240        while (!mQueryQueue.empty() &&
241                    mQueryQueue.front().second->GetQueryResult(visiblePixels, true))
242        {
243                ++ i;
244
245                HierarchyNode *node = mQueryQueue.front().first;
246                mQueryQueue.pop();
247
248                // tested visible
249                if (visiblePixels > mVisibilityThreshold)
250                {
251                        // assing the #frames the node is assumed to stay visible
252                        AssignAssumedVisibility(node);
253                        mHierarchyInterface->PullUpVisibility(node);
254                }
255                else
256                {       
257                        mHierarchyInterface->SetNodeVisible(node, false);
258
259                        ++ mNumQueryCulledNodes;
260
261                        if (mVisualizeCulledNodes)
262                                mHierarchyInterface->VisualizeCulledNode(node, QUERY_CULLED);
263                }
264
265                // update node's visited flag
266                mHierarchyInterface->SetLastVisited(node, mHierarchyInterface->GetFrameId());   
267        }
268}
269//-----------------------------------------------------------------------
270void CoherentHierarchicalCullingPlusPlusManager::SetAssumedVisibility(const unsigned int assumedVisibility)
271{
272        mAssumedVisibility = assumedVisibility;
273}
274//-----------------------------------------------------------------------
275inline bool CoherentHierarchicalCullingPlusPlusManager::DecideVisible(HierarchyNode *node) const
276{
277        mHierarchyInterface->DecNodeAssumedVisible(node);
278        //std::stringstream d; d << "node visible: " << mHierarchyInterface->GetNodeAssumedVisible(node);
279        //CullingLogManager::GetSingleton()->LogMessage(d.str());
280        return mHierarchyInterface->GetNodeAssumedVisible(node) > 0;
281}
282//-----------------------------------------------------------------------
283inline void CoherentHierarchicalCullingPlusPlusManager::SkipQuery(HierarchyNode *node) const
284{
285        //-- set node to be visible in this frame, then traverse it
286        mHierarchyInterface->SetLastVisited(node, mHierarchyInterface->GetFrameId());
287
288        mHierarchyInterface->PullUpVisibility(node);                   
289        mHierarchyInterface->TraverseNode2(node);
290}
291//-----------------------------------------------------------------------
292inline bool CoherentHierarchicalCullingPlusPlusManager::NodeInvalid(HierarchyNode *node) const
293{
294        if (!CULL_INVALID_NODES) return false;
295
296        // parent was tested invisible in this frame
297    const bool nodeInvalid = (
298                 mHierarchyInterface->GetParent(node) &&
299                 (mHierarchyInterface->LastVisited(node) == mHierarchyInterface->GetFrameId()) &&
300                 !mHierarchyInterface->IsNodeVisible(mHierarchyInterface->GetParent(node))
301         );
302
303        return nodeInvalid;
304}
305//-----------------------------------------------------------------------
306void CoherentHierarchicalCullingPlusPlusManager::SetTestGeometryForVisibleLeaves(const bool testGeometry)
307{
308        mTestGeometryForVisibleLeaves = testGeometry;
309}
310//-----------------------------------------------------------------------
311bool CoherentHierarchicalCullingPlusPlusManager::GetTestGeometryForVisibleLeaves()
312{
313        return mTestGeometryForVisibleLeaves;
314}
315//-----------------------------------------------------------------------
316inline void CoherentHierarchicalCullingPlusPlusManager::IssueQuery(HierarchyNode *node,
317                                                                                                                                   const bool queryGeometry)
318{
319        mQueryQueue.push(QueryPair(node, mHierarchyInterface->
320                IssueNodeOcclusionQuery(node, queryGeometry)));
321}
322//-----------------------------------------------------------------------
323void CoherentHierarchicalCullingPlusPlusManager::IssueBatchedQuery(HierarchyNodeContainer &nodes)
324{
325        HierarchyNodeContainer::const_iterator nit, nit_end = nodes.end();
326
327        for (nit = nodes.begin(); nit != nit_end; ++ nit)
328                IssueQuery(*nit, false);
329
330        //for (int i = (int)nodes.size() - 1; i >= 0; -- i)
331        //      IssueQuery(nodes[i], false);
332
333        nodes.clear();
334}
335//-----------------------------------------------------------------------
336#if 0
337void CoherentHierarchicalCullingPlusPlusManager::IssueOptimalBatches(QueryHeap &nodes)
338{
339        while (!nodes.Empty())
340        {       
341                QueryQueueEntry *entry = GetNextQueryQueueEntry();
342                entry->mIsVisibleQuery = false;
343       
344                float pFail = 1.0f;
345                float maxBatchVal = 0.0f;
346                float newPBatch = 1.0f;
347                float newBatchVal;
348               
349                // issue next query
350                while (!nodes.Empty())
351                {
352                        HierarchyNode *node = nodes.Top();
353       
354                        newPBatch *= mNodePredictor.GetProbability(node);
355
356                        if (entry->mNodes.empty())
357                                newBatchVal = 1.0f;
358                        else
359                        {
360                                const float newSize = float(entry->mNodes.size() + 1);
361                                newBatchVal = newSize / (1.0f + (1.0f - newPBatch) * newSize);
362                        }
363
364                        if (newBatchVal <= maxBatchVal)
365                                break;
366
367                        pFail = entry->mNodes.empty() ? 0.0f : (1.0f - newPBatch);
368
369                        nodes.Pop();
370                        entry->AddNode(node);
371
372                        maxBatchVal = newBatchVal;
373                }
374
375                entry->mPFail = pFail;
376
377                IssueQuery(*entry, false);
378                mQueries.push(entry);
379        }
380}
381#endif
382}
Note: See TracBrowser for help on using the repository browser.