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

Revision 51, 14.7 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 "OgreSolidHalfBoundingBox.h"
7
8
9#include <windows.h>
10
11namespace Ogre {
12       
13        //-----------------------------------------------------------------------
14        OcclusionCullingSceneTraverser::OcclusionCullingSceneTraverser(SceneManager *sm, RenderSystem *rsys):
15        mFrameId(1), mDistanceQueue(NULL), mVisibilityThreshold(0), mCurrentTestIdx(0),
16        mQueryMode(MODE_RENDER), mNumSceneNodes(0), mCurrentAlgorithm(RENDER_COHERENT),
17        mNumQueries(0), mNumTraversedNodes(0), mNumQueryCulledNodes(0), mNumFrustumCulledNodes(0),
18        mNumRenderedNodes(0),mNumRenderedGeometry(0), mSceneManager(sm), mRenderSystem(rsys), mSceneRoot(NULL)
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();
29
30                if(mDistanceQueue)
31                        delete mDistanceQueue;
32                //SceneManager::~SceneManager();
33        }
34        //-----------------------------------------------------------------------
35        void OcclusionCullingSceneTraverser::renderScene( Camera *cam )
36        {
37                mNumTraversedNodes = 0;
38                mNumQueryCulledNodes = 0;
39                mNumFrustumCulledNodes = 0;
40                mNumRenderedGeometry = 0;
41                mNumRenderedNodes = 0;
42
43                mCurrentTestIdx = 0;
44
45                initDistanceQueue(cam);
46
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
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:
62                                renderCoherentWithQueue(cam);
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                                {
93                                        pullUpVisibility(cam, node);
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();
107                               
108                                bool intersects = false;
109                                //TODO: Isvisible also checked inside scenenode::findvisibleobjects
110                                if(!cam->isVisible(node->_getWorldAABB(), intersects))
111                                {
112                    mNumFrustumCulledNodes ++;
113                                        continue;
114                                }
115
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
127                                // identify previously visible nodes
128                                bool wasVisible = node->isNodeVisible() && (node->lastVisited() == mFrameId - 1);
129                                       
130                                // identify nodes that we cannot skip queries for
131                                bool leafOrWasInvisible = !wasVisible || isLeaf(node);
132
133                                // reset node's visibility classification
134                                node->setNodeVisible(false);
135
136                                // update node's visited flag
137                                node->setLastVisited(mFrameId);
138                               
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                                }
145                                       
146                                // always traverse a node if it was visible
147                                if(wasVisible)
148                                {
149                                        traverseNode(cam, node);
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);
168
169                        //TODO: IsVisible also checked inside scenenode::_findvisibleobjects
170                        if(!cam->isVisible(node->_getWorldAABB()))
171                        {                       
172                                mNumFrustumCulledNodes ++;
173                                continue;
174                        }
175
176                        // update node's visited flag
177                        node->setLastVisited(mFrameId);
178                        node->setNodeVisible(true);
179                        traverseNode(cam, node);
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
194                        bool intersects = false;
195                        //TODO: Isvisible also checked inside scenenode::findvisibleobjects
196                        if(!cam->isVisible(node->_getWorldAABB(), intersects))
197                        {
198                                mNumFrustumCulledNodes ++;
199                                continue;
200                        }
201
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
211                        HardwareOcclusionQuery *query = issueOcclusionQuery(&node->_getWorldAABB(), false);
212                               
213                        unsigned int visiblePixels;
214                        // wait if result not available
215                        query->pullOcclusionQuery(&visiblePixels);
216       
217                        // node visible
218                        if(visiblePixels > mVisibilityThreshold)
219                        {
220                                node->setNodeVisible(true);
221                                traverseNode(cam, node);
222                        }
223                        else
224                        {
225                                mNumQueryCulledNodes ++;
226                        }
227                }
228        }
229        //-----------------------------------------------------------------------
230        HardwareOcclusionQuery *OcclusionCullingSceneTraverser::issueOcclusionQuery(
231                AxisAlignedBox *box, bool wasVisible )
232        {
233                // change state so the bounding box gets not actually rendered on the screen
234                // TODO: in rendervisibleobjects, the rendermode is changed by ogre itself => change this!!
235               
236                setRenderingMode(MODE_QUERY);
237                //setRenderingMode(MODE_RENDER);
238
239                // get next available test id
240                HardwareOcclusionQuery *query = getNextOcclusionQuery();
241
242                //-- the actual query test
243                query->beginOcclusionQuery();
244                               
245                renderBoundingBox(box);
246
247                query->endOcclusionQuery();
248
249                return query;
250        }
251        //-----------------------------------------------------------------------
252        void OcclusionCullingSceneTraverser::setRenderingMode( int mode )
253        {       
254                // avoid unnecessary state changes
255                //if(mode != mQueryMode)
256                //{
257                        bool enabled = (mode == MODE_RENDER);
258//if(mode == MODE_QUERY){
259                        mRenderSystem->_setColourBufferWriteEnabled(enabled,
260                                enabled, enabled, enabled);
261                        mRenderSystem->_setDepthBufferWriteEnabled(enabled);
262                        mRenderSystem->setLightingEnabled(enabled);
263//}
264                        mQueryMode = mode;
265                //}
266        }
267        //-----------------------------------------------------------------------
268        void OcclusionCullingSceneTraverser::traverseNode( Camera *cam, SceneNode *node )
269        {
270                mNumTraversedNodes ++;
271               
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        {
289                //TODO: does not do any changes
290                setRenderingMode(MODE_RENDER);
291               
292                mSceneManager->_renderSceneNode(cam, node);
293        }
294        //-----------------------------------------------------------------------
295/*      void OcclusionCullingSceneTraverser::preprocess( void )
296        {
297                //-- initialise occlusion queries.
298                deleteQueries();
299
300                for(unsigned int i=0; i < mNumQueries; i++)
301                {
302                        mOcclusionQueries.push_back(mRenderSystem->createHardwareOcclusionQuery());
303                }       
304        }*/
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        //-----------------------------------------------------------------------
336        void OcclusionCullingSceneTraverser::pullUpVisibility( Camera *cam, SceneNode *node )
337        {
338                while(node && !node->isNodeVisible())
339                {
340                        // if we come across some renderable geometry => render it
341                        if(node->numAttachedObjects() > 0)
342                        {
343                                renderSceneNode(cam, node);
344                        }
345
346                        node->setNodeVisible(true);
347                        node = node->getParentSceneNode();
348                }
349        }
350        //-----------------------------------------------------------------------
351        void OcclusionCullingSceneTraverser::deleteQueries( void )
352        {
353                for(unsigned int i=0; i < (unsigned int)mOcclusionQueries.size(); ++i)
354                        delete mOcclusionQueries[i];
355
356                mOcclusionQueries.clear();
357        }
358        //-----------------------------------------------------------------------
359        void OcclusionCullingSceneTraverser::renderBoundingBox( AxisAlignedBox *box )
360        {
361                // Render two halfes of the bounding box (using triangle fans)
362                for(int half = 0; half < 2; half ++)
363                {
364                        static Matrix4 xform[256];
365                        //TODO: this should be full bounding box
366                        SolidHalfBoundingBox *halfbox = getSolidHalfBoundingBox(half);
367                        halfbox->setupBoundingBox(*box);
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
384                        static RenderOperation ro;
385
386                        mSceneManager->useRenderableViewProjMode(halfbox);
387                        halfbox->getRenderOperation(ro);
388                        ro.srcRenderable = halfbox;
389                        mRenderSystem->_render(ro);*/
390
391                        mSceneManager->myrenderSingleObject(getSolidHalfBoundingBox(half),
392                                getSolidHalfBoundingBox(half)->getTechnique()->getPass(0), false);
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        //-----------------------------------------------------------------------
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());
430                        //char *msg = "creating query!!\n"; OutputDebugString(msg);
431                }
432               
433                return mOcclusionQueries[mCurrentTestIdx ++];
434        }
435        //-----------------------------------------------------------------------
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        }
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        }
499}       
Note: See TracBrowser for help on using the repository browser.