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

Revision 44, 14.0 KB checked in by mattausch, 19 years ago (diff)

implementation for terrain + octree scenemanager

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