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

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