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

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