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

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