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

Revision 59, 14.9 KB checked in by mattausch, 19 years ago (diff)

completely changed file structure plus software design

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