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

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