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

Revision 52, 15.4 KB checked in by mattausch, 20 years ago (diff)
RevLine 
[32]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
[33]8
[32]9#include <windows.h>
10
11namespace Ogre {
12       
13        //-----------------------------------------------------------------------
[33]14        OcclusionCullingSceneTraverser::OcclusionCullingSceneTraverser(SceneManager *sm, RenderSystem *rsys):
[32]15        mFrameId(1), mDistanceQueue(NULL), mVisibilityThreshold(0), mCurrentTestIdx(0),
16        mQueryMode(MODE_RENDER), mNumSceneNodes(0), mCurrentAlgorithm(RENDER_COHERENT),
[41]17        mNumQueries(0), mNumTraversedNodes(0), mNumQueryCulledNodes(0), mNumFrustumCulledNodes(0),
[51]18        mNumRenderedNodes(0),mNumRenderedGeometry(0), mSceneManager(sm), mRenderSystem(rsys), mSceneRoot(NULL)
[32]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();
[42]29
30                if(mDistanceQueue)
31                        delete mDistanceQueue;
[32]32                //SceneManager::~SceneManager();
33        }
34        //-----------------------------------------------------------------------
[42]35        void OcclusionCullingSceneTraverser::renderScene( Camera *cam )
[32]36        {
37                mNumTraversedNodes = 0;
38                mNumQueryCulledNodes = 0;
39                mNumFrustumCulledNodes = 0;
40                mNumRenderedGeometry = 0;
[51]41                mNumRenderedNodes = 0;
42
[32]43                mCurrentTestIdx = 0;
[34]44
[42]45                initDistanceQueue(cam);
46
[51]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());
[52]51
[51]52            //mCurrentAlgorithm = RENDER_CULL_FRUSTUM;
53
[32]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:
[51]63                                renderCoherentWithQueue(cam);
[32]64                                break;
65                        default:
66                                renderCullFrustum(cam);
67                                break;
68                }       
[52]69
[32]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                                {
[52]94                                        pullUpVisibility(node);
[32]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();
[41]108                               
[42]109                                bool intersects = false;
[41]110                                //TODO: Isvisible also checked inside scenenode::findvisibleobjects
[42]111                                if(!cam->isVisible(node->_getWorldAABB(), intersects))
[32]112                                {
[41]113                    mNumFrustumCulledNodes ++;
114                                        continue;
115                                }
116
[42]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);
[52]122                                        pullUpVisibility(node);                 
[42]123                                        traverseNode(cam, node);
124
125                                        continue;
126                                }
127
[41]128                                // identify previously visible nodes
129                                bool wasVisible = node->isNodeVisible() && (node->lastVisited() == mFrameId - 1);
[32]130                                       
[41]131                                // identify nodes that we cannot skip queries for
[52]132                                bool mustQuery= !wasVisible || (node->numAttachedObjects() > 0) || isLeaf(node);
[32]133
[41]134                                // reset node's visibility classification
135                                node->setNodeVisible(false);
[32]136
[41]137                                // update node's visited flag
138                                node->setLastVisited(mFrameId);
[32]139                               
[52]140                                // skip testing previously visible interior nodes without geometry
141                                if(mustQuery)
[41]142                                {
143                                        HardwareOcclusionQuery *query = issueOcclusionQuery(&node->_getWorldAABB(), wasVisible);
144                                        queryQueue.push(QueryPair(node, query));
145                                }
[32]146                                       
[41]147                                // always traverse a node if it was visible
148                                if(wasVisible)
149                                {
150                                        traverseNode(cam, node);
[32]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);
[40]169
[41]170                        //TODO: IsVisible also checked inside scenenode::_findvisibleobjects
171                        if(!cam->isVisible(node->_getWorldAABB()))
[32]172                        {                       
173                                mNumFrustumCulledNodes ++;
[41]174                                continue;
[32]175                        }
[41]176
177                        // update node's visited flag
178                        node->setLastVisited(mFrameId);
179                        node->setNodeVisible(true);
180                        traverseNode(cam, node);
[32]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
[42]195                        bool intersects = false;
[41]196                        //TODO: Isvisible also checked inside scenenode::findvisibleobjects
[42]197                        if(!cam->isVisible(node->_getWorldAABB(), intersects))
[32]198                        {
[41]199                                mNumFrustumCulledNodes ++;
200                                continue;
201                        }
202
[42]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
[41]212                        HardwareOcclusionQuery *query = issueOcclusionQuery(&node->_getWorldAABB(), false);
[32]213                               
[41]214                        unsigned int visiblePixels;
215                        // wait if result not available
216                        query->pullOcclusionQuery(&visiblePixels);
[51]217       
[41]218                        // node visible
219                        if(visiblePixels > mVisibilityThreshold)
220                        {
[42]221                                node->setNodeVisible(true);
[41]222                                traverseNode(cam, node);
[32]223                        }
224                        else
225                        {
[41]226                                mNumQueryCulledNodes ++;
[32]227                        }
228                }
229        }
230        //-----------------------------------------------------------------------
[41]231        HardwareOcclusionQuery *OcclusionCullingSceneTraverser::issueOcclusionQuery(
232                AxisAlignedBox *box, bool wasVisible )
[32]233        {
234                // change state so the bounding box gets not actually rendered on the screen
[41]235                // TODO: in rendervisibleobjects, the rendermode is changed by ogre itself => change this!!
[44]236               
[51]237                setRenderingMode(MODE_QUERY);
[52]238                //mRenderSystem->_setRasterisationMode(SDL_SOLID);setRenderingMode(MODE_RENDER);
[32]239
240                // get next available test id
[42]241                HardwareOcclusionQuery *query = getNextOcclusionQuery();
[41]242
243                //-- the actual query test
[32]244                query->beginOcclusionQuery();
245                               
[41]246                renderBoundingBox(box);
[32]247
248                query->endOcclusionQuery();
249
[52]250               
251                //mRenderSystem->_setRasterisationMode(SDL_WIREFRAME);
252                setRenderingMode(MODE_RENDER);
253                renderBoundingBox(box);
254                //mRenderSystem->_setRasterisationMode(SDL_SOLID);
255               
[32]256                return query;
257        }
258        //-----------------------------------------------------------------------
259        void OcclusionCullingSceneTraverser::setRenderingMode( int mode )
260        {       
261                // avoid unnecessary state changes
[52]262                if(mode != mQueryMode)
263                {
264                        mQueryMode = mode;
[32]265                        bool enabled = (mode == MODE_RENDER);
[52]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);
[32]279                        mRenderSystem->_setDepthBufferWriteEnabled(enabled);
280                        mRenderSystem->setLightingEnabled(enabled);
[52]281                }
[32]282        }
283        //-----------------------------------------------------------------------
284        void OcclusionCullingSceneTraverser::traverseNode( Camera *cam, SceneNode *node )
285        {
286                mNumTraversedNodes ++;
[34]287               
[32]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        {
[41]305                //TODO: does not do any changes
[32]306                setRenderingMode(MODE_RENDER);
307               
[52]308                if(node->lastRendered() != node->lastVisited())
309                {
310                        node->setLastRendered(node->lastVisited());
311                        mNumRenderedNodes ++;
312
313                        mSceneManager->_renderSceneNode(cam, node);
314                }
[32]315        }
316        //-----------------------------------------------------------------------
[42]317/*      void OcclusionCullingSceneTraverser::preprocess( void )
[32]318        {
319                //-- initialise occlusion queries.
320                deleteQueries();
[37]321
[41]322                for(unsigned int i=0; i < mNumQueries; i++)
[32]323                {
324                        mOcclusionQueries.push_back(mRenderSystem->createHardwareOcclusionQuery());
325                }       
[42]326        }*/
[32]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        //-----------------------------------------------------------------------
[52]358        void OcclusionCullingSceneTraverser::pullUpVisibility(SceneNode *node )
[32]359        {
360                while(node && !node->isNodeVisible())
361                {
362                        node->setNodeVisible(true);
[42]363                        node = node->getParentSceneNode();
[32]364                }
365        }
366        //-----------------------------------------------------------------------
367        void OcclusionCullingSceneTraverser::deleteQueries( void )
368        {
[51]369                for(unsigned int i=0; i < (unsigned int)mOcclusionQueries.size(); ++i)
[32]370                        delete mOcclusionQueries[i];
371
372                mOcclusionQueries.clear();
373        }
374        //-----------------------------------------------------------------------
[41]375        void OcclusionCullingSceneTraverser::renderBoundingBox( AxisAlignedBox *box )
[32]376        {
377                // Render two halfes of the bounding box (using triangle fans)
378                for(int half = 0; half < 2; half ++)
379                {
[51]380                        static Matrix4 xform[256];
381                        //TODO: this should be full bounding box
[41]382                        SolidHalfBoundingBox *halfbox = getSolidHalfBoundingBox(half);
383                        halfbox->setupBoundingBox(*box);
[51]384                       
[52]385                        mRenderSystem->_setWorldMatrix(Matrix4::IDENTITY);
386
[51]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                        }
[52]399                        mRenderSystem->setClipPlanes(halfbox->getClipPlanes());*/
[51]400
[32]401                        static RenderOperation ro;
[39]402
[41]403                        mSceneManager->useRenderableViewProjMode(halfbox);
404                        halfbox->getRenderOperation(ro);
405                        ro.srcRenderable = halfbox;
[52]406                        mRenderSystem->_render(ro);
[32]407
[52]408                        //mSceneManager->myrenderSingleObject(getSolidHalfBoundingBox(half), getSolidHalfBoundingBox(half)->getTechnique()->getPass(0), true);
[32]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        //-----------------------------------------------------------------------
[42]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());
[51]446                        //char *msg = "creating query!!\n"; OutputDebugString(msg);
[42]447                }
448               
449                return mOcclusionQueries[mCurrentTestIdx ++];
450        }
451        //-----------------------------------------------------------------------
[32]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                }
[52]500                if ( key == "NumRenderedNodes" )
501                {
502                        * static_cast < unsigned int * > ( val ) = mNumRenderedNodes;
503                        return true;
504                }
[32]505                return false;
506        }
[33]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" );
[52]516                refKeys.push_back( "mNumRenderedGeometry" );
[33]517
518                return true;
519        }
[32]520}       
Note: See TracBrowser for help on using the repository browser.