source: GTP/trunk/App/Demos/Vis/CHC_revisited/RenderTraverser.cpp @ 2642

Revision 2642, 11.4 KB checked in by mattausch, 16 years ago (diff)

new demo

Line 
1#include "RenderTraverser.h"
2#include "glInterface.h"
3#include "Timers.h"
4
5/*extern "C"
6{
7        #include "MathStuff.h"
8}*/
9
10
11RenderTraverser::RenderTraverser():
12mFrameID(1),
13mVisibilityThreshold(0),
14mHierarchyRoot(NULL),
15mOcclusionQueries(NULL),
16mCurrentQueryIdx(0),
17mIsQueryMode(false),
18mNumTraversedNodes(0),
19mNumQueryCulledNodes(0),
20mNumFrustumCulledNodes(0),
21mRenderTime(0),
22mNumRenderedGeometry(0),
23mUseOptimization(true),
24mUseArbQueries(false)
25{
26}
27
28
29RenderTraverser::~RenderTraverser()
30{
31        DelQueries();
32}
33
34
35void RenderTraverser::Render(int mode)
36{
37        mDistanceQueue.push(mHierarchyRoot);
38
39        long startTime = getTime();
40
41        Preprocess();
42
43        switch(mode)
44        {
45                case RENDER_CULL_FRUSTUM:
46                        RenderCullFrustum();
47            break;
48                case RENDER_STOP_AND_WAIT:
49                        RenderStopAndWait();
50                        break;
51                case RENDER_COHERENT:
52                        RenderCoherentWithQueue();
53                        break;
54                default:
55                        RenderCullFrustum();
56                        break;
57        }
58
59        mFrameID ++;
60       
61
62        long endTime = getTime();
63        mRenderTime = endTime - startTime;
64
65        finishTiming();
66}
67
68/**
69        This is the standard render traversal algorithm doing only frustum culling
70*/
71void RenderTraverser::RenderCullFrustum()
72{
73        while(!mDistanceQueue.empty())
74        {
75                HierarchyNode *node = mDistanceQueue.top();
76                mDistanceQueue.pop();
77       
78                // interesting for the visualization, so rest and set
79                node->SetVisible(false);
80                mNumTraversedNodes ++;
81
82                bool intersects;
83       
84                if(InsideViewFrustum(node, intersects))
85                {
86                        // update node's visited flag => needed for rendering
87                        // so set it also here
88                        node->SetLastVisited(mFrameID);
89                        node->SetVisible(true);
90                        TraverseNode(node);
91                }
92                else
93                {
94                        mNumFrustumCulledNodes ++;
95                }
96        }
97}
98
99void RenderTraverser::RenderStopAndWait()
100{
101        while(! mDistanceQueue.empty())
102        {
103                HierarchyNode *node = mDistanceQueue.top();
104                mDistanceQueue.pop();
105                mNumTraversedNodes ++;
106                // interesting for the visualization, so rest and set
107                node->SetVisible(false);
108
109                bool intersects;
110               
111                if(InsideViewFrustum(node, intersects))
112                {
113                        // update node's visited flag
114                        node->SetLastVisited(mFrameID);
115
116                        // for near plane intersecting abbs possible
117                        // wrong results => skip occlusion query
118                        if(intersects)
119                        {
120                                node->SetVisible(true);
121                                TraverseNode(node);
122                        }
123                        else
124                        {
125                                IssueOcclusionQuery(node, false);
126                               
127                                // wait if result not available
128                                int visiblePixels = GetOcclusionQueryResult(node);
129                               
130                                // node visible
131                                if(visiblePixels > mVisibilityThreshold)
132                                {
133                                        node->SetVisible(true);
134                                        TraverseNode(node);
135                                }
136                                else
137                                {
138                                        mNumQueryCulledNodes ++;
139                                }
140                        }                                       
141                }
142                else
143                {
144                        mNumFrustumCulledNodes ++;
145                }
146        }
147}
148
149void RenderTraverser::RenderCoherentWithQueue()
150{
151        QueryQueue queryQueue;
152
153        //-- PART 1: process finished occlusion queries
154        while (!mDistanceQueue.empty() || !queryQueue.empty())
155        {
156                while (!queryQueue.empty() &&
157                           (ResultAvailable(queryQueue.front()) || mDistanceQueue.empty()))
158                {
159                        HierarchyNode *node = queryQueue.front();
160                        queryQueue.pop();
161                       
162                        // wait until result available
163                        int visiblePixels = GetOcclusionQueryResult(node);
164
165                        if(visiblePixels > mVisibilityThreshold)
166                        {
167                                PullUpVisibility(node);
168                                TraverseNode(node);
169                        }
170                        else
171                        {
172                                mNumQueryCulledNodes ++;
173                        }
174                }       
175
176                //-- PART 2: hierarchical traversal
177                if (!mDistanceQueue.empty())
178                {
179                        HierarchyNode *node = mDistanceQueue.top();
180
181                        mDistanceQueue.pop();
182       
183                        mNumTraversedNodes ++;
184
185                        bool intersects;
186                       
187                        if (InsideViewFrustum(node, intersects))
188                        {
189                                // for near plane intersecting bounding box possible
190                                // wrong results => skip occlusion query
191                                if(intersects)
192                                {
193                                        // update node's visited flag
194                                        node->SetLastVisited(mFrameID);
195                                        node->SetVisible(true);
196                                        PullUpVisibility(node);
197                                        TraverseNode(node);
198                                }
199                                else
200                                {               
201                                        // identify previously visible nodes
202                                        bool wasVisible = node->Visible() && (node->LastVisited() == mFrameID - 1);
203                                       
204                                        // identify nodes that we cannot skip queries for
205                                        bool leafOrWasInvisible = (node->LastVisited() != mFrameID) && (!wasVisible || node->IsLeaf());
206
207                                        // reset node's visibility classification
208                                        node->SetVisible(false);
209
210                                        // update node's visited flag
211                                        node->SetLastVisited(mFrameID);
212                                       
213                                        // skip testing previously visible interior nodes
214                                        if(leafOrWasInvisible)
215                                        {
216                                                IssueOcclusionQuery(node, wasVisible);
217                                                queryQueue.push(node);
218                                        }
219                                       
220                                        // always traverse a node if it was visible
221                                        if(wasVisible)
222                                                TraverseNode(node);
223                                }
224                        }
225                        else
226                        {
227                                // for stats
228                                mNumFrustumCulledNodes ++;
229                        }
230                }
231        }
232}
233       
234void RenderTraverser::TraverseNode(HierarchyNode *node)
235{
236        if(node->IsLeaf())
237                mNumRenderedGeometry += node->Render();
238        else
239        {
240                // for non leafs this renders only the bounding volume (if the flag is set)
241                //node->Render();
242                mDistanceQueue.push(node->GetLeftChild());
243                mDistanceQueue.push(node->GetRightChild());
244        }
245}
246
247void RenderTraverser::RenderVisualization()
248{
249        mDistanceQueue.push(mHierarchyRoot);
250
251        while(! mDistanceQueue.empty())
252        {
253                HierarchyNode *node = mDistanceQueue.top();
254                mDistanceQueue.pop();
255
256                // identify previously visible nodes
257                bool wasVisible = node->Visible() && (node->LastVisited() == mFrameID - 1);
258
259                if(wasVisible)
260                        TraverseNode(node);
261                else
262                {
263                        // also render culled nodes
264                        glColor3f(1.0,0.0,0.0);
265                        node->RenderBoundingVolumeForVisualization();           
266                }
267        }
268}
269
270
271void RenderTraverser::PullUpVisibility(HierarchyNode *node)
272{
273        while(node && !node->Visible())
274        {
275                node->SetVisible(true);
276                node = node->GetParent();
277        }
278}
279
280bool RenderTraverser::ResultAvailable(HierarchyNode *node) const
281{
282        unsigned int result;
283        if (mUseArbQueries)
284        {
285                glGetQueryObjectuivARB(node->GetOcclusionQuery(),
286                                                           GL_QUERY_RESULT_AVAILABLE_ARB, &result);
287        }
288        else
289        {
290               
291                glGetOcclusionQueryuivNV(node->GetOcclusionQuery(),
292                                                                 GL_PIXEL_COUNT_AVAILABLE_NV, &result);
293
294        }
295       
296        return (result == GL_TRUE);
297}
298
299void RenderTraverser::SetHierarchy(HierarchyNode *sceneRoot)
300{
301        mHierarchyRoot = sceneRoot;
302
303        DelQueries();
304}
305
306HierarchyNode *RenderTraverser::GetHierarchy()
307{
308        return mHierarchyRoot;
309}
310
311unsigned int RenderTraverser::GetOcclusionQueryResult(HierarchyNode *node) const
312{
313        unsigned int result;
314
315        if (mUseArbQueries)
316        {
317                glGetQueryObjectuivARB(node->GetOcclusionQuery(), GL_QUERY_RESULT_ARB, &result);
318        }
319        else
320        {
321                glGetOcclusionQueryuivNV(node->GetOcclusionQuery(), GL_PIXEL_COUNT_NV, &result);
322        }
323
324        return result;
325}
326
327
328void RenderTraverser::Switch2GLQueryState()
329{       
330        // boolean used to avoid unnecessary state changes
331        if(!mIsQueryMode)
332        {
333                glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
334                glDepthMask(GL_FALSE);
335                glDisable(GL_LIGHTING);
336                mIsQueryMode = true;
337        }
338}
339
340
341void RenderTraverser::Switch2GLRenderState()
342{
343        // boolean used to avoid unnecessary state changes
344        if(mIsQueryMode)
345        {
346                // switch back to rendermode           
347                glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
348                glDepthMask(GL_TRUE);
349                glEnable(GL_LIGHTING);
350                mIsQueryMode = false;
351        }
352}
353
354void RenderTraverser::IssueOcclusionQuery(HierarchyNode *node, const bool wasVisible)
355{
356        // get next available test id
357        unsigned int occlusionQuery = mOcclusionQueries[mCurrentQueryIdx ++];
358       
359        node->SetOcclusionQuery(occlusionQuery);
360
361        // do the actual occlusion query for this node
362        if (mUseArbQueries)
363        {
364                glBeginQueryARB(GL_SAMPLES_PASSED_ARB, occlusionQuery);
365        }
366        else
367        {
368                glBeginOcclusionQueryNV(occlusionQuery);
369        }
370       
371        // if leaf and was visible => will be rendered anyway, thus we
372        // can also test with the real geometry
373        if(node->IsLeaf() && wasVisible && mUseOptimization)
374        {
375                mNumRenderedGeometry += node->Render();
376        }
377        else
378        {
379                // change state so the bounding box gets not actually rendered on the screen
380                Switch2GLQueryState();
381                node->RenderBoundingVolume();
382                Switch2GLRenderState();
383        }
384
385        if (mUseArbQueries)
386        {
387                glEndQueryARB(GL_SAMPLES_PASSED_ARB);
388        }
389        else
390        {
391                glEndOcclusionQueryNV();
392        }
393}
394
395void RenderTraverser::Preprocess()
396{
397        if (!mOcclusionQueries)
398        {
399                mOcclusionQueries = new unsigned int[mHierarchyRoot->GetNumHierarchyNodes()];
400
401                // generate ids for occlusion test
402                if (mUseArbQueries)
403                {
404                        glGenQueriesARB(mHierarchyRoot->GetNumHierarchyNodes(), mOcclusionQueries);
405                }
406                else
407                {
408                        glGenOcclusionQueriesNV(mHierarchyRoot->GetNumHierarchyNodes(), mOcclusionQueries);
409                }
410        }
411
412        // view frustum planes for view frustum culling
413        calcViewFrustumPlanes(&mClipPlanes, mProjViewMatrix);
414        calcAABNPVertexIndices(mNPVertexIndices, mClipPlanes);
415
416        mCurrentQueryIdx = 0;
417
418        // reset statistics
419        mNumTraversedNodes = 0;
420        mNumQueryCulledNodes = 0;
421        mNumFrustumCulledNodes = 0;
422        mNumRenderedGeometry = 0;
423}
424
425
426void RenderTraverser::DelQueries()
427{
428        if (!mOcclusionQueries)
429                return;
430
431        // tell the driver that the occlusion queries won't be needed any more
432        if (mUseArbQueries)
433        {
434                glDeleteQueriesARB(mHierarchyRoot->GetNumHierarchyNodes(), mOcclusionQueries);
435        }
436        else
437        {
438                glDeleteOcclusionQueriesNV(mHierarchyRoot->GetNumHierarchyNodes(), mOcclusionQueries);
439        }
440
441        delete [] mOcclusionQueries;
442
443        mOcclusionQueries = NULL;
444}
445
446
447void RenderTraverser::SetViewpoint(Vector3 const &viewpoint)
448{
449        copyVector3(mViewpoint, viewpoint);
450}
451       
452
453void RenderTraverser::SetProjViewMatrix(Matrix4x4 const &projViewMatrix)
454{
455        copyMatrix(mProjViewMatrix, projViewMatrix);
456}
457
458
459bool RenderTraverser::InsideViewFrustum(HierarchyNode *node, bool &intersects)
460{
461        Vector3x8 vertices;
462       
463        bool intersect = false;
464
465        calcAABoxPoints(vertices, node->GetBoundingVolume());
466
467        // simply test all 6 vertices
468        for (int i = 0; i < 6; i++)
469        {               
470                // test the n-vertex
471                // note: the calcAABNearestVertexId should be preprocessed
472                if(!pointBeforePlane(mClipPlanes.plane[i], vertices[mNPVertexIndices[i * 2]]))
473                {
474                        // outside
475                        return false;
476                }
477        }
478
479        // test if bounding box is intersected by nearplane (using the p-vertex)
480        intersects = (!pointBeforePlane(mClipPlanes.plane[5], vertices[mNPVertexIndices[11]]));
481
482        // -- get vector from viewpoint to center of bounding volume
483        Vector3 vec;
484        calcAABoxCenter(vec, node->GetBoundingVolume());
485        diffVector3(vec, vec, mViewpoint);
486
487        // compute distance from nearest point to viewpoint
488        diffVector3(vec, vertices[calcAABNearestVertexIdx(vec)], mViewpoint);
489        node->SetDistance(squaredLength(vec));
490       
491        return true;
492}
493
494
495void RenderTraverser::SetVisibilityThreshold(int threshold)
496{
497        mVisibilityThreshold = threshold;
498}
499
500void RenderTraverser::SetUseArbQueries(const bool useArbQueries)
501{
502        DelQueries();
503        mUseArbQueries = useArbQueries;
504}
505
506bool RenderTraverser::GetUseArbQueries() const
507{
508        return mUseArbQueries;
509}
510
511long RenderTraverser::GetRenderTime()
512{
513        return mRenderTime;
514}
515
516int RenderTraverser::GetNumTraversedNodes()
517{
518        return mNumTraversedNodes;
519}
520
521int RenderTraverser::GetNumQueryCulledNodes()
522{
523        return mNumQueryCulledNodes;
524}
525
526int RenderTraverser::GetNumFrustumCulledNodes()
527{
528        return mNumFrustumCulledNodes;
529}
530
531
532int RenderTraverser::GetNumRenderedGeometry()
533{
534        return mNumRenderedGeometry;
535}
536
537
538int RenderTraverser::GetVisibilityThreshold()
539{
540        return mVisibilityThreshold;
541}
542
543void RenderTraverser::SetUseOptimization(bool useOptimization)
544{
545        mUseOptimization = useOptimization;
546        printf("using opt %d\n", mUseOptimization);
547}
Note: See TracBrowser for help on using the repository browser.