source: trunk/VUT/OcclusionCullingSceneManager/src/OgreOcclusionCullingSceneManager.cpp @ 31

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