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

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