[45] | 1 | #include "OgreOcclusionCullingOctreeSceneTraverser.h"
|
---|
[48] | 2 | #include "OgreOcclusionCullingOctreeSceneManager.h"
|
---|
[45] | 3 | #include "OgreHardwareOcclusionQuery.h"
|
---|
| 4 |
|
---|
| 5 | #include <windows.h>
|
---|
| 6 |
|
---|
| 7 | namespace Ogre {
|
---|
| 8 | //-----------------------------------------------------------------------
|
---|
[48] | 9 | OcclusionCullingOctreeSceneTraverser::OcclusionCullingOctreeSceneTraverser(SceneManager *sm, RenderSystem *rsys):
|
---|
[45] | 10 | OcclusionCullingSceneTraverser(sm, rsys), mOctreeSceneRoot(0), mOctreeDistanceQueue(0)
|
---|
| 11 | {
|
---|
| 12 | }
|
---|
| 13 | //-----------------------------------------------------------------------
|
---|
[48] | 14 | OcclusionCullingOctreeSceneTraverser::~OcclusionCullingOctreeSceneTraverser()
|
---|
[45] | 15 | {
|
---|
| 16 | if(mOctreeDistanceQueue)
|
---|
| 17 | delete mOctreeDistanceQueue;
|
---|
| 18 | }
|
---|
| 19 | //-----------------------------------------------------------------------
|
---|
[52] | 20 | void OcclusionCullingOctreeSceneTraverser::traverseOctant(Camera *cam, Octree *octant)
|
---|
[45] | 21 | {
|
---|
| 22 | mNumTraversedNodes ++;
|
---|
| 23 |
|
---|
| 24 | // if we come across some renderable geometry => render it
|
---|
| 25 | renderOctant(cam, octant); |
---|
| 26 |
|
---|
| 27 | for(int i=0; i<8; i++)
|
---|
| 28 | {
|
---|
| 29 | Octree *nextChild = octant->mChildren[(i & 4) >> 2][(i & 2) >> 1][i & 1];
|
---|
[51] | 30 |
|
---|
| 31 | /*char msg[100];
|
---|
| 32 | sprintf(msg, "node number: %d %d %d\n", (i & 4) >> 2, (i & 2) >> 1, i & 1);
|
---|
| 33 | OutputDebugString(msg);*/
|
---|
| 34 |
|
---|
[45] | 35 | if(nextChild)
|
---|
[52] | 36 | {
|
---|
[45] | 37 | mOctreeDistanceQueue->push(nextChild);
|
---|
[52] | 38 | }
|
---|
[45] | 39 | }
|
---|
| 40 | }
|
---|
| 41 | //-----------------------------------------------------------------------
|
---|
[48] | 42 | void OcclusionCullingOctreeSceneTraverser::renderCullFrustum(Camera *cam)
|
---|
[45] | 43 | {
|
---|
| 44 | AxisAlignedBox box;
|
---|
| 45 |
|
---|
| 46 | while(!mOctreeDistanceQueue->empty()) |
---|
| 47 | { |
---|
| 48 | Octree *octant = mOctreeDistanceQueue->top(); |
---|
| 49 | mOctreeDistanceQueue->pop(); |
---|
| 50 | |
---|
| 51 | // interesting for visualization purpose |
---|
[51] | 52 | octant->setOctreeVisible(false); |
---|
[45] | 53 | octant->_getCullBounds(&box); |
---|
| 54 | |
---|
| 55 | if(!cam->isVisible(box)) |
---|
| 56 | { |
---|
| 57 | mNumFrustumCulledNodes ++; |
---|
| 58 | continue; |
---|
| 59 | } |
---|
| 60 | |
---|
| 61 | // update node's visited flag |
---|
| 62 | octant->setLastVisited(mFrameId); |
---|
| 63 | octant->setOctreeVisible(true); |
---|
| 64 |
|
---|
| 65 | traverseOctant(cam, octant); |
---|
| 66 | }
|
---|
| 67 | }
|
---|
| 68 | //----------------------------------------------------------------------- |
---|
| 69 | /** Renders the scene with the hierarchical stop and wait algorithm. */ |
---|
[48] | 70 | void OcclusionCullingOctreeSceneTraverser::renderStopAndWait( Camera *cam ) |
---|
[45] | 71 | { |
---|
| 72 | AxisAlignedBox box; |
---|
| 73 | |
---|
| 74 | while(!mOctreeDistanceQueue->empty()) |
---|
| 75 | { |
---|
| 76 | Octree *octant = mOctreeDistanceQueue->top(); |
---|
| 77 | mOctreeDistanceQueue->pop(); |
---|
| 78 | |
---|
| 79 | // interesting for visualization purpose |
---|
| 80 | octant->setOctreeVisible(false); |
---|
| 81 | octant->setLastVisited(mFrameId); |
---|
| 82 | |
---|
| 83 | //TODO: Isvisible also checked inside scenenode::findvisibleobjects |
---|
| 84 | octant->_getCullBounds(&box); |
---|
| 85 | |
---|
| 86 | bool intersects = false; |
---|
| 87 | |
---|
[52] | 88 | /*char msg2[100];
|
---|
| 89 | Vector3 min = box.getMinimum();
|
---|
| 90 | Vector3 max = box.getMaximum();
|
---|
| 91 |
|
---|
| 92 | sprintf(msg2, "culling box: %3.3f %3.3f %3.3f %3.3f %3.3f %3.3f\n", min.x, min.y, min.z, max.x, max.y, max.z);
|
---|
| 93 | OutputDebugString(msg2);*/ |
---|
| 94 | |
---|
[45] | 95 | if(!cam->isVisible(box, intersects)) |
---|
| 96 | { |
---|
| 97 | mNumFrustumCulledNodes ++; |
---|
| 98 | continue; |
---|
| 99 | } |
---|
| 100 | //if intersects near plane => skip occlusion query because wrong results possible |
---|
| 101 | if(intersects) |
---|
| 102 | { |
---|
| 103 | octant->setOctreeVisible(true); |
---|
[52] | 104 | // char msg[100]; sprintf(msg, "intersecting\n"); |
---|
| 105 | // OutputDebugString(msg); |
---|
[45] | 106 | traverseOctant(cam, octant); |
---|
| 107 | continue; |
---|
| 108 | } |
---|
| 109 | |
---|
| 110 | HardwareOcclusionQuery *query = issueOcclusionQuery(&box, false); |
---|
| 111 | |
---|
| 112 | unsigned int visiblePixels; |
---|
| 113 | // wait if result not available |
---|
| 114 | query->pullOcclusionQuery(&visiblePixels); |
---|
[52] | 115 | |
---|
| 116 | char msg[100]; sprintf(msg, "visible pixels: %d\n", visiblePixels, intersects); |
---|
| 117 | OutputDebugString(msg); |
---|
| 118 | |
---|
[45] | 119 | // node visible |
---|
| 120 | if(visiblePixels > mVisibilityThreshold) |
---|
| 121 | { |
---|
| 122 | traverseOctant(cam, octant); |
---|
| 123 | } |
---|
| 124 | else |
---|
| 125 | { |
---|
| 126 | mNumQueryCulledNodes ++; |
---|
| 127 | } |
---|
| 128 | } |
---|
| 129 | } |
---|
| 130 | //----------------------------------------------------------------------- |
---|
| 131 | /** Renders the scene with the coherent hierarchical algorithm and the query queye. */ |
---|
[48] | 132 | void OcclusionCullingOctreeSceneTraverser::renderCoherentWithQueue( Camera *cam )
|
---|
[45] | 133 | {
|
---|
| 134 | OctreeQueryQueue queryQueue; |
---|
| 135 | AxisAlignedBox box; |
---|
| 136 | |
---|
| 137 | //-- PART 1: process finished occlusion queries |
---|
| 138 | while(!mOctreeDistanceQueue->empty() || !queryQueue.empty()) |
---|
| 139 | { |
---|
| 140 | while(!queryQueue.empty() && |
---|
| 141 | ((queryQueue.front().second)->resultAvailable() || mOctreeDistanceQueue->empty())) |
---|
| 142 | { |
---|
| 143 | Octree *octant = queryQueue.front().first; |
---|
| 144 | HardwareOcclusionQuery *query = queryQueue.front().second; |
---|
| 145 | |
---|
| 146 | queryQueue.pop(); |
---|
| 147 | |
---|
| 148 | // wait until result available |
---|
| 149 | unsigned int visiblePixels; |
---|
| 150 | query->pullOcclusionQuery(&visiblePixels); |
---|
[52] | 151 | |
---|
[45] | 152 | if(visiblePixels > mVisibilityThreshold) |
---|
| 153 | { |
---|
[52] | 154 | pullUpVisibility(octant); |
---|
[45] | 155 | traverseOctant(cam, octant); |
---|
| 156 | } |
---|
| 157 | else |
---|
| 158 | { |
---|
| 159 | mNumQueryCulledNodes ++; |
---|
| 160 | } |
---|
| 161 | } |
---|
| 162 | |
---|
| 163 | //-- PART 2: hierarchical traversal |
---|
| 164 | if(!mOctreeDistanceQueue->empty()) |
---|
| 165 | { |
---|
| 166 | Octree *octant = mOctreeDistanceQueue->top(); |
---|
| 167 | mOctreeDistanceQueue->pop(); |
---|
| 168 | |
---|
| 169 | octant->_getCullBounds(&box); |
---|
| 170 | |
---|
| 171 | bool intersects = false; |
---|
| 172 | //TODO: Isvisible also checked inside scenenode::findvisibleobjects |
---|
| 173 | if(!cam->isVisible(box, intersects)) |
---|
| 174 | { |
---|
| 175 | mNumFrustumCulledNodes ++; |
---|
| 176 | continue; |
---|
| 177 | } |
---|
| 178 | |
---|
| 179 | // if intersects near plane => skip occlusion query because wrong results possible |
---|
| 180 | if(intersects) |
---|
| 181 | { |
---|
[51] | 182 | // update octant's visited flag |
---|
[45] | 183 | octant->setLastVisited(mFrameId); |
---|
[52] | 184 | |
---|
| 185 | pullUpVisibility(octant); |
---|
[45] | 186 | traverseOctant(cam, octant); |
---|
| 187 | |
---|
| 188 | continue; |
---|
| 189 | } |
---|
| 190 | |
---|
| 191 | // identify previously visible nodes |
---|
| 192 | bool wasVisible = octant->isOctreeVisible() && (octant->lastVisited() == mFrameId - 1); |
---|
[51] | 193 | |
---|
[52] | 194 | /* |
---|
| 195 | char msg[100]; |
---|
[51] | 196 | if(wasVisible) sprintf(msg, "yes, was visible, %d\n", mFrameId); |
---|
| 197 | else sprintf(msg, "no was invisible, %d\n", mFrameId); |
---|
[52] | 198 | OutputDebugString(msg); |
---|
| 199 | */ |
---|
[51] | 200 | |
---|
[45] | 201 | // identify nodes that we cannot skip queries for |
---|
[52] | 202 | bool mustQuery = !wasVisible || (octant->numNodes() > 0) || isLeaf(octant); |
---|
[45] | 203 | |
---|
| 204 | // reset node's visibility classification |
---|
| 205 | octant->setOctreeVisible(false); |
---|
| 206 | |
---|
| 207 | // update node's visited flag |
---|
| 208 | octant->setLastVisited(mFrameId); |
---|
| 209 | |
---|
| 210 | // skip testing previously visible interior nodes |
---|
[52] | 211 | if(mustQuery) |
---|
[45] | 212 | { |
---|
| 213 | HardwareOcclusionQuery *query = issueOcclusionQuery(&box, wasVisible); |
---|
| 214 | queryQueue.push(OctreeQueryPair(octant, query)); |
---|
| 215 | } |
---|
| 216 | |
---|
| 217 | // always traverse a node if it was visible |
---|
| 218 | if(wasVisible) |
---|
| 219 | { |
---|
| 220 | traverseOctant(cam, octant); |
---|
| 221 | } |
---|
| 222 | } |
---|
| 223 | }
|
---|
| 224 | }
|
---|
| 225 | //-----------------------------------------------------------------------
|
---|
[52] | 226 | void OcclusionCullingOctreeSceneTraverser::pullUpVisibility( Octree *octant )
|
---|
[45] | 227 | {
|
---|
| 228 | while(octant && !octant->isOctreeVisible()) |
---|
| 229 | { |
---|
| 230 | octant->setOctreeVisible(true); |
---|
| 231 | octant = octant->getParent(); |
---|
| 232 | }
|
---|
| 233 | }
|
---|
| 234 | //-----------------------------------------------------------------------
|
---|
[48] | 235 | void OcclusionCullingOctreeSceneTraverser::renderOctant( Camera *cam, Octree *octant )
|
---|
[45] | 236 | {
|
---|
[52] | 237 | if(octant->lastRendered() != mFrameId)
|
---|
[45] | 238 | {
|
---|
[52] | 239 | octant->setLastRendered(mFrameId);
|
---|
| 240 |
|
---|
| 241 | if(octant->numNodes() == 0) return;
|
---|
| 242 |
|
---|
[51] | 243 | //TODO: does nothing useful
|
---|
| 244 | setRenderingMode(MODE_RENDER);
|
---|
[45] | 245 |
|
---|
[51] | 246 | ((OctreeSceneManager *)mSceneManager)->_renderOctant(cam, octant);
|
---|
[52] | 247 |
|
---|
| 248 | mNumRenderedNodes ++;
|
---|
[45] | 249 | }
|
---|
| 250 | }
|
---|
| 251 | //-----------------------------------------------------------------------
|
---|
[52] | 252 | void OcclusionCullingOctreeSceneTraverser::setSceneRoot( Octree *root )
|
---|
[45] | 253 | {
|
---|
| 254 | mOctreeSceneRoot = root;
|
---|
| 255 | }
|
---|
| 256 | //-----------------------------------------------------------------------
|
---|
[52] | 257 | void OcclusionCullingOctreeSceneTraverser::initDistanceQueue( Camera *cam )
|
---|
[45] | 258 | {
|
---|
| 259 | if(mOctreeDistanceQueue)
|
---|
| 260 | delete mOctreeDistanceQueue;
|
---|
| 261 |
|
---|
| 262 | mOctreeDistanceQueue = new OctreePriorityQueue(octreeless<Octree *>(cam));
|
---|
| 263 | mOctreeDistanceQueue->push(mOctreeSceneRoot);
|
---|
| 264 | }
|
---|
| 265 | //-----------------------------------------------------------------------
|
---|
[48] | 266 | bool OcclusionCullingOctreeSceneTraverser::isLeaf(Octree *octant)
|
---|
[45] | 267 | {
|
---|
| 268 | for(int i=0; i<8; i++)
|
---|
| 269 | {
|
---|
| 270 | if(octant->mChildren[(i & 4) >> 2][(i & 2) >> 1][i & 1])
|
---|
| 271 | return false;
|
---|
| 272 | }
|
---|
| 273 |
|
---|
| 274 | return true;
|
---|
| 275 | }
|
---|
| 276 | //-----------------------------------------------------------------------
|
---|
[48] | 277 | void OcclusionCullingOctreeSceneTraverser::setNumOctreeNodes(unsigned int num)
|
---|
[45] | 278 | {
|
---|
| 279 | mNumOctreeNodes = num;
|
---|
| 280 | }
|
---|
| 281 | //-----------------------------------------------------------------------
|
---|
[48] | 282 | bool OcclusionCullingOctreeSceneTraverser::getOption( const String & key, void *val )
|
---|
[45] | 283 | {
|
---|
[52] | 284 | if (key == "NumOctreeNodes")
|
---|
[45] | 285 | {
|
---|
| 286 | * static_cast < unsigned int * > ( val ) = mNumOctreeNodes;
|
---|
| 287 | return true;
|
---|
| 288 | }
|
---|
| 289 |
|
---|
| 290 | return OcclusionCullingSceneTraverser::getOption(key, val);
|
---|
| 291 | }
|
---|
| 292 | //-----------------------------------------------------------------------
|
---|
[48] | 293 | bool OcclusionCullingOctreeSceneTraverser::getOptionKeys( StringVector & refKeys )
|
---|
[45] | 294 | {
|
---|
[52] | 295 | refKeys.push_back("NumOctreeNodes");
|
---|
[45] | 296 |
|
---|
| 297 | return OcclusionCullingSceneTraverser::getOptionKeys(refKeys);
|
---|
| 298 | }
|
---|
| 299 | } |
---|