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

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