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

Revision 34, 12.0 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(query_pair(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                                if(cam->isVisible(node->_getWorldAABB()))
156                                {
157                                        mNumQueryCulledNodes ++;
158                                }else
159                        {                       
160                                mNumFrustumCulledNodes ++;
161                        }
162                }
163        }       
164        //-----------------------------------------------------------------------
165        void OcclusionCullingSceneTraverser::renderStopAndWait(Camera *cam)
166        {
167                while(!mDistanceQueue->empty())
168                {
169                        SceneNode *node = mDistanceQueue->top();
170                        mDistanceQueue->pop();
171               
172                        // interesting for the visualization
173                        node->setNodeVisible(false);
174                        node->setLastVisited(mFrameId);
175
176                        if(cam->isVisible(node->_getWorldAABB()))
177                        {
178                                HardwareOcclusionQuery *query = issueOcclusionQuery(node, false);
179                               
180                                unsigned int visiblePixels;
181                                // wait if result not available
182                                query->pullOcclusionQuery(&visiblePixels);
183                               
184                                // node visible
185                                if(visiblePixels > mVisibilityThreshold)
186                                {
187                                        traverseNode(cam, node);
188                                }
189                                else
190                                {
191                                        mNumQueryCulledNodes ++;
192                                }
193                        }
194                        else
195                        {
196                                mNumFrustumCulledNodes ++;
197                        }
198                }
199        }
200        //-----------------------------------------------------------------------
201        HardwareOcclusionQuery *OcclusionCullingSceneTraverser::issueOcclusionQuery( SceneNode *node, bool wasVisible )
202        {
203                // change state so the bounding box gets not actually rendered on the screen
204                setRenderingMode(MODE_QUERY);
205
206                // get next available test id
207                HardwareOcclusionQuery *query = mOcclusionQueries[mCurrentTestIdx++];
208               
209                query->beginOcclusionQuery();
210                               
211                renderBoundingBox(node);
212
213                query->endOcclusionQuery();
214
215                return query;
216        }
217        //-----------------------------------------------------------------------
218        void OcclusionCullingSceneTraverser::setRenderingMode( int mode )
219        {       
220                // avoid unnecessary state changes
221                if(mode != mQueryMode)
222                {
223                        bool enabled = (mode == MODE_RENDER);
224                       
225                        mRenderSystem->_setColourBufferWriteEnabled(enabled,
226                                enabled, enabled, enabled);
227                        mRenderSystem->_setDepthBufferWriteEnabled(enabled);
228                        mRenderSystem->setLightingEnabled(enabled);
229
230                        mQueryMode = mode;
231                }
232        }
233        //-----------------------------------------------------------------------
234        void OcclusionCullingSceneTraverser::traverseNode( Camera *cam, SceneNode *node )
235        {
236                mNumTraversedNodes ++;
237               
238                if(node->numAttachedObjects() > 0)
239                {
240                        renderSceneNode(cam, node);
241                }
242
243                // internal node: add children to priority queue for further processing
244                Node::ChildNodeIterator it = node->getChildIterator();
245                                       
246                while (it.hasMoreElements())                   
247                {
248                        SceneNode* sceneChild = static_cast<SceneNode*>(it.getNext());
249                        mDistanceQueue->push(sceneChild);
250                }
251        }
252        //-----------------------------------------------------------------------
253        void OcclusionCullingSceneTraverser::renderSceneNode( Camera *cam, SceneNode *node )
254        {
255                setRenderingMode(MODE_RENDER);
256               
257                //HACK (too slow)
258                mSceneManager->_renderSceneNode(cam, node);
259                //MessageBox( NULL, "myplugin registered", "this is my plugin", MB_OK | MB_ICONERROR | MB_TASKMODAL);
260        }
261        //-----------------------------------------------------------------------
262        void OcclusionCullingSceneTraverser::preprocess( void )
263        {
264                //-- initialise occlusion queries.
265                deleteQueries();
266               
267                for(unsigned int i=0; i < mNumSceneNodes; i++)
268                {
269                        mOcclusionQueries.push_back(mRenderSystem->createHardwareOcclusionQuery());
270                }       
271        }
272        //-----------------------------------------------------------------------
273        void OcclusionCullingSceneTraverser::setSceneManager( SceneManager *sm )
274        {
275                mSceneManager = sm;
276        }
277        //-----------------------------------------------------------------------
278        void OcclusionCullingSceneTraverser::setRenderSystem( RenderSystem *rsys )
279        {
280                mRenderSystem = rsys;
281        }
282        //-----------------------------------------------------------------------
283        /*unsigned int OcclusionCullingSceneManager::countSceneNodes(SceneNode *node)
284        {
285                unsigned int result = 1;
286               
287                Node::ChildNodeIterator it = node->getChildIterator();
288               
289                while (it.hasMoreElements())
290                {
291                        SceneNode* sceneChild = static_cast<SceneNode*>(it.getNext());
292                        result += countSceneNodes(sceneChild);
293        }
294
295                return result;
296        }*/
297        //-----------------------------------------------------------------------
298        bool OcclusionCullingSceneTraverser::isLeaf( SceneNode *node )
299        {
300                return (node->numChildren() == 0);
301        }
302        //-----------------------------------------------------------------------
303        void OcclusionCullingSceneTraverser::pullUpVisibility( SceneNode *node )
304        {
305                while(node && !node->isNodeVisible())
306                {
307                        node->setNodeVisible(true);
308                        node = static_cast<SceneNode *>(node->getParent());
309                }
310        }
311        //-----------------------------------------------------------------------
312        void OcclusionCullingSceneTraverser::deleteQueries( void )
313        {
314                for(unsigned int i=0; i < mNumSceneNodes; i++)
315                        delete mOcclusionQueries[i];
316
317                mOcclusionQueries.clear();
318        }
319        //-----------------------------------------------------------------------
320        void OcclusionCullingSceneTraverser::renderBoundingBox( SceneNode *node )
321        {
322                // Render two halfes of the bounding box (using triangle fans)
323                for(int half = 0; half < 2; half ++)
324                {
325                        SolidHalfBoundingBox *box = getSolidHalfBoundingBox(half);
326                       
327                        box->setupBoundingBox(node->_getWorldAABB());
328
329                        static RenderOperation ro;
330                        mSceneManager->useRenderableViewProjMode(box);
331                        box->getRenderOperation(ro);
332                        ro.srcRenderable = box;
333                        mRenderSystem->_render(ro);
334
335                        //mSceneManager->renderSingleObject(getSolidHalfBoundingBox(half),
336                        //      getSolidHalfBoundingBox(half)->getTechnique()->getPass(0), false);
337                }
338        }
339        //-----------------------------------------------------------------------
340        SolidHalfBoundingBox *OcclusionCullingSceneTraverser::getSolidHalfBoundingBox( int half )
341        {
342                if(!mHalfBoundingBox[half])
343                        mHalfBoundingBox[half] = new SolidHalfBoundingBox(half == 1);
344
345                return mHalfBoundingBox[half]; 
346        }
347        //-----------------------------------------------------------------------
348        bool OcclusionCullingSceneTraverser::setOption( const String & key, const void * val )
349        {
350                if ( key == "Algorithm" )
351                {
352                        mCurrentAlgorithm = * static_cast < const int * > ( val );
353                        return true;
354                }
355                if ( key == "Threshold" )
356                {
357                        mVisibilityThreshold = * static_cast < const int * > ( val );
358                        return true;
359                }
360
361                return false;
362        }
363        //-----------------------------------------------------------------------
364        bool OcclusionCullingSceneTraverser::getOption( const String & key, void *val )
365        {
366                if ( key == "Algorithm" )
367                {
368                        * static_cast < int * > ( val ) = mCurrentAlgorithm;
369                        return true;
370                }
371                if ( key == "Threshold" )
372                {
373                        * static_cast < unsigned int * > ( val ) = mVisibilityThreshold;
374                        return true;
375                }
376                if ( key == "NumSceneNodes" )
377                {
378                        * static_cast < unsigned int * > ( val ) = mNumSceneNodes;
379                        return true;
380                }
381                if ( key == "NumTraversedNodes" )
382                {
383                        * static_cast < unsigned int * > ( val ) = mNumTraversedNodes;
384                        return true;
385                }
386                if ( key == "NumQueryCulledNodes" )
387                {
388                        * static_cast < unsigned int * > ( val ) = mNumQueryCulledNodes;
389                        return true;
390                }
391                if ( key == "NumFrustumCulledNodes" )
392                {
393                        * static_cast < unsigned int * > ( val ) = mNumFrustumCulledNodes;
394                        return true;
395                }
396                return false;
397        }
398        //-----------------------------------------------------------------------
399        bool OcclusionCullingSceneTraverser::getOptionKeys( StringVector & refKeys )
400        {
401                refKeys.push_back( "Algorithm" );
402                refKeys.push_back( "Threshold" );
403                refKeys.push_back( "NumSceneNodes" );
404                refKeys.push_back( "NumTraversedNodes" );
405                refKeys.push_back( "NumQueryCulledNodes" );
406                refKeys.push_back( "NumFrustumCulledNodes" );
407                //refKeys.push_back( "mNumRenderedGeometry" );
408
409                return true;
410        }
411        //-----------------------------------------------------------------------
412        void OcclusionCullingSceneTraverser::setNumSceneNodes(int num)
413        {
414                mNumSceneNodes = num;
415        }
416}       
Note: See TracBrowser for help on using the repository browser.