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

Revision 39, 12.1 KB checked in by mattausch, 19 years ago (diff)
Line 
1#include "OgreOcclusionCullingSceneTraverser.h"
2#include "OgreMath.h"
3#include "OgreIteratorWrappers.h"
4#include "OgreCamera.h"
5#include "OgreHardwareOcclusionQuery.h"
6//#include "OgreWireBoundingBox.h"
7#include "OgreSolidHalfBoundingBox.h"
8
9
10#include <windows.h>
11
12namespace Ogre {
13       
14        //-----------------------------------------------------------------------
15        OcclusionCullingSceneTraverser::OcclusionCullingSceneTraverser(SceneManager *sm, RenderSystem *rsys):
16        mFrameId(1), mDistanceQueue(NULL), mVisibilityThreshold(0), mCurrentTestIdx(0),
17        mQueryMode(MODE_RENDER), mNumSceneNodes(0), mCurrentAlgorithm(RENDER_COHERENT),
18        mNumTraversedNodes(0), mNumQueryCulledNodes(0), mNumFrustumCulledNodes(0),
19        mNumRenderedGeometry(0), mSceneManager(sm), mRenderSystem(rsys)
20        {               
21                mHalfBoundingBox[0] = mHalfBoundingBox[1] = 0;
22        }
23        //-----------------------------------------------------------------------
24        OcclusionCullingSceneTraverser::~OcclusionCullingSceneTraverser()
25        {               
26                if(mHalfBoundingBox[0]) delete mHalfBoundingBox[0];
27                if(mHalfBoundingBox[1]) delete mHalfBoundingBox[1];
28
29                deleteQueries();
30                //SceneManager::~SceneManager();
31        }
32        //-----------------------------------------------------------------------
33        void OcclusionCullingSceneTraverser::renderScene( Camera *cam, SceneNode *root )
34        {
35                mNumTraversedNodes = 0;
36                mNumQueryCulledNodes = 0;
37                mNumFrustumCulledNodes = 0;
38                mNumRenderedGeometry = 0;
39               
40                mDistanceQueue = new PriorityQueue(myless<SceneNode *>(cam));
41                mDistanceQueue->push(root);
42                mCurrentTestIdx = 0;
43
44//mCurrentAlgorithm = RENDER_CULL_FRUSTUM;
45                switch(mCurrentAlgorithm)
46                {
47                        case RENDER_CULL_FRUSTUM:
48                                renderCullFrustum(cam);
49                        break;
50                        case RENDER_STOP_AND_WAIT:
51                                renderStopAndWait(cam);
52                                break;
53                        case RENDER_COHERENT:
54                                renderCoherentWithQueue(cam);
55                                break;
56                        default:
57                                renderCullFrustum(cam);
58                                break;
59                }       
60               
61                delete mDistanceQueue;
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                                if(cam->isVisible(node->_getWorldAABB()))
103                                {
104                                        // identify previously visible nodes
105                                        bool wasVisible = node->isNodeVisible() && (node->lastVisited() == mFrameId - 1);
106                                       
107                                        // identify nodes that we cannot skip queries for
108                                        bool leafOrWasInvisible = !wasVisible || isLeaf(node);
109
110                                        // reset node's visibility classification
111                                        node->setNodeVisible(false);
112
113                                        // update node's visited flag
114                                        node->setLastVisited(mFrameId);
115                               
116                                        // skip testing previously visible interior nodes
117                                        if(leafOrWasInvisible)
118                                        {
119                                                HardwareOcclusionQuery *query = issueOcclusionQuery(node, wasVisible);
120                                                queryQueue.push(QueryPair(node, query));
121                                        }
122                                       
123                                        // always traverse a node if it was visible
124                                        if(wasVisible)
125                                        {
126                                                traverseNode(cam, node);
127                                        }
128                                }
129                                else
130                                {
131                                        mNumFrustumCulledNodes ++;
132                                }
133                        }
134                }
135        }
136        //-----------------------------------------------------------------------
137        void OcclusionCullingSceneTraverser::renderCullFrustum(Camera *cam)
138        {
139                while(!mDistanceQueue->empty())
140                {
141                        SceneNode *node = mDistanceQueue->top();
142                        mDistanceQueue->pop();
143       
144                        // interesting for visualization purpose
145                        node->setNodeVisible(false);
146                               
147                        if(cam->isVisible(node->_getWorldAABB()))
148                        {
149                                // update node's visited flag
150                                node->setLastVisited(mFrameId);
151                                node->setNodeVisible(true);
152                                traverseNode(cam, node);
153                        }
154                        else
155                        {                       
156                                mNumFrustumCulledNodes ++;
157                        }
158                }
159        }       
160        //-----------------------------------------------------------------------
161        void OcclusionCullingSceneTraverser::renderStopAndWait(Camera *cam)
162        {
163                while(!mDistanceQueue->empty())
164                {
165                        SceneNode *node = mDistanceQueue->top();
166                        mDistanceQueue->pop();
167               
168                        // interesting for the visualization
169                        node->setNodeVisible(false);
170                        node->setLastVisited(mFrameId);
171
172                        if(cam->isVisible(node->_getWorldAABB()))
173                        {
174                                HardwareOcclusionQuery *query = issueOcclusionQuery(node, false);
175                               
176                                unsigned int visiblePixels;
177                                // wait if result not available
178                                query->pullOcclusionQuery(&visiblePixels);
179                               
180                                // node visible
181                                if(visiblePixels > mVisibilityThreshold)
182                                {
183                                        traverseNode(cam, node);
184                                }
185                                else
186                                {
187                                        mNumQueryCulledNodes ++;
188                                }
189                        }
190                        else
191                        {
192                                mNumFrustumCulledNodes ++;
193                        }
194                }
195        }
196        //-----------------------------------------------------------------------
197        HardwareOcclusionQuery *OcclusionCullingSceneTraverser::issueOcclusionQuery( SceneNode *node, bool wasVisible )
198        {
199                // change state so the bounding box gets not actually rendered on the screen
200                setRenderingMode(MODE_QUERY);
201                //setRenderingMode(MODE_RENDER);
202
203                // get next available test id
204                HardwareOcclusionQuery *query = mOcclusionQueries[mCurrentTestIdx++];
205               
206                query->beginOcclusionQuery();
207                               
208                renderBoundingBox(node);
209
210                query->endOcclusionQuery();
211
212                return query;
213        }
214        //-----------------------------------------------------------------------
215        void OcclusionCullingSceneTraverser::setRenderingMode( int mode )
216        {       
217                // avoid unnecessary state changes
218                if(mode != mQueryMode)
219                {
220                        bool enabled = (mode == MODE_RENDER);
221                       
222                        mRenderSystem->_setColourBufferWriteEnabled(enabled,
223                                enabled, enabled, enabled);
224                        mRenderSystem->_setDepthBufferWriteEnabled(enabled);
225                        mRenderSystem->setLightingEnabled(enabled);
226
227                        mQueryMode = mode;
228                }
229        }
230        //-----------------------------------------------------------------------
231        void OcclusionCullingSceneTraverser::traverseNode( Camera *cam, SceneNode *node )
232        {
233                mNumTraversedNodes ++;
234               
235                if(node->numAttachedObjects() > 0)
236                {
237                        renderSceneNode(cam, node);
238                }
239
240                // internal node: add children to priority queue for further processing
241                Node::ChildNodeIterator it = node->getChildIterator();
242                                       
243                while (it.hasMoreElements())                   
244                {
245                        SceneNode* sceneChild = static_cast<SceneNode*>(it.getNext());
246                        mDistanceQueue->push(sceneChild);
247                }
248        }
249        //-----------------------------------------------------------------------
250        void OcclusionCullingSceneTraverser::renderSceneNode( Camera *cam, SceneNode *node )
251        {
252                setRenderingMode(MODE_RENDER);
253               
254                //HACK (too slow)
255                mSceneManager->_renderSceneNode(cam, node);
256        }
257        //-----------------------------------------------------------------------
258        void OcclusionCullingSceneTraverser::preprocess( void )
259        {
260                //-- initialise occlusion queries.
261                deleteQueries();
262               
263                //char str[100];sprintf(str, "num nodes: %d", mNumSceneNodes);
264                //MessageBox( NULL, str, "this is my plugin", MB_OK | MB_ICONERROR | MB_TASKMODAL);
265
266                for(unsigned int i=0; i < mNumSceneNodes; i++)
267                {
268                        mOcclusionQueries.push_back(mRenderSystem->createHardwareOcclusionQuery());
269                }       
270        }
271        //-----------------------------------------------------------------------
272        void OcclusionCullingSceneTraverser::setSceneManager( SceneManager *sm )
273        {
274                mSceneManager = sm;
275        }
276        //-----------------------------------------------------------------------
277        void OcclusionCullingSceneTraverser::setRenderSystem( RenderSystem *rsys )
278        {
279                mRenderSystem = rsys;
280        }
281        //-----------------------------------------------------------------------
282        /*unsigned int OcclusionCullingSceneManager::countSceneNodes(SceneNode *node)
283        {
284                unsigned int result = 1;
285               
286                Node::ChildNodeIterator it = node->getChildIterator();
287               
288                while (it.hasMoreElements())
289                {
290                        SceneNode* sceneChild = static_cast<SceneNode*>(it.getNext());
291                        result += countSceneNodes(sceneChild);
292        }
293
294                return result;
295        }*/
296        //-----------------------------------------------------------------------
297        bool OcclusionCullingSceneTraverser::isLeaf( SceneNode *node )
298        {
299                return (node->numChildren() == 0);
300        }
301        //-----------------------------------------------------------------------
302        void OcclusionCullingSceneTraverser::pullUpVisibility( SceneNode *node )
303        {
304                while(node && !node->isNodeVisible())
305                {
306                        node->setNodeVisible(true);
307                        node = static_cast<SceneNode *>(node->getParent());
308                }
309        }
310        //-----------------------------------------------------------------------
311        void OcclusionCullingSceneTraverser::deleteQueries( void )
312        {
313                for(unsigned int i=0; i < mOcclusionQueries.size(); i++)
314                        delete mOcclusionQueries[i];
315
316                mOcclusionQueries.clear();
317        }
318        //-----------------------------------------------------------------------
319        void OcclusionCullingSceneTraverser::renderBoundingBox( SceneNode *node )
320        {
321                // Render two halfes of the bounding box (using triangle fans)
322                for(int half = 0; half < 2; half ++)
323                {
324                        //static Matrix4 xform[256];
325
326                        SolidHalfBoundingBox *box = getSolidHalfBoundingBox(half);
327                        box->setupBoundingBox(node->_getWorldAABB());
328
329                        mRenderSystem->_setWorldMatrix(Matrix4::IDENTITY);
330                       
331                        static RenderOperation ro;
332
333                        mSceneManager->useRenderableViewProjMode(box);
334                        box->getRenderOperation(ro);
335                        ro.srcRenderable = box;
336                        mRenderSystem->_render(ro);
337
338                        //mSceneManager->renderSingleObject(getSolidHalfBoundingBox(half),
339                        //      getSolidHalfBoundingBox(half)->getTechnique()->getPass(0), false);
340                }
341        }
342        //-----------------------------------------------------------------------
343        SolidHalfBoundingBox *OcclusionCullingSceneTraverser::getSolidHalfBoundingBox( int half )
344        {
345                if(!mHalfBoundingBox[half])
346                        mHalfBoundingBox[half] = new SolidHalfBoundingBox(half == 1);
347
348                return mHalfBoundingBox[half]; 
349        }
350        //-----------------------------------------------------------------------
351        bool OcclusionCullingSceneTraverser::setOption( const String & key, const void * val )
352        {
353                if ( key == "Algorithm" )
354                {
355                        mCurrentAlgorithm = * static_cast < const int * > ( val );
356                        return true;
357                }
358                if ( key == "Threshold" )
359                {
360                        mVisibilityThreshold = * static_cast < const int * > ( val );
361                        return true;
362                }
363
364                return false;
365        }
366        //-----------------------------------------------------------------------
367        bool OcclusionCullingSceneTraverser::getOption( const String & key, void *val )
368        {
369                if ( key == "Algorithm" )
370                {
371                        * static_cast < int * > ( val ) = mCurrentAlgorithm;
372                        return true;
373                }
374                if ( key == "Threshold" )
375                {
376                        * static_cast < unsigned int * > ( val ) = mVisibilityThreshold;
377                        return true;
378                }
379                if ( key == "NumSceneNodes" )
380                {
381                        * static_cast < unsigned int * > ( val ) = mNumSceneNodes;
382                        return true;
383                }
384                if ( key == "NumTraversedNodes" )
385                {
386                        * static_cast < unsigned int * > ( val ) = mNumTraversedNodes;
387                        return true;
388                }
389                if ( key == "NumQueryCulledNodes" )
390                {
391                        * static_cast < unsigned int * > ( val ) = mNumQueryCulledNodes;
392                        return true;
393                }
394                if ( key == "NumFrustumCulledNodes" )
395                {
396                        * static_cast < unsigned int * > ( val ) = mNumFrustumCulledNodes;
397                        return true;
398                }
399                return false;
400        }
401        //-----------------------------------------------------------------------
402        bool OcclusionCullingSceneTraverser::getOptionKeys( StringVector & refKeys )
403        {
404                refKeys.push_back( "Algorithm" );
405                refKeys.push_back( "Threshold" );
406                refKeys.push_back( "NumSceneNodes" );
407                refKeys.push_back( "NumTraversedNodes" );
408                refKeys.push_back( "NumQueryCulledNodes" );
409                refKeys.push_back( "NumFrustumCulledNodes" );
410                //refKeys.push_back( "mNumRenderedGeometry" );
411
412                return true;
413        }
414        //-----------------------------------------------------------------------
415        void OcclusionCullingSceneTraverser::setNumSceneNodes(int num)
416        {
417                mNumSceneNodes = num;
418        }
419}       
Note: See TracBrowser for help on using the repository browser.