source: trunk/VUT/OcclusionCullingSceneManager/src/OgreOcclusionCullingSceneManager.cpp @ 29

Revision 29, 11.2 KB checked in by gametools, 19 years ago (diff)
Line 
1#include "OgreOcclusionCullingSceneManager.h"
2#include "OgreMath.h"
3#include "OgreIteratorWrappers.h"
4#include "OgreRenderSystem.h"
5#include "OgreCamera.h"
6#include "OgreHardwareOcclusionQuery.h"
7//#include "OgreWireBoundingBox.h"
8#include "OgreSolidHalfBoundingBox.h"
9
10#include <windows.h>
11
12namespace Ogre {
13       
14        //-----------------------------------------------------------------------
15        OcclusionCullingSceneManager::OcclusionCullingSceneManager():
16        mFrameId(1), mDistanceQueue(NULL), mVisibilityThreshold(0), mCurrentTestIdx(0),
17        mQueryMode(MODE_RENDER), mNumSceneNodes(0), mCurrentAlgorithm(RENDER_COHERENT)
18        {               
19                mHalfBoundingBox[0] = mHalfBoundingBox[1] = 0;
20        }
21        //-----------------------------------------------------------------------
22        void OcclusionCullingSceneManager::_findVisibleObjects(Camera* cam, bool onlyShadowCasters)
23        {
24                // empty because we have to find in _renderVisibleObjects
25        }
26        //-----------------------------------------------------------------------
27        OcclusionCullingSceneManager::~OcclusionCullingSceneManager()
28        {               
29                if(mHalfBoundingBox[0]) delete mHalfBoundingBox[0];
30                if(mHalfBoundingBox[1]) delete mHalfBoundingBox[1];
31
32                deleteQueries();
33                //SceneManager::~SceneManager();
34        }
35        //-----------------------------------------------------------------------
36        void OcclusionCullingSceneManager::_renderVisibleObjects(void)
37        {
38                mDistanceQueue = new PriorityQueue(myless<SceneNode *>(mCameraInProgress));
39               
40                mDistanceQueue->push(mSceneRoot);
41
42                mCurrentTestIdx = 0;
43
44                //renderZPass();
45
46                switch(mCurrentAlgorithm)
47                {
48                        case RENDER_CULL_FRUSTUM:
49                                renderCullFrustum();
50                        break;
51                        case RENDER_STOP_AND_WAIT:
52                                renderStopAndWait();
53                                break;
54                        case RENDER_COHERENT:
55                                renderCoherentWithQueue();
56                                break;
57                        default:
58                                renderCullFrustum();
59                                break;
60                }       
61               
62                delete mDistanceQueue;
63
64                /*mDestRenderSystem->_setDepthBufferParams(true, false, CMPF_LESS);
65                  SceneManager::_renderVisibleObjects();
66                  mDestRenderSystem->_setDepthBufferParams();
67          mDistanceQueue.push(mSceneRoot);
68                  Preprocess();
69                  //ResetQueries();
70                */
71               
72                mFrameId ++;
73        }
74        //-----------------------------------------------------------------------
75        void OcclusionCullingSceneManager::renderZPass()
76        {
77                traverseNode(mSceneRoot);
78        }
79        //-----------------------------------------------------------------------
80        void OcclusionCullingSceneManager::renderCoherentWithQueue()
81        {
82                QueryQueue queryQueue;
83
84                //-- PART 1: process finished occlusion queries
85                while(!mDistanceQueue->empty() || !queryQueue.empty())
86                {
87                        while(!queryQueue.empty() &&
88                                  ((queryQueue.front().second)->resultAvailable() || mDistanceQueue->empty()))
89                        {
90                                SceneNode *node = queryQueue.front().first;
91                                HardwareOcclusionQuery *query = queryQueue.front().second;
92
93                                queryQueue.pop();
94                       
95                                // wait until result available
96                                unsigned int visiblePixels;
97                                query->pullOcclusionQuery(&visiblePixels);
98
99                                if(visiblePixels > mVisibilityThreshold)
100                                {
101                                        pullUpVisibility(node);
102                                        traverseNode(node);
103                                }
104                        }       
105
106                        //-- PART 2: hierarchical traversal
107                        if(!mDistanceQueue->empty())
108                        {
109                                SceneNode *node = mDistanceQueue->top();
110
111                                mDistanceQueue->pop();
112       
113                                if(mCameraInProgress->isVisible(node->_getWorldAABB()))
114                                {
115                                        // identify previously visible nodes
116                                        bool wasVisible = node->isNodeVisible() && (node->lastVisited() == mFrameId - 1);
117                                       
118                                        // identify nodes that we cannot skip queries for
119                                        bool leafOrWasInvisible = !wasVisible || isLeaf(node);
120
121                                        // reset node's visibility classification
122                                        node->setNodeVisible(false);
123
124                                        // update node's visited flag
125                                        node->setLastVisited(mFrameId);
126                               
127                                        // skip testing previously visible interior nodes
128                                        if(leafOrWasInvisible)
129                                        {
130                                                HardwareOcclusionQuery *query = issueOcclusionQuery(node, wasVisible);
131                                                queryQueue.push(query_pair(node, query));
132                                        }
133                                       
134                                        // always traverse a node if it was visible
135                                        if(wasVisible)
136                                                traverseNode(node);
137                                }
138                        }
139                }
140        }
141        //-----------------------------------------------------------------------
142        void OcclusionCullingSceneManager::renderCullFrustum()
143        {
144                while(!mDistanceQueue->empty())
145                {
146                        SceneNode *node = mDistanceQueue->top();
147                        mDistanceQueue->pop();
148       
149                        // interesting for visualization purpose
150                        node->setNodeVisible(false);
151                               
152                        if(mCameraInProgress->isVisible(node->_getWorldAABB()))
153                        {
154                                // update node's visited flag
155                                node->setLastVisited(mFrameId);
156                                node->setNodeVisible(true);
157                                traverseNode(node);
158                        }
159                }
160        }       
161        //-----------------------------------------------------------------------
162        void OcclusionCullingSceneManager::renderStopAndWait()
163        {
164                while(!mDistanceQueue->empty())
165                {
166                        SceneNode *node = mDistanceQueue->top();
167                        mDistanceQueue->pop();
168               
169                        // interesting for the visualization
170                        node->setNodeVisible(false);
171                        node->setLastVisited(mFrameId);
172
173                        if(mCameraInProgress->isVisible(node->_getWorldAABB()))
174                        {
175                                HardwareOcclusionQuery *query = issueOcclusionQuery(node, false);
176                               
177                                unsigned int visiblePixels;
178                                // wait if result not available
179                                query->pullOcclusionQuery(&visiblePixels);
180                               
181                                //char str[100]; sprintf(str, "number: %d, id: %d", (int)visiblePixels, mCurrentTestIdx);
182                                //MessageBox( NULL, str, "this is my plugin", MB_OK | MB_ICONERROR | MB_TASKMODAL);
183
184                                // node visible
185                                if(visiblePixels > mVisibilityThreshold)
186                                {
187                                        traverseNode(node);
188                                }
189                        }                                       
190                }
191        }
192        //-----------------------------------------------------------------------
193        HardwareOcclusionQuery *OcclusionCullingSceneManager::issueOcclusionQuery(SceneNode *node, bool wasVisible)
194        {
195                // change state so the bounding box gets not actually rendered on the screen
196                setRenderingMode(MODE_QUERY);
197
198                // get next available test id
199                HardwareOcclusionQuery *query = mOcclusionQueries[mCurrentTestIdx++];
200               
201                query->beginOcclusionQuery();
202               
203                /*
204                static RenderOperation ro;
205
206                // Issue view / projection changes if any
207                useRenderableViewProjMode(&box);
208
209                box.getRenderOperation(ro);
210                ro.srcRenderable = &box;
211                mDestRenderSystem->_render(ro);
212                */
213                               
214                renderBoundingBox(node);
215
216                query->endOcclusionQuery();
217
218                return query;
219        }
220
221        //-----------------------------------------------------------------------
222        void OcclusionCullingSceneManager::setRenderingMode(int mode)
223        {       
224                // avoid unnecessary state changes
225                if(mode != mQueryMode)
226                {
227                        bool enabled = (mode == MODE_RENDER);
228                       
229                        mDestRenderSystem->_setColourBufferWriteEnabled(enabled,
230                                enabled, enabled, enabled);
231                        mDestRenderSystem->_setDepthBufferWriteEnabled(enabled);
232                        mDestRenderSystem->setLightingEnabled(enabled);
233                        mQueryMode = mode;
234                }
235        }
236        //-----------------------------------------------------------------------
237        void OcclusionCullingSceneManager::traverseNode(SceneNode *node)
238        {
239                if(isLeaf(node))
240                {
241                        render(node);
242                }
243                else // internal node: add children to priority queue for further processing
244                {
245                        Node::ChildNodeIterator it = node->getChildIterator();
246                                       
247                        while (it.hasMoreElements())
248                        {
249                                SceneNode* sceneChild = static_cast<SceneNode*>(it.getNext());
250                                mDistanceQueue->push(sceneChild);
251                        }
252                 }
253        }
254        //-----------------------------------------------------------------------
255        void OcclusionCullingSceneManager::render(SceneNode *node)
256        {
257                //setRenderingMode(MODE_RENDER);
258                //MessageBox( NULL, "harhar", "this is my plugin", MB_OK | MB_ICONERROR | MB_TASKMODAL);
259                //HACK (too slow)
260                node->_findVisibleObjects(mCameraInProgress, getRenderQueue(), false,
261                                                                  mDisplayNodes, false);
262                SceneManager::_renderVisibleObjects();
263                getRenderQueue()->clear();
264        }
265        //-----------------------------------------------------------------------
266        void OcclusionCullingSceneManager::_updateSceneGraph(Camera* cam)
267        {
268                int numnodes = countSceneNodes(mSceneRoot);
269               
270                //-- initialise occlusion queries.
271                if(numnodes != mNumSceneNodes)
272                {
273                        deleteQueries();
274                        mNumSceneNodes = numnodes;
275
276                        for(unsigned int i=0; i < mNumSceneNodes; i++)
277                        {
278                                HardwareOcclusionQuery *hw = mDestRenderSystem->createHardwareOcclusionQuery();
279                                mOcclusionQueries.push_back(hw);
280                        }
281                }
282
283                SceneManager::_updateSceneGraph(cam);
284        }
285        //-----------------------------------------------------------------------
286        int OcclusionCullingSceneManager::countSceneNodes(SceneNode *node)
287        {
288                int num = 1;
289                if(isLeaf(node))
290                {
291                        return num;
292                }
293
294                Node::ChildNodeIterator it = node->getChildIterator();
295               
296                while (it.hasMoreElements())
297                {
298                        SceneNode* sceneChild = static_cast<SceneNode*>(it.getNext());
299                        num += countSceneNodes(sceneChild);
300        }
301
302                return num;
303        }
304        //-----------------------------------------------------------------------
305        int OcclusionCullingSceneManager::isLeaf(SceneNode *node)
306        {
307                return (node->numChildren() == 0);
308        }
309        //-----------------------------------------------------------------------
310        void OcclusionCullingSceneManager::pullUpVisibility(SceneNode *node)
311        {
312                while(!node->isNodeVisible())
313                {
314                        node->setNodeVisible(true);
315                       
316                        if(node != mSceneRoot)
317                                node = static_cast<SceneNode *>(node->getParent());
318                }
319        }
320        //-----------------------------------------------------------------------
321        void OcclusionCullingSceneManager::deleteQueries()
322        {
323                for(unsigned int i=0; i < mNumSceneNodes; i++)
324                        delete mOcclusionQueries[i];
325
326                mOcclusionQueries.clear();
327        }
328        //-----------------------------------------------------------------------
329        void OcclusionCullingSceneManager::renderBoundingBox(SceneNode *node)
330        {
331                // Render two halfes of the bounding box (using triangle fans)
332                for(int half=0; half < 2; half ++)
333                {
334                        getSolidHalfBoundingBox(half)->setupBoundingBox(node->_getWorldAABB());
335                        SceneManager::renderSingleObject(getSolidHalfBoundingBox(half),
336                                getSolidHalfBoundingBox(half)->getTechnique()->getPass(0), false);
337                }
338        }
339        //-----------------------------------------------------------------------
340        SolidHalfBoundingBox *OcclusionCullingSceneManager::getSolidHalfBoundingBox(int half)
341        {
342                if(!mHalfBoundingBox[half])
343                        mHalfBoundingBox[half] = new SolidHalfBoundingBox(half == 1);
344
345                return mHalfBoundingBox[half]; 
346        }
347        //-----------------------------------------------------------------------
348        bool OcclusionCullingSceneManager::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       
356                return SceneManager::setOption( key, val );
357        }
358        //-----------------------------------------------------------------------
359        bool OcclusionCullingSceneManager::getOption( const String & key, void *val )
360        {
361                if ( key == "Algorithm" )
362                {
363                        * static_cast < int * > ( val ) = mCurrentAlgorithm;
364                        return true;
365                }
366
367                return SceneManager::getOption( key, val );
368        }
369        //-----------------------------------------------------------------------
370        bool OcclusionCullingSceneManager::getOptionValues( const String & key, StringVector  &refValueList )
371        {
372                return SceneManager::getOptionValues( key, refValueList );
373        }
374        //-----------------------------------------------------------------------
375        bool OcclusionCullingSceneManager::getOptionKeys( StringVector & refKeys )
376        {
377                SceneManager::getOptionKeys( refKeys );
378                refKeys.push_back( "Algorithm" );
379       
380                return true;
381        }
382}       
Note: See TracBrowser for help on using the repository browser.