source: trunk/VUT/OcclusionCullingSceneManager/src/OgreOcclusionCullingSceneTraverser.cpp @ 42

Revision 42, 14.0 KB checked in by mattausch, 19 years ago (diff)
Line 
1#include "OgreOcclusionCullingSceneTraverser.h"
2#include "OgreMath.h"
3#include "OgreIteratorWrappers.h"
4#include "OgreCamera.h"
5#include "OgreHardwareOcclusionQuery.h"
6//#include "OgreWireBoundingBox.h"
7#include "OgreSolidHalfBoundingBox.h"
8
9
10#include <windows.h>
11
12namespace Ogre {
13       
14        //-----------------------------------------------------------------------
15        OcclusionCullingSceneTraverser::OcclusionCullingSceneTraverser(SceneManager *sm, RenderSystem *rsys):
16        mFrameId(1), mDistanceQueue(NULL), mVisibilityThreshold(0), mCurrentTestIdx(0),
17        mQueryMode(MODE_RENDER), mNumSceneNodes(0), mCurrentAlgorithm(RENDER_COHERENT),
18        mNumQueries(0), mNumTraversedNodes(0), mNumQueryCulledNodes(0), mNumFrustumCulledNodes(0),
19        mNumRenderedGeometry(0), mSceneManager(sm), mRenderSystem(rsys), mSceneRoot(NULL)
20        {               
21                mHalfBoundingBox[0] = mHalfBoundingBox[1] = 0;
22        }
23        //-----------------------------------------------------------------------
24        OcclusionCullingSceneTraverser::~OcclusionCullingSceneTraverser()
25        {               
26                if(mHalfBoundingBox[0]) delete mHalfBoundingBox[0];
27                if(mHalfBoundingBox[1]) delete mHalfBoundingBox[1];
28
29                deleteQueries();
30
31                if(mDistanceQueue)
32                        delete mDistanceQueue;
33                //SceneManager::~SceneManager();
34        }
35        //-----------------------------------------------------------------------
36        void OcclusionCullingSceneTraverser::renderScene( Camera *cam )
37        {
38                mNumTraversedNodes = 0;
39                mNumQueryCulledNodes = 0;
40                mNumFrustumCulledNodes = 0;
41                mNumRenderedGeometry = 0;
42               
43                mCurrentTestIdx = 0;
44
45                initDistanceQueue(cam);
46
47//mCurrentAlgorithm = RENDER_CULL_FRUSTUM;
48                switch(mCurrentAlgorithm)
49                {
50                        case RENDER_CULL_FRUSTUM:
51                                renderCullFrustum(cam);
52                        break;
53                        case RENDER_STOP_AND_WAIT:
54                                renderStopAndWait(cam);
55                                break;
56                        case RENDER_COHERENT:
57                                renderCoherentWithQueue(cam);
58                                break;
59                        default:
60                                renderCullFrustum(cam);
61                                break;
62                }       
63               
64                mFrameId ++;
65        }
66        //-----------------------------------------------------------------------
67        void OcclusionCullingSceneTraverser::renderCoherentWithQueue(Camera *cam)
68        {
69                QueryQueue queryQueue;
70
71                //-- PART 1: process finished occlusion queries
72                while(!mDistanceQueue->empty() || !queryQueue.empty())
73                {
74                        while(!queryQueue.empty() &&
75                                  ((queryQueue.front().second)->resultAvailable() || mDistanceQueue->empty()))
76                        {
77                                SceneNode *node = queryQueue.front().first;
78                                HardwareOcclusionQuery *query = queryQueue.front().second;
79
80                                queryQueue.pop();
81                       
82                                // wait until result available
83                                unsigned int visiblePixels;
84                                query->pullOcclusionQuery(&visiblePixels);
85
86                                if(visiblePixels > mVisibilityThreshold)
87                                {
88                                        pullUpVisibility(cam, node);
89                                        traverseNode(cam, node);
90                                }
91                                else
92                                {
93                                        mNumQueryCulledNodes ++;
94                                }
95                        }       
96
97                        //-- PART 2: hierarchical traversal
98                        if(!mDistanceQueue->empty())
99                        {
100                                SceneNode *node = mDistanceQueue->top();
101                                mDistanceQueue->pop();
102                               
103                                bool intersects = false;
104                                //TODO: Isvisible also checked inside scenenode::findvisibleobjects
105                                if(!cam->isVisible(node->_getWorldAABB(), intersects))
106                                {
107                    mNumFrustumCulledNodes ++;
108                                        continue;
109                                }
110
111                                // if intersects near plane => skip occlusion query because wrong results possible
112                                if(intersects)
113                                {
114                                        // update node's visited flag
115                                        node->setLastVisited(mFrameId);
116                                        pullUpVisibility(cam, node);                   
117                                        traverseNode(cam, node);
118
119                                        continue;
120                                }
121
122                                // identify previously visible nodes
123                                bool wasVisible = node->isNodeVisible() && (node->lastVisited() == mFrameId - 1);
124                                       
125                                // identify nodes that we cannot skip queries for
126                                bool leafOrWasInvisible = !wasVisible || isLeaf(node);
127
128                                // reset node's visibility classification
129                                node->setNodeVisible(false);
130
131                                // update node's visited flag
132                                node->setLastVisited(mFrameId);
133                               
134                                // skip testing previously visible interior nodes
135                                if(leafOrWasInvisible)
136                                {
137                                        HardwareOcclusionQuery *query = issueOcclusionQuery(&node->_getWorldAABB(), wasVisible);
138                                        queryQueue.push(QueryPair(node, query));
139                                }
140                                       
141                                // always traverse a node if it was visible
142                                if(wasVisible)
143                                {
144                                        traverseNode(cam, node);
145                                }
146                                else
147                                {
148                                        mNumFrustumCulledNodes ++;
149                                }
150                        }
151                }
152        }
153        //-----------------------------------------------------------------------
154        void OcclusionCullingSceneTraverser::renderCullFrustum(Camera *cam)
155        {
156                while(!mDistanceQueue->empty())
157                {
158                        SceneNode *node = mDistanceQueue->top();
159                        mDistanceQueue->pop();
160       
161                        // interesting for visualization purpose
162                        node->setNodeVisible(false);
163
164                        //TODO: IsVisible also checked inside scenenode::_findvisibleobjects
165                        if(!cam->isVisible(node->_getWorldAABB()))
166                        {                       
167                                mNumFrustumCulledNodes ++;
168                                continue;
169                        }
170
171                        // update node's visited flag
172                        node->setLastVisited(mFrameId);
173                        node->setNodeVisible(true);
174                        traverseNode(cam, node);
175                }
176        }       
177        //-----------------------------------------------------------------------
178        void OcclusionCullingSceneTraverser::renderStopAndWait(Camera *cam)
179        {
180                while(!mDistanceQueue->empty())
181                {
182                        SceneNode *node = mDistanceQueue->top();
183                        mDistanceQueue->pop();
184               
185                        // interesting for the visualization
186                        node->setNodeVisible(false);
187                        node->setLastVisited(mFrameId);
188
189                        bool intersects = false;
190                        //TODO: Isvisible also checked inside scenenode::findvisibleobjects
191                        if(!cam->isVisible(node->_getWorldAABB(), intersects))
192                        {
193                                mNumFrustumCulledNodes ++;
194                                continue;
195                        }
196
197                        // if intersects near plane => skip occlusion query because wrong results possible
198                        if(intersects)
199                        {
200                                node->setNodeVisible(true);
201                                traverseNode(cam, node);
202
203                                continue;
204                        }
205
206                        HardwareOcclusionQuery *query = issueOcclusionQuery(&node->_getWorldAABB(), false);
207                               
208                        unsigned int visiblePixels;
209                        // wait if result not available
210                        query->pullOcclusionQuery(&visiblePixels);
211                               
212                        // node visible
213                        if(visiblePixels > mVisibilityThreshold)
214                        {
215                                node->setNodeVisible(true);
216                                traverseNode(cam, node);
217                        }
218                        else
219                        {
220                                mNumQueryCulledNodes ++;
221                        }
222                }
223        }
224        //-----------------------------------------------------------------------
225        HardwareOcclusionQuery *OcclusionCullingSceneTraverser::issueOcclusionQuery(
226                AxisAlignedBox *box, bool wasVisible )
227        {
228                // change state so the bounding box gets not actually rendered on the screen
229                // TODO: in rendervisibleobjects, the rendermode is changed by ogre itself => change this!!
230                setRenderingMode(MODE_QUERY);
231                //setRenderingMode(MODE_RENDER);
232
233                // get next available test id
234                HardwareOcclusionQuery *query = getNextOcclusionQuery();
235
236                //-- the actual query test
237                query->beginOcclusionQuery();
238                               
239                renderBoundingBox(box);
240
241                query->endOcclusionQuery();
242
243                return query;
244        }
245        //-----------------------------------------------------------------------
246        void OcclusionCullingSceneTraverser::setRenderingMode( int mode )
247        {       
248                // avoid unnecessary state changes
249                if(mode != mQueryMode)
250                {
251                        bool enabled = (mode == MODE_RENDER);
252                       
253                        mRenderSystem->_setColourBufferWriteEnabled(enabled,
254                                enabled, enabled, enabled);
255                        mRenderSystem->_setDepthBufferWriteEnabled(enabled);
256                        mRenderSystem->setLightingEnabled(enabled);
257
258                        mQueryMode = mode;
259                }
260        }
261        //-----------------------------------------------------------------------
262        void OcclusionCullingSceneTraverser::traverseNode( Camera *cam, SceneNode *node )
263        {
264                mNumTraversedNodes ++;
265               
266                if(node->numAttachedObjects() > 0)
267                {
268                        renderSceneNode(cam, node);
269                }
270
271                // internal node: add children to priority queue for further processing
272                Node::ChildNodeIterator it = node->getChildIterator();
273                                       
274                while (it.hasMoreElements())                   
275                {
276                        SceneNode* sceneChild = static_cast<SceneNode*>(it.getNext());
277                        mDistanceQueue->push(sceneChild);
278                }
279        }
280        //-----------------------------------------------------------------------
281        void OcclusionCullingSceneTraverser::renderSceneNode( Camera *cam, SceneNode *node )
282        {
283                //TODO: does not do any changes
284                setRenderingMode(MODE_RENDER);
285               
286                mSceneManager->_renderSceneNode(cam, node);
287        }
288        //-----------------------------------------------------------------------
289/*      void OcclusionCullingSceneTraverser::preprocess( void )
290        {
291                //-- initialise occlusion queries.
292                deleteQueries();
293
294                for(unsigned int i=0; i < mNumQueries; i++)
295                {
296                        mOcclusionQueries.push_back(mRenderSystem->createHardwareOcclusionQuery());
297                }       
298        }*/
299        //-----------------------------------------------------------------------
300        void OcclusionCullingSceneTraverser::setSceneManager( SceneManager *sm )
301        {
302                mSceneManager = sm;
303        }
304        //-----------------------------------------------------------------------
305        void OcclusionCullingSceneTraverser::setRenderSystem( RenderSystem *rsys )
306        {
307                mRenderSystem = rsys;
308        }
309        //-----------------------------------------------------------------------
310        /*unsigned int OcclusionCullingSceneManager::countSceneNodes(SceneNode *node)
311        {
312                unsigned int result = 1;
313               
314                Node::ChildNodeIterator it = node->getChildIterator();
315               
316                while (it.hasMoreElements())
317                {
318                        SceneNode* sceneChild = static_cast<SceneNode*>(it.getNext());
319                        result += countSceneNodes(sceneChild);
320        }
321
322                return result;
323        }*/
324        //-----------------------------------------------------------------------
325        bool OcclusionCullingSceneTraverser::isLeaf( SceneNode *node )
326        {
327                return (node->numChildren() == 0);
328        }
329        //-----------------------------------------------------------------------
330        void OcclusionCullingSceneTraverser::pullUpVisibility( Camera *cam, SceneNode *node )
331        {
332                while(node && !node->isNodeVisible())
333                {
334                        // if we come across some renderable geometry => render it
335                        if(node->numAttachedObjects() > 0)
336                        {
337                                renderSceneNode(cam, node);
338                        }
339
340                        node->setNodeVisible(true);
341                        node = node->getParentSceneNode();
342                }
343        }
344        //-----------------------------------------------------------------------
345        void OcclusionCullingSceneTraverser::deleteQueries( void )
346        {
347                for(unsigned int i=0; i < (unsigned int)mOcclusionQueries.size(); i++)
348                        delete mOcclusionQueries[i];
349
350                mOcclusionQueries.clear();
351        }
352        //-----------------------------------------------------------------------
353        void OcclusionCullingSceneTraverser::renderBoundingBox( AxisAlignedBox *box )
354        {
355                // Render two halfes of the bounding box (using triangle fans)
356                for(int half = 0; half < 2; half ++)
357                {
358                        //static Matrix4 xform[256];
359                        //TODO: this should be full boudning box
360                        SolidHalfBoundingBox *halfbox = getSolidHalfBoundingBox(half);
361                        halfbox->setupBoundingBox(*box);
362
363                        mRenderSystem->_setWorldMatrix(Matrix4::IDENTITY);
364                       
365                        static RenderOperation ro;
366
367                        mSceneManager->useRenderableViewProjMode(halfbox);
368                        halfbox->getRenderOperation(ro);
369                        ro.srcRenderable = halfbox;
370                        mRenderSystem->_render(ro);
371
372                        //mSceneManager->renderSingleObject(getSolidHalfBoundingBox(half),
373                        //      getSolidHalfBoundingBox(half)->getTechnique()->getPass(0), false);
374                }
375        }
376        //-----------------------------------------------------------------------
377        SolidHalfBoundingBox *OcclusionCullingSceneTraverser::getSolidHalfBoundingBox( int half )
378        {
379                if(!mHalfBoundingBox[half])
380                        mHalfBoundingBox[half] = new SolidHalfBoundingBox(half == 1);
381
382                return mHalfBoundingBox[half]; 
383        }
384        //-----------------------------------------------------------------------
385        void OcclusionCullingSceneTraverser::setNumSceneNodes(int num)
386        {
387                mNumSceneNodes = num;
388        }
389        //-----------------------------------------------------------------------
390        /*void OcclusionCullingSceneTraverser::setNumQueries(int num)
391        {
392                mNumQueries = num;
393        }*/
394        //-----------------------------------------------------------------------
395        void OcclusionCullingSceneTraverser::setSceneRoot(SceneNode *root)
396        {
397                mSceneRoot = root;
398        }
399        //-----------------------------------------------------------------------
400        void OcclusionCullingSceneTraverser::initDistanceQueue(Camera *cam)
401        {
402                mDistanceQueue = new PriorityQueue(myless<SceneNode *>(cam));
403                mDistanceQueue->push(mSceneRoot);
404        }
405        //-----------------------------------------------------------------------
406        HardwareOcclusionQuery *OcclusionCullingSceneTraverser::getNextOcclusionQuery(void)
407        {
408                if(mCurrentTestIdx == mOcclusionQueries.size())
409                {
410                        mOcclusionQueries.push_back(mRenderSystem->createHardwareOcclusionQuery());
411                }
412               
413                return mOcclusionQueries[mCurrentTestIdx ++];
414        }
415        //-----------------------------------------------------------------------
416        bool OcclusionCullingSceneTraverser::setOption( const String & key, const void * val )
417        {
418                if ( key == "Algorithm" )
419                {
420                        mCurrentAlgorithm = * static_cast < const int * > ( val );
421                        return true;
422                }
423                if ( key == "Threshold" )
424                {
425                        mVisibilityThreshold = * static_cast < const int * > ( val );
426                        return true;
427                }
428
429                return false;
430        }
431        //-----------------------------------------------------------------------
432        bool OcclusionCullingSceneTraverser::getOption( const String & key, void *val )
433        {
434                if ( key == "Algorithm" )
435                {
436                        * static_cast < int * > ( val ) = mCurrentAlgorithm;
437                        return true;
438                }
439                if ( key == "Threshold" )
440                {
441                        * static_cast < unsigned int * > ( val ) = mVisibilityThreshold;
442                        return true;
443                }
444                if ( key == "NumSceneNodes" )
445                {
446                        * static_cast < unsigned int * > ( val ) = mNumSceneNodes;
447                        return true;
448                }
449                if ( key == "NumTraversedNodes" )
450                {
451                        * static_cast < unsigned int * > ( val ) = mNumTraversedNodes;
452                        return true;
453                }
454                if ( key == "NumQueryCulledNodes" )
455                {
456                        * static_cast < unsigned int * > ( val ) = mNumQueryCulledNodes;
457                        return true;
458                }
459                if ( key == "NumFrustumCulledNodes" )
460                {
461                        * static_cast < unsigned int * > ( val ) = mNumFrustumCulledNodes;
462                        return true;
463                }
464                return false;
465        }
466        //-----------------------------------------------------------------------
467        bool OcclusionCullingSceneTraverser::getOptionKeys( StringVector & refKeys )
468        {
469                refKeys.push_back( "Algorithm" );
470                refKeys.push_back( "Threshold" );
471                refKeys.push_back( "NumSceneNodes" );
472                refKeys.push_back( "NumTraversedNodes" );
473                refKeys.push_back( "NumQueryCulledNodes" );
474                refKeys.push_back( "NumFrustumCulledNodes" );
475                //refKeys.push_back( "mNumRenderedGeometry" );
476
477                return true;
478        }
479}       
Note: See TracBrowser for help on using the repository browser.