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

Revision 54, 15.0 KB checked in by mattausch, 19 years ago (diff)

fixed terrainscenemanager bug

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