Changeset 1296 for GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE
- Timestamp:
- 08/29/06 18:28:00 (18 years ago)
- Location:
- GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE
- Files:
-
- 8 edited
Legend:
- Unmodified
- Added
- Removed
-
GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/include/OgreBoundingBoxConverter.h
r933 r1296 12 12 class Entity; 13 13 class OctreeSceneManager; 14 class KdTreeSceneManager; 14 15 15 16 /** Class which converts preprocessor types to OGRE types … … 19 20 public: 20 21 OgreBoundingBoxConverter(OctreeSceneManager *sm); 22 OgreBoundingBoxConverter(KdTreeSceneManager *sm); 21 23 22 24 bool IdentifyObjects(const GtpVisibilityPreprocessor::IndexedBoundingBoxContainer &iboxes, … … 28 30 Entity *FindCorrespondingObject(const AxisAlignedBox &box) const; 29 31 30 OctreeSceneManager *mSceneMgr; 32 OctreeSceneManager *mOctSceneMgr; 33 KdTreeSceneManager *mKdSceneMgr; 31 34 }; 32 35 -
GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/include/OgreKdTree.h
r1250 r1296 561 561 //void findVisibleNodes(NodeList& visibleNodes, Camera * cam); 562 562 563 /** Recurses the kdtree, adding any nodes intersecting with the 564 box/sphere/volume/ray into the given list. 565 It ignores the exclude scene node. 566 */ 567 void findNodesIn(const AxisAlignedBox &box, std::list<SceneNode *> &list, SceneNode *exclude = 0); 568 void findNodesIn(const Sphere &sphere, std::list<SceneNode *> &list, SceneNode *exclude = 0); 569 void findNodesIn(const PlaneBoundedVolume &volume, std::list<SceneNode *> &list, SceneNode *exclude = 0); 570 void findNodesIn(const Ray &ray, std::list<SceneNode *> &list, SceneNode *exclude = 0); 571 563 572 // self-explanatory ... 564 573 int getMaxDepth(void) { return mMaxDepth; }; 565 StatsgetStats(void) const { return mStats; };574 const Stats& getStats(void) const { return mStats; }; 566 575 AxisAlignedBox getBox(void) { if (mKdRoot) return mKdRoot->mAABB; else return AxisAlignedBox(); }; 567 576 void setBuildMethod(BuildMethod bm) { mBuildMethod = bm; } … … 598 607 //void recFindVisibleNodes(KdTree::Node * node, NodeList& visibleNodes, Camera * cam); 599 608 609 /** Recurses the kdtree, adding any nodes intersecting with the 610 box/sphere/volume/ray into the given list. 611 It ignores the exclude scene node. 612 */ 613 void recFindNodesIn(const AxisAlignedBox &box, std::list<SceneNode *> &list, SceneNode *exclude, Node * node, bool full = false); 614 void recFindNodesIn(const Sphere &sphere, std::list<SceneNode *> &list, SceneNode *exclude, Node * node, bool full = false); 615 void recFindNodesIn(const PlaneBoundedVolume &volume, std::list<SceneNode *> &list, SceneNode *exclude, Node * node, bool full = false); 616 void recFindNodesIn(const Ray &ray, std::list<SceneNode *> &list, SceneNode *exclude, Node * node, bool full = false); 617 600 618 // the root node of the kdtree 601 619 KdTree::Node * mKdRoot; -
GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/include/OgreKdTreeSceneManager.h
r1285 r1296 13 13 #include <OgreSceneManager.h> 14 14 #include <VisibilityManager.h> 15 #include <ViewCellsManager.h> 15 16 16 17 #include "OgreKdTree.h" … … 123 124 virtual bool getShowBoxes(void) const; 124 125 126 /** Recurses the kdtree, adding any nodes intersecting with the 127 box/sphere/volume/ray into the given list. 128 It ignores the exclude scene node. 129 */ 130 void findNodesIn( const AxisAlignedBox &box, std::list < SceneNode * > &list, SceneNode *exclude = 0 ) 131 { 132 if (mKdTree) 133 mKdTree->findNodesIn(box, list, exclude); 134 } 135 void findNodesIn( const Sphere &sphere, std::list < SceneNode * > &list, SceneNode *exclude = 0 ) 136 { 137 if (mKdTree) 138 mKdTree->findNodesIn(sphere, list, exclude); 139 } 140 void findNodesIn( const PlaneBoundedVolume &volume, std::list < SceneNode * > &list, SceneNode *exclude=0 ) 141 { 142 if (mKdTree) 143 mKdTree->findNodesIn(volume, list, exclude); 144 } 145 void findNodesIn( const Ray &ray, std::list < SceneNode * > &list, SceneNode *exclude=0 ) 146 { 147 if (mKdTree) 148 mKdTree->findNodesIn(ray, list, exclude); 149 } 150 151 /************************************************************************/ 152 /* Functions for PVS */ 153 /************************************************************************/ 154 /** Loads view cells for this particular scene. 155 */ 156 bool LoadViewCells(const String &filename); 157 125 158 /************************************************************************/ 126 159 /* Functions for CHC */ … … 168 201 void WriteLog(); 169 202 170 /** Switches between simple & enhanced visibility 171 */ 172 //void setEnhancedVis(bool enhanced); 173 203 /************************************************************************/ 204 /* Functions for PVS */ 205 /************************************************************************/ 206 /** Loads / unloads pvs of the view cell to set the visibility in the scene. 207 */ 208 void applyViewCellPvs(GtpVisibilityPreprocessor::ViewCell *vc, const bool load); 209 210 /** updates pvs in current frame. 211 */ 212 void updatePvs(Camera *cam); 213 214 /** Sets all objects invisible. 215 */ 216 void SetObjectsVisible(const bool visible); 174 217 175 218 /************************************************************************/ … … 225 268 // if we currently render the item buffer 226 269 bool mIsItemBufferPhase; 270 // delete or clear the renderqueue after each rame? 271 bool mDeleteQueueAfterRendering; 272 227 273 228 274 // remember visited scene nodes for viz 229 //KdRenderableList mVisibleNodes;230 275 KdTree::NodeList mVisibleNodes; 231 232 bool mDeleteQueueAfterRendering;233 276 234 277 /************************************************************************/ … … 258 301 // the method of building the tree 259 302 KdTree::BuildMethod mBuildMethod; 303 304 /************************************************************************/ 305 /* PVS specific options and members */ 306 /************************************************************************/ 307 308 // The view cell manager 309 GtpVisibilityPreprocessor::ViewCellsManager *mViewCellsManager; 310 311 /// Used to assign Ogre meshes to view cell entries. 312 GtpVisibilityPreprocessor::ObjectContainer mObjects; 313 314 GtpVisibilityPreprocessor::ViewCell *mElementaryViewCell; 315 GtpVisibilityPreprocessor::ViewCell *mCurrentViewCell; 316 317 /// If view cells are loaded. 318 bool mViewCellsLoaded; 319 320 /// If view cells are used. 321 bool mUseViewCells; 322 323 /// if the view cells are filtered 324 bool mUseVisibilityFilter; 260 325 }; 261 326 -
GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreBoundingBoxConverter.cpp
r1221 r1296 3 3 #include "OgreMeshInstance.h" 4 4 #include "OgreOctreeSceneManager.h" 5 #include "OgreKdTreeSceneManager.h" 5 6 #include <OgreLogManager.h> 6 7 … … 10 11 //------------------------------------------------------------------------- 11 12 OgreBoundingBoxConverter::OgreBoundingBoxConverter(OctreeSceneManager *sm): 12 mSceneMgr(sm) 13 mOctSceneMgr(sm), mKdSceneMgr(0) 14 { 15 } 16 //------------------------------------------------------------------------- 17 OgreBoundingBoxConverter::OgreBoundingBoxConverter(KdTreeSceneManager *sm): 18 mOctSceneMgr(0), mKdSceneMgr(sm) 13 19 { 14 20 } … … 54 60 55 61 // get intersecting scene nodes 56 mSceneMgr->findNodesIn(mybox, sceneNodeList, NULL); 62 if (mOctSceneMgr) 63 mOctSceneMgr->findNodesIn(mybox, sceneNodeList, NULL); 64 else if (mKdSceneMgr) 65 mKdSceneMgr->findNodesIn(mybox, sceneNodeList, NULL); 66 else 67 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, "Bounding Box Converter cannot " 68 "find appropriate scene manager.", "OgreBoundingBoxConverter::FindCorrespondingObject"); 57 69 58 70 -
GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTree.cpp
r1285 r1296 24 24 namespace Ogre 25 25 { 26 Real PlaneEvent::KT = 2.0; 27 Real PlaneEvent::KI = 1.0; 28 29 //---------------------------------------------------------------------------- 30 // determine if this event is left or right of the reference event 31 void PlaneEvent::classify(const PlaneEvent& e, PlaneEvent::Side side) 32 { 33 // only classify events of the same dimension 34 if (mDimension == e.mDimension) 35 { 36 if (mType == PET_END && mPosition[mDimension] <= e.mPosition[e.mDimension]) 26 27 enum Intersection 28 { 29 OUTSIDE=0, 30 INSIDE=1, 31 INTERSECT=2 32 }; 33 34 Intersection intersect( const Ray &one, const AxisAlignedBox &two ) 35 { 36 // Null box? 37 if (two.isNull()) return OUTSIDE; 38 39 bool inside = true; 40 const Vector3* pCorners = two.getAllCorners(); 41 Vector3 origin = one.getOrigin(); 42 Vector3 dir = one.getDirection(); 43 44 Vector3 maxT(-1, -1, -1); 45 46 int i = 0; 47 for(i=0; i<3; i++ ) 48 { 49 if( origin[i] < pCorners[0][i] ) 50 { 51 inside = false; 52 if( dir[i] > 0 ) 53 { 54 maxT[i] = (pCorners[0][i] - origin[i])/ dir[i]; 55 } 56 } 57 else if( origin[i] > pCorners[4][i] ) 58 { 59 inside = false; 60 if( dir[i] < 0 ) 61 { 62 maxT[i] = (pCorners[4][i] - origin[i]) / dir[i]; 63 } 64 } 65 } 66 67 if( inside ) 68 { 69 return INTERSECT; 70 } 71 int whichPlane = 0; 72 if( maxT[1] > maxT[whichPlane]) 73 whichPlane = 1; 74 if( maxT[2] > maxT[whichPlane]) 75 whichPlane = 2; 76 77 if( ((int)maxT[whichPlane]) & 0x80000000 ) 78 { 79 return OUTSIDE; 80 } 81 for(i=0; i<3; i++ ) 82 { 83 if( i!= whichPlane ) 84 { 85 float f = origin[i] + maxT[whichPlane] * dir[i]; 86 if ( f < (pCorners[0][i] - 0.00001f) || 87 f > (pCorners[4][i] +0.00001f ) ) 88 { 89 return OUTSIDE; 90 } 91 } 92 } 93 94 return INTERSECT; 95 96 } 97 98 99 /** Checks how the second box intersects with the first. 100 */ 101 Intersection intersect( const PlaneBoundedVolume &one, const AxisAlignedBox &two ) 102 { 103 // Null box? 104 if (two.isNull()) return OUTSIDE; 105 106 // Get corners of the box 107 const Vector3* pCorners = two.getAllCorners(); 108 109 // For each plane, see if all points are on the negative side 110 // If so, object is not visible. 111 // If one or more are, it's partial. 112 // If all aren't, full 113 int corners[ 8 ] = {0, 4, 3, 5, 2, 6, 1, 7}; 114 bool all_inside = true; 115 PlaneList::const_iterator i, iend; 116 iend = one.planes.end(); 117 for (i = one.planes.begin(); i != iend; ++i) 118 { 119 const Plane& plane = *i; 120 bool all_outside = true; 121 122 float distance = 0; 123 124 for ( int corner = 0; corner < 8; ++corner ) 125 { 126 distance = plane.getDistance( pCorners[ corners[ corner ] ] ); 127 all_outside = all_outside && ( distance < 0 ); 128 all_inside = all_inside && ( distance >= 0 ); 129 130 if ( !all_outside && !all_inside ) 131 break; 132 } 133 134 if ( all_outside ) 135 return OUTSIDE; 136 } 137 138 if ( all_inside ) 139 return INSIDE; 140 else 141 return INTERSECT; 142 143 } 144 145 146 /** Checks how the second box intersects with the first. 147 */ 148 Intersection intersect( const AxisAlignedBox &one, const AxisAlignedBox &two ) 149 { 150 // Null box? 151 if (one.isNull() || two.isNull()) return OUTSIDE; 152 153 const Vector3 * outside = one.getAllCorners(); 154 const Vector3 *inside = two.getAllCorners(); 155 156 if ( inside[ 4 ].x < outside[ 0 ].x || 157 inside[ 4 ].y < outside[ 0 ].y || 158 inside[ 4 ].z < outside[ 0 ].z || 159 inside[ 0 ].x > outside[ 4 ].x || 160 inside[ 0 ].y > outside[ 4 ].y || 161 inside[ 0 ].z > outside[ 4 ].z ) 162 { 163 return OUTSIDE; 164 } 165 166 bool full = ( inside[ 0 ].x > outside[ 0 ].x && 167 inside[ 0 ].y > outside[ 0 ].y && 168 inside[ 0 ].z > outside[ 0 ].z && 169 inside[ 4 ].x < outside[ 4 ].x && 170 inside[ 4 ].y < outside[ 4 ].y && 171 inside[ 4 ].z < outside[ 4 ].z ); 172 173 if ( full ) 174 return INSIDE; 175 else 176 return INTERSECT; 177 178 } 179 180 /** Checks how the box intersects with the sphere. 181 */ 182 Intersection intersect( const Sphere &one, const AxisAlignedBox &two ) 183 { 184 // Null box? 185 if (two.isNull()) return OUTSIDE; 186 187 float sradius = one.getRadius(); 188 189 sradius *= sradius; 190 191 Vector3 scenter = one.getCenter(); 192 193 const Vector3 *corners = two.getAllCorners(); 194 195 float s, d = 0; 196 197 Vector3 mndistance = ( corners[ 0 ] - scenter ); 198 Vector3 mxdistance = ( corners[ 4 ] - scenter ); 199 200 if ( mndistance.squaredLength() < sradius && 201 mxdistance.squaredLength() < sradius ) 202 { 203 return INSIDE; 204 } 205 206 //find the square of the distance 207 //from the sphere to the box 208 for ( int i = 0 ; i < 3 ; i++ ) 209 { 210 if ( scenter[ i ] < corners[ 0 ][ i ] ) 211 { 212 s = scenter[ i ] - corners[ 0 ][ i ]; 213 d += s * s; 214 } 215 216 else if ( scenter[ i ] > corners[ 4 ][ i ] ) 217 { 218 s = scenter[ i ] - corners[ 4 ][ i ]; 219 d += s * s; 220 } 221 222 } 223 224 bool partial = ( d <= sradius ); 225 226 if ( !partial ) 227 { 228 return OUTSIDE; 229 } 230 231 else 232 { 233 return INTERSECT; 234 } 235 } 236 237 Real PlaneEvent::KT = 2.0; 238 Real PlaneEvent::KI = 1.0; 239 240 //---------------------------------------------------------------------------- 241 // determine if this event is left or right of the reference event 242 void PlaneEvent::classify(const PlaneEvent& e, PlaneEvent::Side side) 243 { 244 // only classify events of the same dimension 245 if (mDimension == e.mDimension) 246 { 247 if (mType == PET_END && mPosition[mDimension] <= e.mPosition[e.mDimension]) 248 { 249 mRenderable->setSide(PES_LEFT); 250 } 251 else if (mType == PET_START && mPosition[mDimension] >= e.mPosition[e.mDimension]) 252 { 253 mRenderable->setSide(PES_RIGHT); 254 } 255 else if (mType == PET_ON) 256 { 257 if (mPosition[mDimension] < e.mPosition[e.mDimension] || 258 (mPosition[mDimension] == e.mPosition[e.mDimension] && side == PES_LEFT)) 37 259 { 38 260 mRenderable->setSide(PES_LEFT); 39 261 } 40 else if (mType == PET_START && mPosition[mDimension] >= e.mPosition[e.mDimension]) 262 if (mPosition[mDimension] > e.mPosition[e.mDimension] || 263 (mPosition[mDimension] == e.mPosition[e.mDimension] && side == PES_RIGHT)) 41 264 { 42 265 mRenderable->setSide(PES_RIGHT); 43 266 } 44 else if (mType == PET_ON) 45 { 46 if (mPosition[mDimension] < e.mPosition[e.mDimension] || 47 (mPosition[mDimension] == e.mPosition[e.mDimension] && side == PES_LEFT)) 48 { 49 mRenderable->setSide(PES_LEFT); 50 } 51 if (mPosition[mDimension] > e.mPosition[e.mDimension] || 52 (mPosition[mDimension] == e.mPosition[e.mDimension] && side == PES_RIGHT)) 53 { 54 mRenderable->setSide(PES_RIGHT); 55 } 56 } 57 } 58 } 59 60 //---------------------------------------------------------------------------- 61 // clip this event to an aabb (move it so that the plane on one of the box planes) 62 PlaneEvent PlaneEvent::clip(AxisAlignedBox& box, PlaneEvent::Dimension dim) 63 { 64 Vector3 newpos = mPosition, min = box.getMinimum(), max = box.getMaximum(); 65 if (newpos[dim] < min[dim]) 66 newpos[dim] = min[dim]; 67 else if (newpos[dim] > max[dim]) 68 newpos[dim] = max[dim]; 69 70 return PlaneEvent(mRenderable, newpos, mDimension, mType); 71 } 72 73 //---------------------------------------------------------------------------- 74 // the surface area heuristic to determine the cost of splitting the parent aabb 75 // along the plane represented by this event 76 void PlaneEvent::SAH(const AxisAlignedBox& parent, int nLeft, int nPlane, int nRight, SplitInfo& split) 77 { 78 Real mu = splitBox(parent, split.bleft, split.bright); 79 Real sav = surfaceArea(parent); 80 Real pl = surfaceArea(split.bleft) / sav; 81 Real pr = surfaceArea(split.bright) / sav; 82 Real costl = splitCost(pl, pr, nLeft + nPlane, nRight, mu); 83 Real costr = splitCost(pl, pr, nLeft, nPlane + nRight, mu); 84 85 if (costl < costr) 86 { 87 split.cost = costl; 88 split.side = PES_LEFT; 89 split.nleft = nLeft + nPlane; 90 split.nright = nRight; 91 } 267 } 268 } 269 } 270 271 //---------------------------------------------------------------------------- 272 // clip this event to an aabb (move it so that the plane on one of the box planes) 273 PlaneEvent PlaneEvent::clip(AxisAlignedBox& box, PlaneEvent::Dimension dim) 274 { 275 Vector3 newpos = mPosition, min = box.getMinimum(), max = box.getMaximum(); 276 if (newpos[dim] < min[dim]) 277 newpos[dim] = min[dim]; 278 else if (newpos[dim] > max[dim]) 279 newpos[dim] = max[dim]; 280 281 return PlaneEvent(mRenderable, newpos, mDimension, mType); 282 } 283 284 //---------------------------------------------------------------------------- 285 // the surface area heuristic to determine the cost of splitting the parent aabb 286 // along the plane represented by this event 287 void PlaneEvent::SAH(const AxisAlignedBox& parent, int nLeft, int nPlane, int nRight, SplitInfo& split) 288 { 289 Real mu = splitBox(parent, split.bleft, split.bright); 290 Real sav = surfaceArea(parent); 291 Real pl = surfaceArea(split.bleft) / sav; 292 Real pr = surfaceArea(split.bright) / sav; 293 Real costl = splitCost(pl, pr, nLeft + nPlane, nRight, mu); 294 Real costr = splitCost(pl, pr, nLeft, nPlane + nRight, mu); 295 296 if (costl < costr) 297 { 298 split.cost = costl; 299 split.side = PES_LEFT; 300 split.nleft = nLeft + nPlane; 301 split.nright = nRight; 302 } 303 else 304 { 305 split.cost = costr; 306 split.side = PES_RIGHT; 307 split.nleft = nLeft; 308 split.nright = nPlane + nRight; 309 310 } 311 split.event = *this; 312 } 313 314 //---------------------------------------------------------------------------- 315 // split the parent aabb with the plane in this event 316 Real PlaneEvent::splitBox(const AxisAlignedBox& parent, AxisAlignedBox& left, AxisAlignedBox& right) 317 { 318 Vector3 bmin = parent.getMinimum(); 319 Vector3 bmax = parent.getMaximum(); 320 // calculate the penalty for spliting the box that way 321 Real mu = lookupPenalty( 322 (mPosition[mDimension] - bmin[mDimension]) / 323 (bmax[mDimension] - bmin[mDimension])); 324 // set corners which are the same as parent AABB 325 left.setMinimum(bmin); 326 right.setMaximum(bmax); 327 // modify "inner" corners 328 bmin[mDimension] = mPosition[mDimension]; 329 bmax[mDimension] = mPosition[mDimension]; 330 // set the corners on the split plane 331 left.setMaximum(bmax); 332 right.setMinimum(bmin); 333 334 return mu; 335 } 336 337 //---------------------------------------------------------------------------- 338 // compute surface area of a box ... DUH! 339 Real PlaneEvent::surfaceArea(const AxisAlignedBox& box) 340 { 341 Vector3 sides = box.getMaximum() - box.getMinimum(); 342 return 2 * sides.x * sides.y + 343 2 * sides.y * sides.z + 344 2 * sides.z * sides.x; 345 } 346 347 //---------------------------------------------------------------------------- 348 // lookup the penalty for placing the splitting plane near to the edge of the AABB 349 // 0.0 <= p <= 1.0, p = 0.5 means the plane divides the aabb in half 350 Real PlaneEvent::lookupPenalty(Real p) 351 { 352 // precomputed table of {x^6 + 1|0 <= x <= 1} 353 static Real mPenaltyLookupTable[PLT_SIZE]; 354 static bool init_done = false; 355 356 if (!init_done) 357 { 358 Real step = 1.0 / (PLT_SIZE - 1); 359 Real x = 0.0; 360 //LogManager::getSingleton().logMessage("### Calculating Lookup Table ###"); 361 for (int i = 0; i < PLT_SIZE; i++) 362 { 363 mPenaltyLookupTable[i] = Math::Pow(x, 6) + 1.0; 364 x += step; 365 //LogManager::getSingleton().logMessage("### mPenaltyLookupTable[" + StringConverter::toString(i,3) + "]=" + StringConverter::toString(mPenaltyLookupTable[i])); 366 } 367 init_done = true; 368 //LogManager::getSingleton().logMessage("### Lookup Table Calculated ###"); 369 } 370 371 // normalize p to [0,1] 372 Real x = Math::Abs(p * 2 - 1); 373 // compute index 374 int i = Math::IFloor(x * (PLT_SIZE - 1)); 375 376 return mPenaltyLookupTable[i]; 377 } 378 379 //---------------------------------------------------------------------------- 380 // compute cost of the split, reward splitting of empty space (lambda, const), 381 // penalize splitting off 'thin' slices (mu, const) 382 Real PlaneEvent::splitCost(Real pLeft, Real pRight, int nLeft, int nRight) 383 { 384 // reward splitting off chunks of empty space 385 Real lambda = 1.0; 386 if (nLeft == 0 || nRight == 0) 387 { 388 lambda = 0.8; 389 } 390 391 // penalize splitting off small chunks (thin slices) 392 Real mu = 1.0; 393 if (pLeft < 0.1 || pRight < 0.1 || pLeft > 0.9 || pRight > 0.9) 394 { 395 mu = 1.5; 396 } 397 return lambda * mu * (KT + (KI * (pLeft*nLeft + pRight*nRight))); 398 } 399 400 //---------------------------------------------------------------------------- 401 // compute cost of the split, reward splitting of empty space (lambda, const), 402 // penalize splitting off 'thin' slices (mu, parameter) 403 Real PlaneEvent::splitCost(Real pLeft, Real pRight, int nLeft, int nRight, Real mu) 404 { 405 // reward splitting off chunks of empty space 406 Real lambda = 1.0; 407 if (nLeft == 0 || nRight == 0) 408 { 409 lambda = 0.8; 410 } 411 412 return lambda * mu * (KT + (KI * (pLeft*nLeft + pRight*nRight))); 413 } 414 415 //---------------------------------------------------------------------------- 416 // surface area heuristic modified for the priority queue method of building 417 // the probabilities (p, pl, pr) are relative to the global (all enclosing) aabb 418 void PlaneEvent::pqSAH(Real globalSA, Real parentSA, int nLeft, int nPlane, int nRight, 419 AxisAlignedBox& parentBox, SplitInfo& split) 420 { 421 Real mu = splitBox(parentBox, split.bleft, split.bright); 422 Real p = parentSA / globalSA; 423 Real pl = surfaceArea(split.bleft) / globalSA; 424 Real pr = surfaceArea(split.bright) / globalSA; 425 Real costl = pqSplitCost(p, pl, pr, nLeft + nPlane, nRight, mu); 426 Real costr = pqSplitCost(p, pl, pr, nLeft, nPlane + nRight, mu); 427 428 if (costl < costr) 429 { 430 split.cost = costl; 431 split.side = PES_LEFT; 432 split.nleft = nLeft + nPlane; 433 split.nright = nRight; 434 } 435 else 436 { 437 split.cost = costr; 438 split.side = PES_RIGHT; 439 split.nleft = nLeft; 440 split.nright = nPlane + nRight; 441 442 } 443 split.event = *this; 444 } 445 446 //---------------------------------------------------------------------------- 447 // compute split cost without any penalties 448 Real PlaneEvent::pqSplitCost(Real pParent, Real pLeft, Real pRight, int nLeft, int nRight, Real mu) 449 { 450 return pParent * KT + (KI * (pLeft * nLeft + pRight * nRight)); 451 } 452 453 //---------------------------------------------------------------------------- 454 // DEBUG 455 String PlaneEvent::print() 456 { 457 String dim, type; 458 if (mDimension == PED_X) 459 dim = "X"; 460 if (mDimension == PED_Y) 461 dim = "Y"; 462 if (mDimension == PED_Z) 463 dim = "Z"; 464 if (mType == PET_END) 465 type = "END "; 466 if (mType == PET_ON) 467 type = "ON "; 468 if (mType == PET_START) 469 type = "START"; 470 //return StringConverter::toString(mPosition[mDimension]) + " " + dim + " " + type; 471 return type + " " + dim + " " + StringConverter::toString(mPosition[mDimension]); 472 }; 473 474 //---------------------------------------------------------------------------- 475 String SplitInfo::print() 476 { 477 String sside; 478 if (side == PlaneEvent::PES_BOTH) 479 sside = "BOTH "; 480 if (side == PlaneEvent::PES_LEFT) 481 sside = "LEFT "; 482 if (side == PlaneEvent::PES_RIGHT) 483 sside = "RIGHT"; 484 return "nLeft: " + StringConverter::toString(nleft, 4) + " nRight: " + 485 StringConverter::toString(nright, 4) + " Cost: " + StringConverter::toString(cost, 8, 9) + 486 " Side: " + sside + " Event: " + event.print() + " Leftbox: " + 487 StringConverter::toString(bleft.getMinimum()) + ", " + 488 StringConverter::toString(bleft.getMaximum()) + " Rightbox: " + 489 StringConverter::toString(bright.getMinimum()) + ", " + 490 StringConverter::toString(bright.getMaximum()); 491 }; 492 493 //---------------------------------------------------------------------------- 494 String KdTree::SplitCandidate::print() 495 { 496 String sside; 497 if (side == PlaneEvent::PES_BOTH) 498 sside = "BOTH "; 499 if (side == PlaneEvent::PES_LEFT) 500 sside = "LEFT "; 501 if (side == PlaneEvent::PES_RIGHT) 502 sside = "RIGHT"; 503 return "List: " + StringConverter::toString(events->size(), 4) + " Objects: " + 504 StringConverter::toString(nObjects, 4) + " Cost: " + StringConverter::toString(cost, 8, 9) + 505 " Decrease: " + StringConverter::toString(decrease, 8, 9) + " Side: " + sside + " Best: " + 506 best->print() + " Box: " + StringConverter::toString(aabb.getMinimum()) + ", " 507 + StringConverter::toString(aabb.getMaximum()); 508 509 }; 510 511 //---------------------------------------------------------------------------- 512 //---------------------------------------------------------------------------- 513 //---------------------------------------------------------------------------- 514 515 KdTree::KdTree(int maxdepth, BuildMethod bm): 516 mMaxDepth(maxdepth), 517 mBuildMethod(bm), 518 mHiLiteLevel(0), 519 mShowAllBoxes(false), 520 mShowNodes(true), 521 mKdRoot(0), 522 mBuildLog(0) 523 { 524 init(); 525 } 526 527 KdTree::KdTree(int maxdepth, BuildMethod bm, int hilite, bool allboxes, bool shownodes): 528 mMaxDepth(maxdepth), 529 mBuildMethod(bm), 530 mHiLiteLevel(hilite), 531 mShowAllBoxes(allboxes), 532 mShowNodes(shownodes), 533 mKdRoot(0), 534 mBuildLog(0) 535 { 536 init(); 537 } 538 539 KdTree::~KdTree() 540 { 541 delete mKdRoot; 542 } 543 544 void KdTree::init() 545 { 546 MaterialPtr mat; 547 TextureUnitState *tex; 548 549 // init visualization materials (unlit solid green/yellow) 550 mat = MaterialManager::getSingleton().getByName("KdTree/BoxHiLite"); 551 if (mat.isNull()) 552 { 553 ColourValue green(0, 1, 0); 554 mat = MaterialManager::getSingleton().create("KdTree/BoxHiLite", "General"); 555 //mat->setAmbient(green); 556 //mat->setDiffuse(green); 557 mat->setLightingEnabled(false); 558 tex = mat->getTechnique(0)->getPass(0)->createTextureUnitState(); 559 tex->setColourOperationEx(LBX_SOURCE2, LBS_CURRENT, LBS_MANUAL, green, green); 560 } 561 562 mat = MaterialManager::getSingleton().getByName("KdTree/BoxViz"); 563 if (mat.isNull()) 564 { 565 ColourValue yellow(1, 1, 0); 566 mat = MaterialManager::getSingleton().create("KdTree/BoxViz", "General"); 567 //mat->setAmbient(yellow); 568 //mat->setDiffuse(yellow); 569 mat->setLightingEnabled(false); 570 tex = mat->getTechnique(0)->getPass(0)->createTextureUnitState(); 571 tex->setColourOperationEx(LBX_SOURCE2, LBS_CURRENT, LBS_MANUAL, yellow, yellow); 572 } 573 574 // retrieve or create build log 575 try 576 { 577 mBuildLog = LogManager::getSingleton().getLog(KDTREE_LOGNAME); 578 } 579 catch (Exception&) 580 { 581 mBuildLog = LogManager::getSingleton().createLog(KDTREE_LOGNAME); 582 } 583 584 setEnhancedVis(false); 585 } 586 587 /************************************************************************/ 588 /* KdTree insert/delete functions */ 589 /************************************************************************/ 590 591 void KdTree::remove(KdRenderable * rend) 592 { 593 // DEBUG 594 //LogManager::getSingleton().logMessage("-- Removing SceneNode: " + (static_cast<KdTreeSceneNode *>(rend))->getName()); 595 std::queue<LeafPtr> cleanup; 596 LeafPtr leaf; 597 LeafSet ls = rend->getLeaves(); 598 LeafSet::iterator it = ls.begin(); 599 LeafSet::iterator end = ls.end(); 600 while (it != end) 601 { 602 cleanup.push(*it); 603 it++; 604 } 605 while (!cleanup.empty()) 606 { 607 leaf = cleanup.front(); 608 cleanup.pop(); 609 leaf->remove(rend); 610 bool gone = rend->detachFrom(leaf); 611 assert(gone && "Failed to detach leave which is abso-fuckin-lutely impossible!!!"); 612 //dump(); 613 recDelete(leaf); 614 //dump(); 615 } 616 } 617 618 void KdTree::recDelete(KdTree::Node * node) 619 { 620 if (node == 0) // DEBUG 621 { 622 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 623 "SNAFU while inserting KdRenderable into KdTree.", 624 "KdTree::recInsert" ); 625 return; 626 } 627 628 if (node->isEmpty()) 629 { 630 if (node == mKdRoot) 631 { 632 OGRE_DELETE(mKdRoot); 633 } 92 634 else 93 635 { 94 split.cost = costr; 95 split.side = PES_RIGHT; 96 split.nleft = nLeft; 97 split.nright = nPlane + nRight; 98 99 } 100 split.event = *this; 101 } 102 103 //---------------------------------------------------------------------------- 104 // split the parent aabb with the plane in this event 105 Real PlaneEvent::splitBox(const AxisAlignedBox& parent, AxisAlignedBox& left, AxisAlignedBox& right) 106 { 107 Vector3 bmin = parent.getMinimum(); 108 Vector3 bmax = parent.getMaximum(); 109 // calculate the penalty for spliting the box that way 110 Real mu = lookupPenalty( 111 (mPosition[mDimension] - bmin[mDimension]) / 112 (bmax[mDimension] - bmin[mDimension])); 113 // set corners which are the same as parent AABB 114 left.setMinimum(bmin); 115 right.setMaximum(bmax); 116 // modify "inner" corners 117 bmin[mDimension] = mPosition[mDimension]; 118 bmax[mDimension] = mPosition[mDimension]; 119 // set the corners on the split plane 120 left.setMaximum(bmax); 121 right.setMinimum(bmin); 122 123 return mu; 124 } 125 126 //---------------------------------------------------------------------------- 127 // compute surface area of a box ... DUH! 128 Real PlaneEvent::surfaceArea(const AxisAlignedBox& box) 129 { 130 Vector3 sides = box.getMaximum() - box.getMinimum(); 131 return 2 * sides.x * sides.y + 132 2 * sides.y * sides.z + 133 2 * sides.z * sides.x; 134 } 135 136 //---------------------------------------------------------------------------- 137 // lookup the penalty for placing the splitting plane near to the edge of the AABB 138 // 0.0 <= p <= 1.0, p = 0.5 means the plane divides the aabb in half 139 Real PlaneEvent::lookupPenalty(Real p) 140 { 141 // precomputed table of {x^6 + 1|0 <= x <= 1} 142 static Real mPenaltyLookupTable[PLT_SIZE]; 143 static bool init_done = false; 144 145 if (!init_done) 146 { 147 Real step = 1.0 / (PLT_SIZE - 1); 148 Real x = 0.0; 149 //LogManager::getSingleton().logMessage("### Calculating Lookup Table ###"); 150 for (int i = 0; i < PLT_SIZE; i++) 151 { 152 mPenaltyLookupTable[i] = Math::Pow(x, 6) + 1.0; 153 x += step; 154 //LogManager::getSingleton().logMessage("### mPenaltyLookupTable[" + StringConverter::toString(i,3) + "]=" + StringConverter::toString(mPenaltyLookupTable[i])); 155 } 156 init_done = true; 157 //LogManager::getSingleton().logMessage("### Lookup Table Calculated ###"); 158 } 159 160 // normalize p to [0,1] 161 Real x = Math::Abs(p * 2 - 1); 162 // compute index 163 int i = Math::IFloor(x * (PLT_SIZE - 1)); 164 165 return mPenaltyLookupTable[i]; 166 } 167 168 //---------------------------------------------------------------------------- 169 // compute cost of the split, reward splitting of empty space (lambda, const), 170 // penalize splitting off 'thin' slices (mu, const) 171 Real PlaneEvent::splitCost(Real pLeft, Real pRight, int nLeft, int nRight) 172 { 173 // reward splitting off chunks of empty space 174 Real lambda = 1.0; 175 if (nLeft == 0 || nRight == 0) 176 { 177 lambda = 0.8; 178 } 179 180 // penalize splitting off small chunks (thin slices) 181 Real mu = 1.0; 182 if (pLeft < 0.1 || pRight < 0.1 || pLeft > 0.9 || pRight > 0.9) 183 { 184 mu = 1.5; 185 } 186 return lambda * mu * (KT + (KI * (pLeft*nLeft + pRight*nRight))); 187 } 188 189 //---------------------------------------------------------------------------- 190 // compute cost of the split, reward splitting of empty space (lambda, const), 191 // penalize splitting off 'thin' slices (mu, parameter) 192 Real PlaneEvent::splitCost(Real pLeft, Real pRight, int nLeft, int nRight, Real mu) 193 { 194 // reward splitting off chunks of empty space 195 Real lambda = 1.0; 196 if (nLeft == 0 || nRight == 0) 197 { 198 lambda = 0.8; 199 } 200 201 return lambda * mu * (KT + (KI * (pLeft*nLeft + pRight*nRight))); 202 } 203 204 //---------------------------------------------------------------------------- 205 // surface area heuristic modified for the priority queue method of building 206 // the probabilities (p, pl, pr) are relative to the global (all enclosing) aabb 207 void PlaneEvent::pqSAH(Real globalSA, Real parentSA, int nLeft, int nPlane, int nRight, 208 AxisAlignedBox& parentBox, SplitInfo& split) 209 { 210 Real mu = splitBox(parentBox, split.bleft, split.bright); 211 Real p = parentSA / globalSA; 212 Real pl = surfaceArea(split.bleft) / globalSA; 213 Real pr = surfaceArea(split.bright) / globalSA; 214 Real costl = pqSplitCost(p, pl, pr, nLeft + nPlane, nRight, mu); 215 Real costr = pqSplitCost(p, pl, pr, nLeft, nPlane + nRight, mu); 216 217 if (costl < costr) 218 { 219 split.cost = costl; 220 split.side = PES_LEFT; 221 split.nleft = nLeft + nPlane; 222 split.nright = nRight; 636 KdTree::Branch * parent = KDBRANCHPTR_CAST(node->getParent()); 637 if (node == parent->mLeft) 638 { 639 OGRE_DELETE(parent->mLeft); 640 } 641 else if (node == parent->mRight) 642 { 643 OGRE_DELETE(parent->mRight); 644 } 645 recDelete(parent); 646 } 647 } 648 } 649 650 void KdTree::insert(KdRenderable * rend) 651 { 652 // make sure the tree exists 653 if (mKdRoot) 654 { 655 // make sure the renderable is inside the world bounding box 656 AxisAlignedBox aabb = rend->getBoundingBox(); 657 AxisAlignedBox isect = mKdRoot->mAABB.intersection(aabb); 658 if (isect.getMinimum() == aabb.getMinimum() && isect.getMaximum() == aabb.getMaximum()) 659 { 660 recInsert(mKdRoot, rend); 223 661 } 224 662 else 225 663 { 226 split.cost = costr; 227 split.side = PES_RIGHT; 228 split.nleft = nLeft; 229 split.nright = nPlane + nRight; 230 231 } 232 split.event = *this; 233 } 234 235 //---------------------------------------------------------------------------- 236 // compute split cost without any penalties 237 Real PlaneEvent::pqSplitCost(Real pParent, Real pLeft, Real pRight, int nLeft, int nRight, Real mu) 238 { 239 return pParent * KT + (KI * (pLeft * nLeft + pRight * nRight)); 240 } 241 242 //---------------------------------------------------------------------------- 243 // DEBUG 244 String PlaneEvent::print() 245 { 246 String dim, type; 247 if (mDimension == PED_X) 248 dim = "X"; 249 if (mDimension == PED_Y) 250 dim = "Y"; 251 if (mDimension == PED_Z) 252 dim = "Z"; 253 if (mType == PET_END) 254 type = "END "; 255 if (mType == PET_ON) 256 type = "ON "; 257 if (mType == PET_START) 258 type = "START"; 259 //return StringConverter::toString(mPosition[mDimension]) + " " + dim + " " + type; 260 return type + " " + dim + " " + StringConverter::toString(mPosition[mDimension]); 261 }; 262 263 //---------------------------------------------------------------------------- 264 String SplitInfo::print() 265 { 266 String sside; 267 if (side == PlaneEvent::PES_BOTH) 268 sside = "BOTH "; 269 if (side == PlaneEvent::PES_LEFT) 270 sside = "LEFT "; 271 if (side == PlaneEvent::PES_RIGHT) 272 sside = "RIGHT"; 273 return "nLeft: " + StringConverter::toString(nleft, 4) + " nRight: " + 274 StringConverter::toString(nright, 4) + " Cost: " + StringConverter::toString(cost, 8, 9) + 275 " Side: " + sside + " Event: " + event.print() + " Leftbox: " + 276 StringConverter::toString(bleft.getMinimum()) + ", " + 277 StringConverter::toString(bleft.getMaximum()) + " Rightbox: " + 278 StringConverter::toString(bright.getMinimum()) + ", " + 279 StringConverter::toString(bright.getMaximum()); 280 }; 281 282 //---------------------------------------------------------------------------- 283 String KdTree::SplitCandidate::print() 284 { 285 String sside; 286 if (side == PlaneEvent::PES_BOTH) 287 sside = "BOTH "; 288 if (side == PlaneEvent::PES_LEFT) 289 sside = "LEFT "; 290 if (side == PlaneEvent::PES_RIGHT) 291 sside = "RIGHT"; 292 return "List: " + StringConverter::toString(events->size(), 4) + " Objects: " + 293 StringConverter::toString(nObjects, 4) + " Cost: " + StringConverter::toString(cost, 8, 9) + 294 " Decrease: " + StringConverter::toString(decrease, 8, 9) + " Side: " + sside + " Best: " + 295 best->print() + " Box: " + StringConverter::toString(aabb.getMinimum()) + ", " 296 + StringConverter::toString(aabb.getMaximum()); 297 298 }; 299 300 //---------------------------------------------------------------------------- 301 //---------------------------------------------------------------------------- 302 //---------------------------------------------------------------------------- 303 304 KdTree::KdTree(int maxdepth, BuildMethod bm): 305 mMaxDepth(maxdepth), 306 mBuildMethod(bm), 307 mHiLiteLevel(0), 308 mShowAllBoxes(false), 309 mShowNodes(true), 310 mKdRoot(0), 311 mBuildLog(0) 312 { 313 init(); 314 } 315 316 KdTree::KdTree(int maxdepth, BuildMethod bm, int hilite, bool allboxes, bool shownodes): 317 mMaxDepth(maxdepth), 318 mBuildMethod(bm), 319 mHiLiteLevel(hilite), 320 mShowAllBoxes(allboxes), 321 mShowNodes(shownodes), 322 mKdRoot(0), 323 mBuildLog(0) 324 { 325 init(); 326 } 327 328 KdTree::~KdTree() 329 { 330 delete mKdRoot; 331 } 332 333 void KdTree::init() 334 { 335 MaterialPtr mat; 336 TextureUnitState *tex; 337 338 // init visualization materials (unlit solid green/yellow) 339 mat = MaterialManager::getSingleton().getByName("KdTree/BoxHiLite"); 340 if (mat.isNull()) 341 { 342 ColourValue green(0, 1, 0); 343 mat = MaterialManager::getSingleton().create("KdTree/BoxHiLite", "General"); 344 //mat->setAmbient(green); 345 //mat->setDiffuse(green); 346 mat->setLightingEnabled(false); 347 tex = mat->getTechnique(0)->getPass(0)->createTextureUnitState(); 348 tex->setColourOperationEx(LBX_SOURCE2, LBS_CURRENT, LBS_MANUAL, green, green); 349 } 350 351 mat = MaterialManager::getSingleton().getByName("KdTree/BoxViz"); 352 if (mat.isNull()) 353 { 354 ColourValue yellow(1, 1, 0); 355 mat = MaterialManager::getSingleton().create("KdTree/BoxViz", "General"); 356 //mat->setAmbient(yellow); 357 //mat->setDiffuse(yellow); 358 mat->setLightingEnabled(false); 359 tex = mat->getTechnique(0)->getPass(0)->createTextureUnitState(); 360 tex->setColourOperationEx(LBX_SOURCE2, LBS_CURRENT, LBS_MANUAL, yellow, yellow); 361 } 362 363 // retrieve or create build log 364 try 365 { 366 mBuildLog = LogManager::getSingleton().getLog(KDTREE_LOGNAME); 367 } 368 catch (Exception&) 369 { 370 mBuildLog = LogManager::getSingleton().createLog(KDTREE_LOGNAME); 371 } 372 373 setEnhancedVis(false); 374 } 375 376 /************************************************************************/ 377 /* KdTree insert/delete functions */ 378 /************************************************************************/ 379 380 void KdTree::remove(KdRenderable * rend) 381 { 382 // DEBUG 383 //LogManager::getSingleton().logMessage("-- Removing SceneNode: " + (static_cast<KdTreeSceneNode *>(rend))->getName()); 384 std::queue<LeafPtr> cleanup; 385 LeafPtr leaf; 386 LeafSet ls = rend->getLeaves(); 387 LeafSet::iterator it = ls.begin(); 388 LeafSet::iterator end = ls.end(); 389 while (it != end) 390 { 391 cleanup.push(*it); 392 it++; 393 } 394 while (!cleanup.empty()) 395 { 396 leaf = cleanup.front(); 397 cleanup.pop(); 398 leaf->remove(rend); 399 bool gone = rend->detachFrom(leaf); 400 assert(gone && "Failed to detach leave which is abso-fuckin-lutely impossible!!!"); 401 //dump(); 402 recDelete(leaf); 403 //dump(); 404 } 405 } 406 407 void KdTree::recDelete(KdTree::Node * node) 408 { 409 if (node == 0) // DEBUG 664 //LogManager::getSingleton().logMessage("Inserted node outside of world AABB."); 665 KdRenderableList nodelist; 666 nodelist.push_back(rend); 667 addRendToList(mKdRoot, nodelist); 668 OGRE_DELETE(mKdRoot); 669 mKdRoot = buildFromList(nodelist, 0, AxisAlignedBox()); 670 } 671 } 672 // otherwise build a new one 673 else 674 { 675 build(rend); 676 } 677 } 678 679 void KdTree::recInsert(KdTree::Node * node, KdRenderable * rend) 680 { 681 if (node == 0) // DEBUG 682 { 683 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 684 "SNAFU while inserting KdRenderable into KdTree.", 685 "KdTree::recInsert" ); 686 return; 687 } 688 689 // rebuild the leaf/replace with subtree ... 690 if (node->isLeaf()) 691 { 692 //LogManager::getSingleton().logMessage("## Replacing leaf."); 693 rebuildSubtree(node, rend); 694 } 695 else 696 { 697 KdTree::Branch * branch = KDBRANCHPTR_CAST(node); 698 AxisAlignedBox aabb = rend->getBoundingBox(); 699 Plane::Side smin = branch->mSplitPlane->getSide(aabb.getMinimum()); 700 Plane::Side smax = branch->mSplitPlane->getSide(aabb.getMaximum()); 701 if (smin == smax) 702 { 703 if (smax == Plane::NEGATIVE_SIDE || 704 (smax == Plane::NO_SIDE && branch->mPlaneSide == PlaneEvent::PES_LEFT)) 705 { 706 if (branch->mLeft) 707 recInsert(branch->mLeft, rend); 708 else 709 recInsertNew(branch, PlaneEvent::PES_LEFT, rend); 710 } 711 else if (smin == Plane::POSITIVE_SIDE || 712 (smin == Plane::NO_SIDE && branch->mPlaneSide == PlaneEvent::PES_RIGHT)) 713 { 714 if (branch->mRight) 715 recInsert(branch->mRight, rend); 716 else 717 recInsertNew(branch, PlaneEvent::PES_RIGHT, rend); 718 } 719 } 720 else 721 { 722 if (smin == Plane::NEGATIVE_SIDE && smax == Plane::NO_SIDE) 723 { 724 if (branch->mLeft) 725 recInsert(branch->mLeft, rend); 726 else 727 recInsertNew(branch, PlaneEvent::PES_LEFT, rend); 728 } 729 else if (smax == Plane::POSITIVE_SIDE && smin == Plane::NO_SIDE) 730 { 731 if (branch->mRight) 732 recInsert(branch->mRight, rend); 733 else 734 recInsertNew(branch, PlaneEvent::PES_RIGHT, rend); 735 } 736 else 737 { 738 // to avoid SNAFUs, rebuild whole subtree 739 //LogManager::getSingleton().logMessage("## Rebuilding subtree for insertion"); 740 rebuildSubtree(node, rend); 741 } 742 } 743 } 744 } 745 746 void KdTree::recInsertNew(KdTree::Branch * parent, PlaneEvent::Side side, KdRenderable * rend) 747 { 748 //LogManager::getSingleton().logMessage("## Inserting into new subtree"); 749 750 AxisAlignedBox left, rigth, aabb; 751 PlaneEventList events; 752 int nObjects; 753 754 rend->computeScene(events, aabb, nObjects, false); 755 756 // override aabb 757 splitBox(*parent, left, rigth); 758 if (side == PlaneEvent::PES_LEFT) 759 { 760 aabb = left; 761 if (mBuildMethod == KDBM_RECURSIVE) 762 parent->mLeft = recBuild(events, nObjects, aabb, parent); 763 else if (mBuildMethod == KDBM_PRIORITYQUEUE) 764 parent->mLeft = pqBuild(events, nObjects, aabb, parent); 765 else 766 { 767 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 768 "Invalid build method for the KdTree.", 769 "KdTree::buildFromList"); 770 parent->mLeft = 0; 771 } 772 773 } 774 else if (side == PlaneEvent::PES_RIGHT) 775 { 776 aabb = rigth; 777 if (mBuildMethod == KDBM_RECURSIVE) 778 parent->mRight = recBuild(events, nObjects, aabb, parent); 779 else if (mBuildMethod == KDBM_PRIORITYQUEUE) 780 parent->mRight = pqBuild(events, nObjects, aabb, parent); 781 else 782 { 783 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 784 "Invalid build method for the KdTree.", 785 "KdTree::buildFromList"); 786 parent->mRight = 0; 787 } 788 } 789 } 790 791 void KdTree::rebuildSubtree(KdTree::Node * node, KdRenderable * rend) 792 { 793 //LogManager::getSingleton().logMessage("## Rebuilding subtree"); 794 795 AxisAlignedBox aabb = node->mAABB; 796 797 KdRenderableList nodelist; 798 nodelist.push_back(rend); 799 addRendToList(node, nodelist); 800 801 if (node == mKdRoot) 802 { 803 OGRE_DELETE(mKdRoot); 804 mKdRoot = buildFromList(nodelist, 0, aabb); 805 } 806 else 807 { 808 KdTree::Branch * parent = KDBRANCHPTR_CAST(node->getParent()); 809 810 if (node == parent->mLeft) 811 { 812 OGRE_DELETE(parent->mLeft); 813 parent->mLeft = buildFromList(nodelist, parent, aabb); 814 } 815 else if (node == parent->mRight) 816 { 817 OGRE_DELETE(parent->mRight); 818 parent->mRight = buildFromList(nodelist, parent, aabb); 819 } 820 else 410 821 { 411 822 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 412 823 "SNAFU while inserting KdRenderable into KdTree.", 413 824 "KdTree::recInsert" ); 414 return; 415 } 416 417 if (node->isEmpty()) 418 { 419 if (node == mKdRoot) 420 { 421 OGRE_DELETE(mKdRoot); 422 } 825 } 826 } 827 } 828 829 // compute both AABB then return the requested one. 830 void KdTree::splitBox(const KdTree::Branch& parent, AxisAlignedBox& left, AxisAlignedBox& right) 831 { 832 Vector3 bmin = parent.mAABB.getMinimum(); 833 Vector3 bmax = parent.mAABB.getMaximum(); 834 Real pos = - parent.mSplitPlane->d; 835 int dim = static_cast<int>(parent.mSplitPlane->normal.dotProduct(Vector3(0,1,2))); 836 // set corners which are the same as parent AABB 837 left.setMinimum(bmin); 838 right.setMaximum(bmax); 839 // modify "inner" corners 840 bmin[dim] = pos; 841 bmax[dim] = pos; 842 // set the corners on the split plane 843 left.setMaximum(bmax); 844 right.setMinimum(bmin); 845 } 846 847 void KdTree::addRendToList(KdTree::Node * node, KdRenderableList& nodelist) 848 { 849 if (node->isLeaf()) 850 { 851 KdTree::Leaf * leaf = KDLEAFPTR_CAST(node); 852 KdRenderableList::iterator it = leaf->mKdRenderables.begin(); 853 KdRenderableList::iterator end = leaf->mKdRenderables.end(); 854 while (it != end) 855 { 856 nodelist.push_back(*it); 857 it++; 858 } 859 } 860 else 861 { 862 KdTree::Branch * branch = KDBRANCHPTR_CAST(node); 863 if (branch->mLeft) 864 addRendToList(branch->mLeft, nodelist); 865 if (branch->mRight) 866 addRendToList(branch->mRight, nodelist); 867 } 868 } 869 870 /************************************************************************/ 871 /* KdTree build functions */ 872 /************************************************************************/ 873 874 void KdTree::build(KdRenderable * sceneRoot) 875 { 876 Timer *timer = Root::getSingleton().getTimer(); 877 unsigned long t1, t2, t3, t4; 878 879 mStats.clear(); 880 881 // data we want to collect 882 PlaneEventList events; 883 AxisAlignedBox aabb; 884 int nObjects = 0; 885 886 t1 = timer->getMicroseconds(); // DEBUG 887 sceneRoot->computeScene(events, aabb, nObjects); 888 t2 = timer->getMicroseconds(); // DEBUG 889 events.sort(); 890 t3 = timer->getMicroseconds(); // DEBUG 891 892 mStats.mNumSceneNodes = nObjects; 893 894 assert(! aabb.isNull() && "Teh stubid worldAABB iz NULL ... waht now?"); 895 // hack to avoid SNAFU with "2-dimensional" scene 896 aabb.merge(aabb.getMaximum()+Vector3(1,1,1)); 897 aabb.merge(aabb.getMinimum()+Vector3(-1,-1,-1)); 898 899 if (mBuildMethod == KDBM_RECURSIVE) 900 mKdRoot = recBuild(events, nObjects, aabb, 0); 901 else if (mBuildMethod == KDBM_PRIORITYQUEUE) 902 mKdRoot = pqBuild(events, nObjects, aabb, 0); 903 else 904 { 905 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 906 "Invalid build method for the KdTree.", 907 "KdTree::build"); 908 mKdRoot = 0; 909 } 910 911 t4 = timer->getMicroseconds(); // DEBUG 912 913 String method = "Invalid"; 914 if (mBuildMethod == KDBM_RECURSIVE) 915 method = "Recursive"; 916 else if (mBuildMethod == KDBM_PRIORITYQUEUE) 917 method = "Priority Queue"; 918 919 mBuildLog->logMessage("######## SAH Statistics ########"); 920 mBuildLog->logMessage("Build Method: " + method); 921 mBuildLog->logMessage("Time for events build: " + StringConverter::toString(t2 - t1) + "µs"); 922 mBuildLog->logMessage("Time for events sort: " + StringConverter::toString(t3 - t2) + "µs"); 923 mBuildLog->logMessage("Time for tree build: " + StringConverter::toString(t4 - t3) + "µs"); 924 mBuildLog->logMessage("Total time: " + StringConverter::toString(t4 - t1) + "µs"); 925 mBuildLog->logMessage("Tree Depth: " + StringConverter::toString(mMaxDepth)); 926 mBuildLog->logMessage("Number of Objects: " + StringConverter::toString(mStats.mNumSceneNodes)); 927 mBuildLog->logMessage("Number of Leaves: " + StringConverter::toString(mStats.mNumLeaves)); 928 mBuildLog->logMessage("Number of Nodes: " + StringConverter::toString(mStats.mNumNodes)); 929 mBuildLog->logMessage("Total cost: " + StringConverter::toString(calcCost())); 930 mBuildLog->logMessage("################################"); 931 } 932 933 KdTree::Node * KdTree::buildFromList(KdRenderableList& nodelist, KdTree::Branch * parent, AxisAlignedBox& aabb) 934 { 935 // data we want to collect 936 PlaneEventList events; 937 AxisAlignedBox nodeaabb; 938 int nObjects = 0; 939 940 KdRenderableList::iterator it = nodelist.begin(); 941 KdRenderableList::iterator end = nodelist.end(); 942 while (it != end) 943 { 944 (*it)->computeScene(events, nodeaabb, nObjects, false); 945 it++; 946 } 947 948 events.sort(); 949 950 // HACK 951 if (aabb.isNull()) 952 { 953 aabb = nodeaabb; 954 } 955 956 if (mBuildMethod == KDBM_RECURSIVE) 957 return recBuild(events, nObjects, aabb, parent); 958 else if (mBuildMethod == KDBM_PRIORITYQUEUE) 959 return pqBuild(events, nObjects, aabb, parent); 960 else 961 { 962 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 963 "Invalid build method for the KdTree.", 964 "KdTree::buildFromList"); 965 return 0; 966 } 967 } 968 969 KdTree::Node * KdTree::recBuild(PlaneEventList& events, int nObjects, AxisAlignedBox& aabb, KdTree::Branch * parent) 970 { 971 // determine the depth we are on 972 int level = 0; 973 if (parent) 974 { 975 level = parent->getLevel() + 1; 976 } 977 978 /************************************************/ 979 /**************** BEGIN FINDPLANE ***************/ 980 /************************************************/ 981 // find optimal split plane and split node accordingly 982 983 // initialize 984 const int dim = 3; 985 int pStart, pOn, pEnd; 986 int nLeft[dim], nPlane[dim], nRight[dim]; 987 for (int i = 0; i < dim; i++) 988 { 989 nLeft[i] = 0; nPlane[i] = 0; nRight[i] = nObjects; 990 } 991 992 SplitInfo split, best; 993 best.cost = Math::POS_INFINITY; 994 995 PlaneEventList::iterator begin = events.begin(); 996 PlaneEventList::iterator end = events.end(); 997 PlaneEventList::iterator it = begin; 998 // try all planes to find the best one for the given set of objects 999 while (it != end) 1000 { 1001 PlaneEventList::iterator p = it; 1002 pStart = pOn = pEnd = 0; 1003 while (it != end && p->equalsType(*it, PlaneEvent::PET_END)) 1004 { 1005 it++; pEnd++; 1006 } 1007 while (it != end && p->equalsType(*it, PlaneEvent::PET_ON)) 1008 { 1009 it++; pOn++; 1010 } 1011 while (it != end && p->equalsType(*it, PlaneEvent::PET_START)) 1012 { 1013 it++; pStart++; 1014 } 1015 int d = p->getDimension(); 1016 nPlane[d] = pOn; nRight[d] -= pOn; nRight[d] -= pEnd; 1017 p->SAH(aabb, nLeft[d], nPlane[d], nRight[d], split); 1018 if (split.cost < best.cost) 1019 { 1020 best = split; 1021 } 1022 nLeft[d] += pStart; nLeft[d] += pOn; nPlane[d] = 0; 1023 } 1024 1025 /************************************************/ 1026 /**************** BEGIN TERMINATE ***************/ 1027 /************************************************/ 1028 // check terminating condition 1029 if (best.cost > PlaneEvent::KI*nObjects || level >= mMaxDepth) 1030 { 1031 // Terminating condition reached, create leaf and add renderables to list 1032 KdTree::Leaf * leaf = new KdTree::Leaf(this, level, aabb, parent); 1033 KdRenderable *rend; 1034 it = begin; 1035 while (it != end) 1036 { 1037 rend = it->getRenderable(); 1038 rend->setClassified(false); 1039 if (rend->attachTo(leaf, this)) 1040 { 1041 leaf->insert(rend); 1042 } 1043 it++; 1044 } 1045 // update stats 1046 ++ mStats.mNumNodes; 1047 ++ mStats.mNumLeaves; 1048 // update bounding box 1049 leaf->_updateBounds(false); 1050 return leaf; 1051 } 1052 1053 /************************************************/ 1054 /**************** BEGIN CLASSIFY ****************/ 1055 /************************************************/ 1056 // split the event list in left and right sub-lists 1057 else 1058 { 1059 PlaneEventList eventsRight, eventsLeft; 1060 it = begin; 1061 // slightly redundant, since we mark each renderable up to 6 times 1062 while (it != end) 1063 { 1064 it->getRenderable()->setSide(PlaneEvent::PES_BOTH); 1065 it->getRenderable()->setClassified(false); 1066 it++; 1067 } 1068 // now classify all renderables. do they belong to the left child, the right child or both? 1069 it = begin; 1070 while (it != end) 1071 { 1072 it->classify(best.event, best.side); 1073 it++; 1074 } 1075 // divide the event lists 1076 int nLeftS = 0, nRightS = 0, nBothS = 0; 1077 it = begin; 1078 while (it != end) 1079 { 1080 // right-only nodes go in right list 1081 if (it->getRenderable()->getSide() == PlaneEvent::PES_RIGHT) 1082 { 1083 if (!it->getRenderable()->isClassified()) 1084 { 1085 it->getRenderable()->setClassified(true); 1086 nRightS++; 1087 } 1088 eventsRight.push_back(*it); 1089 } 1090 // left-only nodes go in left list 1091 else if (it->getRenderable()->getSide() == PlaneEvent::PES_LEFT) 1092 { 1093 if (!it->getRenderable()->isClassified()) 1094 { 1095 it->getRenderable()->setClassified(true); 1096 nLeftS++; 1097 } 1098 eventsLeft.push_back(*it); 1099 } 1100 // remaining nodes go in both lists, bust must be clipped to prevent 1101 // events from lying outside the new nodes aabb 423 1102 else 424 1103 { 425 KdTree::Branch * parent = KDBRANCHPTR_CAST(node->getParent()); 426 if (node == parent->mLeft) 1104 if (!it->getRenderable()->isClassified()) 427 1105 { 428 OGRE_DELETE(parent->mLeft); 1106 it->getRenderable()->setClassified(true); 1107 nBothS++; 429 1108 } 430 else if (node == parent->mRight) 431 { 432 OGRE_DELETE(parent->mRight); 433 } 434 recDelete(parent); 435 } 436 } 437 } 438 439 void KdTree::insert(KdRenderable * rend) 440 { 441 // make sure the tree exists 442 if (mKdRoot) 443 { 444 // make sure the renderable is inside the world bounding box 445 AxisAlignedBox aabb = rend->getBoundingBox(); 446 AxisAlignedBox isect = mKdRoot->mAABB.intersection(aabb); 447 if (isect.getMinimum() == aabb.getMinimum() && isect.getMaximum() == aabb.getMaximum()) 448 { 449 recInsert(mKdRoot, rend); 450 } 451 else 452 { 453 //LogManager::getSingleton().logMessage("Inserted node outside of world AABB."); 454 KdRenderableList nodelist; 455 nodelist.push_back(rend); 456 addRendToList(mKdRoot, nodelist); 457 OGRE_DELETE(mKdRoot); 458 mKdRoot = buildFromList(nodelist, 0, AxisAlignedBox()); 459 } 460 } 461 // otherwise build a new one 462 else 463 { 464 build(rend); 465 } 466 } 467 468 void KdTree::recInsert(KdTree::Node * node, KdRenderable * rend) 469 { 470 if (node == 0) // DEBUG 471 { 472 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 473 "SNAFU while inserting KdRenderable into KdTree.", 474 "KdTree::recInsert" ); 475 return; 476 } 477 478 // rebuild the leaf/replace with subtree ... 479 if (node->isLeaf()) 480 { 481 //LogManager::getSingleton().logMessage("## Replacing leaf."); 482 rebuildSubtree(node, rend); 483 } 484 else 485 { 486 KdTree::Branch * branch = KDBRANCHPTR_CAST(node); 487 AxisAlignedBox aabb = rend->getBoundingBox(); 488 Plane::Side smin = branch->mSplitPlane->getSide(aabb.getMinimum()); 489 Plane::Side smax = branch->mSplitPlane->getSide(aabb.getMaximum()); 490 if (smin == smax) 491 { 492 if (smax == Plane::NEGATIVE_SIDE || 493 (smax == Plane::NO_SIDE && branch->mPlaneSide == PlaneEvent::PES_LEFT)) 494 { 495 if (branch->mLeft) 496 recInsert(branch->mLeft, rend); 497 else 498 recInsertNew(branch, PlaneEvent::PES_LEFT, rend); 499 } 500 else if (smin == Plane::POSITIVE_SIDE || 501 (smin == Plane::NO_SIDE && branch->mPlaneSide == PlaneEvent::PES_RIGHT)) 502 { 503 if (branch->mRight) 504 recInsert(branch->mRight, rend); 505 else 506 recInsertNew(branch, PlaneEvent::PES_RIGHT, rend); 507 } 508 } 509 else 510 { 511 if (smin == Plane::NEGATIVE_SIDE && smax == Plane::NO_SIDE) 512 { 513 if (branch->mLeft) 514 recInsert(branch->mLeft, rend); 515 else 516 recInsertNew(branch, PlaneEvent::PES_LEFT, rend); 517 } 518 else if (smax == Plane::POSITIVE_SIDE && smin == Plane::NO_SIDE) 519 { 520 if (branch->mRight) 521 recInsert(branch->mRight, rend); 522 else 523 recInsertNew(branch, PlaneEvent::PES_RIGHT, rend); 524 } 525 else 526 { 527 // to avoid SNAFUs, rebuild whole subtree 528 //LogManager::getSingleton().logMessage("## Rebuilding subtree for insertion"); 529 rebuildSubtree(node, rend); 530 } 531 } 532 } 533 } 534 535 void KdTree::recInsertNew(KdTree::Branch * parent, PlaneEvent::Side side, KdRenderable * rend) 536 { 537 //LogManager::getSingleton().logMessage("## Inserting into new subtree"); 538 539 AxisAlignedBox left, rigth, aabb; 540 PlaneEventList events; 541 int nObjects; 542 543 rend->computeScene(events, aabb, nObjects, false); 544 545 // override aabb 546 splitBox(*parent, left, rigth); 547 if (side == PlaneEvent::PES_LEFT) 548 { 549 aabb = left; 550 if (mBuildMethod == KDBM_RECURSIVE) 551 parent->mLeft = recBuild(events, nObjects, aabb, parent); 552 else if (mBuildMethod == KDBM_PRIORITYQUEUE) 553 parent->mLeft = pqBuild(events, nObjects, aabb, parent); 554 else 555 { 556 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 557 "Invalid build method for the KdTree.", 558 "KdTree::buildFromList"); 559 parent->mLeft = 0; 560 } 561 562 } 563 else if (side == PlaneEvent::PES_RIGHT) 564 { 565 aabb = rigth; 566 if (mBuildMethod == KDBM_RECURSIVE) 567 parent->mRight = recBuild(events, nObjects, aabb, parent); 568 else if (mBuildMethod == KDBM_PRIORITYQUEUE) 569 parent->mRight = pqBuild(events, nObjects, aabb, parent); 570 else 571 { 572 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 573 "Invalid build method for the KdTree.", 574 "KdTree::buildFromList"); 575 parent->mRight = 0; 576 } 577 } 578 } 579 580 void KdTree::rebuildSubtree(KdTree::Node * node, KdRenderable * rend) 581 { 582 //LogManager::getSingleton().logMessage("## Rebuilding subtree"); 583 584 AxisAlignedBox aabb = node->mAABB; 585 586 KdRenderableList nodelist; 587 nodelist.push_back(rend); 588 addRendToList(node, nodelist); 589 590 if (node == mKdRoot) 591 { 592 OGRE_DELETE(mKdRoot); 593 mKdRoot = buildFromList(nodelist, 0, aabb); 594 } 595 else 596 { 597 KdTree::Branch * parent = KDBRANCHPTR_CAST(node->getParent()); 598 599 if (node == parent->mLeft) 600 { 601 OGRE_DELETE(parent->mLeft); 602 parent->mLeft = buildFromList(nodelist, parent, aabb); 603 } 604 else if (node == parent->mRight) 605 { 606 OGRE_DELETE(parent->mRight); 607 parent->mRight = buildFromList(nodelist, parent, aabb); 608 } 609 else 610 { 611 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 612 "SNAFU while inserting KdRenderable into KdTree.", 613 "KdTree::recInsert" ); 614 } 615 } 616 } 617 618 // compute both AABB then return the requested one. 619 void KdTree::splitBox(const KdTree::Branch& parent, AxisAlignedBox& left, AxisAlignedBox& right) 620 { 621 Vector3 bmin = parent.mAABB.getMinimum(); 622 Vector3 bmax = parent.mAABB.getMaximum(); 623 Real pos = - parent.mSplitPlane->d; 624 int dim = static_cast<int>(parent.mSplitPlane->normal.dotProduct(Vector3(0,1,2))); 625 // set corners which are the same as parent AABB 626 left.setMinimum(bmin); 627 right.setMaximum(bmax); 628 // modify "inner" corners 629 bmin[dim] = pos; 630 bmax[dim] = pos; 631 // set the corners on the split plane 632 left.setMaximum(bmax); 633 right.setMinimum(bmin); 634 } 635 636 void KdTree::addRendToList(KdTree::Node * node, KdRenderableList& nodelist) 637 { 638 if (node->isLeaf()) 639 { 640 KdTree::Leaf * leaf = KDLEAFPTR_CAST(node); 641 KdRenderableList::iterator it = leaf->mKdRenderables.begin(); 642 KdRenderableList::iterator end = leaf->mKdRenderables.end(); 643 while (it != end) 644 { 645 nodelist.push_back(*it); 646 it++; 647 } 648 } 649 else 650 { 651 KdTree::Branch * branch = KDBRANCHPTR_CAST(node); 652 if (branch->mLeft) 653 addRendToList(branch->mLeft, nodelist); 654 if (branch->mRight) 655 addRendToList(branch->mRight, nodelist); 656 } 657 } 658 659 /************************************************************************/ 660 /* KdTree build functions */ 661 /************************************************************************/ 662 663 void KdTree::build(KdRenderable * sceneRoot) 664 { 665 Timer *timer = Root::getSingleton().getTimer(); 666 unsigned long t1, t2, t3, t4; 667 668 mStats.clear(); 669 670 // data we want to collect 671 PlaneEventList events; 672 AxisAlignedBox aabb; 673 int nObjects = 0; 674 675 t1 = timer->getMicroseconds(); // DEBUG 676 sceneRoot->computeScene(events, aabb, nObjects); 677 t2 = timer->getMicroseconds(); // DEBUG 678 events.sort(); 679 t3 = timer->getMicroseconds(); // DEBUG 680 681 mStats.mNumSceneNodes = nObjects; 682 683 assert(! aabb.isNull() && "Teh stubid worldAABB iz NULL ... waht now?"); 684 // hack to avoid SNAFU with "2-dimensional" scene 685 aabb.merge(aabb.getMaximum()+Vector3(1,1,1)); 686 aabb.merge(aabb.getMinimum()+Vector3(-1,-1,-1)); 687 688 if (mBuildMethod == KDBM_RECURSIVE) 689 mKdRoot = recBuild(events, nObjects, aabb, 0); 690 else if (mBuildMethod == KDBM_PRIORITYQUEUE) 691 mKdRoot = pqBuild(events, nObjects, aabb, 0); 692 else 693 { 694 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 695 "Invalid build method for the KdTree.", 696 "KdTree::build"); 697 mKdRoot = 0; 698 } 699 700 t4 = timer->getMicroseconds(); // DEBUG 701 702 String method = "Invalid"; 703 if (mBuildMethod == KDBM_RECURSIVE) 704 method = "Recursive"; 705 else if (mBuildMethod == KDBM_PRIORITYQUEUE) 706 method = "Priority Queue"; 707 708 mBuildLog->logMessage("######## SAH Statistics ########"); 709 mBuildLog->logMessage("Build Method: " + method); 710 mBuildLog->logMessage("Time for events build: " + StringConverter::toString(t2 - t1) + "µs"); 711 mBuildLog->logMessage("Time for events sort: " + StringConverter::toString(t3 - t2) + "µs"); 712 mBuildLog->logMessage("Time for tree build: " + StringConverter::toString(t4 - t3) + "µs"); 713 mBuildLog->logMessage("Total time: " + StringConverter::toString(t4 - t1) + "µs"); 714 mBuildLog->logMessage("Tree Depth: " + StringConverter::toString(mMaxDepth)); 715 mBuildLog->logMessage("Number of Objects: " + StringConverter::toString(mStats.mNumSceneNodes)); 716 mBuildLog->logMessage("Number of Leaves: " + StringConverter::toString(mStats.mNumLeaves)); 717 mBuildLog->logMessage("Number of Nodes: " + StringConverter::toString(mStats.mNumNodes)); 718 mBuildLog->logMessage("Total cost: " + StringConverter::toString(calcCost())); 719 mBuildLog->logMessage("################################"); 720 } 721 722 KdTree::Node * KdTree::buildFromList(KdRenderableList& nodelist, KdTree::Branch * parent, AxisAlignedBox& aabb) 723 { 724 // data we want to collect 725 PlaneEventList events; 726 AxisAlignedBox nodeaabb; 727 int nObjects = 0; 728 729 KdRenderableList::iterator it = nodelist.begin(); 730 KdRenderableList::iterator end = nodelist.end(); 731 while (it != end) 732 { 733 (*it)->computeScene(events, nodeaabb, nObjects, false); 1109 eventsRight.push_back(it->clip(best.bright, best.event.getDimension())); 1110 eventsLeft.push_back(it->clip(best.bleft, best.event.getDimension())); 1111 } 734 1112 it++; 735 1113 } 736 1114 737 events.sort(); 738 739 // HACK 740 if (aabb.isNull()) 741 { 742 aabb = nodeaabb; 743 } 744 745 if (mBuildMethod == KDBM_RECURSIVE) 746 return recBuild(events, nObjects, aabb, parent); 747 else if (mBuildMethod == KDBM_PRIORITYQUEUE) 748 return pqBuild(events, nObjects, aabb, parent); 749 else 750 { 751 OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, 752 "Invalid build method for the KdTree.", 753 "KdTree::buildFromList"); 754 return 0; 755 } 756 } 757 758 KdTree::Node * KdTree::recBuild(PlaneEventList& events, int nObjects, AxisAlignedBox& aabb, KdTree::Branch * parent) 759 { 1115 // create a new branch node and continue recursion 1116 KdTree::Branch * branch = new KdTree::Branch(this, level, aabb, parent, 1117 best.event.getSplitPlane(), best.side); 1118 1119 // now create the child nodes and continue recursion 1120 if (eventsLeft.size() > 0) 1121 { 1122 branch->mLeft = recBuild(eventsLeft, nLeftS + nBothS, best.bleft, branch); 1123 } 1124 if (eventsRight.size() > 0) 1125 { 1126 branch->mRight = recBuild(eventsRight, nBothS + nRightS, best.bright, branch); 1127 } 1128 1129 // update stats 1130 ++ mStats.mNumNodes; 1131 1132 // update bounding box 1133 branch->_updateBounds(false); 1134 1135 return branch; 1136 } 1137 } 1138 1139 KdTree::Node * KdTree::pqBuild(PlaneEventList& events, int nObjects, AxisAlignedBox& aabb, KdTree::Branch * parent) 1140 { 1141 SplitCandidatePQ pqueue; 1142 Real globalTreeCost; 1143 Real globalSA; 1144 1145 KdTree::Node * newNode = 0, * topNode = 0; 1146 // init global tree cost 1147 globalTreeCost = PlaneEvent::KI * nObjects; 1148 globalSA = PlaneEvent::surfaceArea(aabb); 1149 1150 PlaneEventList * e = new PlaneEventList(events); 1151 1152 // inital split candidate 1153 SplitInfo * best = pqFindPlane(e, nObjects, aabb, globalSA); 1154 SplitCandidate splitcandidate(e, nObjects, aabb, parent, globalTreeCost, 1155 globalTreeCost - best->cost, best, PlaneEvent::PES_BOTH); 1156 pqueue.push(splitcandidate); 1157 1158 1159 /*** BEGIN ITERATIVE BUILD ***/ 1160 while (!pqueue.empty()) 1161 { 1162 SplitCandidate sc = pqueue.top(); 1163 pqueue.pop(); 1164 760 1165 // determine the depth we are on 761 1166 int level = 0; 762 if (parent) 763 { 764 level = parent->getLevel() + 1; 765 } 766 767 /************************************************/ 768 /**************** BEGIN FINDPLANE ***************/ 769 /************************************************/ 770 // find optimal split plane and split node accordingly 771 772 // initialize 773 const int dim = 3; 774 int pStart, pOn, pEnd; 775 int nLeft[dim], nPlane[dim], nRight[dim]; 776 for (int i = 0; i < dim; i++) 777 { 778 nLeft[i] = 0; nPlane[i] = 0; nRight[i] = nObjects; 779 } 780 781 SplitInfo split, best; 782 best.cost = Math::POS_INFINITY; 783 784 PlaneEventList::iterator begin = events.begin(); 785 PlaneEventList::iterator end = events.end(); 786 PlaneEventList::iterator it = begin; 787 // try all planes to find the best one for the given set of objects 788 while (it != end) 789 { 790 PlaneEventList::iterator p = it; 791 pStart = pOn = pEnd = 0; 792 while (it != end && p->equalsType(*it, PlaneEvent::PET_END)) 793 { 794 it++; pEnd++; 795 } 796 while (it != end && p->equalsType(*it, PlaneEvent::PET_ON)) 797 { 798 it++; pOn++; 799 } 800 while (it != end && p->equalsType(*it, PlaneEvent::PET_START)) 801 { 802 it++; pStart++; 803 } 804 int d = p->getDimension(); 805 nPlane[d] = pOn; nRight[d] -= pOn; nRight[d] -= pEnd; 806 p->SAH(aabb, nLeft[d], nPlane[d], nRight[d], split); 807 if (split.cost < best.cost) 808 { 809 best = split; 810 } 811 nLeft[d] += pStart; nLeft[d] += pOn; nPlane[d] = 0; 1167 if (sc.parent) 1168 { 1169 level = sc.parent->getLevel() + 1; 812 1170 } 813 1171 … … 816 1174 /************************************************/ 817 1175 // check terminating condition 818 if ( best.cost > PlaneEvent::KI*nObjects|| level >= mMaxDepth)1176 if (sc.decrease < 0.0 || level >= mMaxDepth) 819 1177 { 820 1178 // Terminating condition reached, create leaf and add renderables to list 821 KdTree::Leaf * leaf = new KdTree::Leaf(this, level, aabb,parent);1179 KdTree::Leaf * leaf = new KdTree::Leaf(this, level, sc.aabb, sc.parent); 822 1180 KdRenderable *rend; 823 it = begin; 1181 PlaneEventList::iterator begin = sc.events->begin(); 1182 PlaneEventList::iterator end = sc.events->end(); 1183 PlaneEventList::iterator it = begin; 824 1184 while (it != end) 825 1185 { … … 832 1192 it++; 833 1193 } 1194 newNode = leaf; 1195 if (!topNode) 1196 topNode = leaf; 834 1197 // update stats 835 1198 ++ mStats.mNumNodes; 836 1199 ++ mStats.mNumLeaves; 837 // update bounding box838 leaf->_updateBounds(false);839 return leaf;840 1200 } 841 1201 … … 843 1203 /**************** BEGIN CLASSIFY ****************/ 844 1204 /************************************************/ 845 // split the event list in left and right sub-lists846 1205 else 847 1206 { 848 PlaneEventList eventsRight, eventsLeft; 849 it = begin; 1207 PlaneEventList * eventsLeft = new PlaneEventList(); 1208 PlaneEventList * eventsRight = new PlaneEventList(); 1209 PlaneEventList::iterator begin = sc.events->begin(); 1210 PlaneEventList::iterator end = sc.events->end(); 1211 PlaneEventList::iterator it = begin; 850 1212 // slightly redundant, since we mark each renderable up to 6 times 851 1213 while (it != end) … … 855 1217 it++; 856 1218 } 1219 857 1220 // now classify all renderables. do they belong to the left child, the right child or both? 858 1221 it = begin; 859 1222 while (it != end) 860 1223 { 861 it->classify( best.event, best.side);1224 it->classify(sc.best->event, sc.best->side); 862 1225 it++; 863 1226 } 1227 864 1228 // divide the event lists 865 1229 int nLeftS = 0, nRightS = 0, nBothS = 0; … … 867 1231 while (it != end) 868 1232 { 869 // right-only nodes go inright list1233 // right-only events go in the right list 870 1234 if (it->getRenderable()->getSide() == PlaneEvent::PES_RIGHT) 871 1235 { … … 875 1239 nRightS++; 876 1240 } 877 eventsRight.push_back(*it); 1241 1242 eventsRight->push_back(*it); 878 1243 } 879 // left-only nodes go inleft list1244 // left-only events go in the left list 880 1245 else if (it->getRenderable()->getSide() == PlaneEvent::PES_LEFT) 881 1246 { … … 885 1250 nLeftS++; 886 1251 } 887 eventsLeft .push_back(*it);1252 eventsLeft->push_back(*it); 888 1253 } 889 // remaining nodes go in both lists, bust must be clipped to prevent 890 // events from lying outside the new nodes aabb 1254 // the rest goes in both lists after being clipped 891 1255 else 892 1256 { … … 896 1260 nBothS++; 897 1261 } 898 eventsRight.push_back(it->clip(best.bright, best.event.getDimension())); 899 eventsLeft.push_back(it->clip(best.bleft, best.event.getDimension())); 1262 1263 eventsRight->push_back(it->clip(sc.best->bright, sc.best->event.getDimension())); 1264 eventsLeft->push_back(it->clip(sc.best->bleft, sc.best->event.getDimension())); 900 1265 } 901 1266 it++; 902 1267 } 903 1268 904 // create a new branch node and continue recursion 905 KdTree::Branch * branch = new KdTree::Branch(this, level, aabb, parent, 906 best.event.getSplitPlane(), best.side); 907 908 // now create the child nodes and continue recursion 909 if (eventsLeft.size() > 0) 910 { 911 branch->mLeft = recBuild(eventsLeft, nLeftS + nBothS, best.bleft, branch); 912 } 913 if (eventsRight.size() > 0) 914 { 915 branch->mRight = recBuild(eventsRight, nBothS + nRightS, best.bright, branch); 916 } 1269 // create a new branch node 1270 KdTree::Branch * branch = new KdTree::Branch(this, level, sc.aabb, sc.parent, 1271 sc.best->event.getSplitPlane(), sc.best->side); 1272 1273 globalTreeCost -= sc.decrease; 1274 1275 1276 // now for each potential child node, compute the split plane and the cost decrease 1277 // and place them in the queue 1278 if (eventsLeft->size() > 0) 1279 { 1280 best = pqFindPlane(eventsLeft, nLeftS + nBothS, sc.best->bleft, globalSA); 1281 Real old = PlaneEvent::surfaceArea(sc.best->bleft)/globalSA*PlaneEvent::KI*(nLeftS + nBothS); 1282 SplitCandidate scleft(eventsLeft, nLeftS + nBothS, sc.best->bleft, 1283 branch, old, old - best->cost, best, PlaneEvent::PES_LEFT); 1284 pqueue.push(scleft); 1285 } 1286 // cleanup 1287 else 1288 { 1289 delete eventsLeft; 1290 } 1291 1292 if (eventsRight->size() > 0) 1293 { 1294 best = pqFindPlane(eventsRight, nBothS + nRightS, sc.best->bright, globalSA); 1295 Real old = PlaneEvent::surfaceArea(sc.best->bright)/globalSA*PlaneEvent::KI*(nBothS + nRightS); 1296 SplitCandidate scright(eventsRight, nBothS + nRightS, sc.best->bright, 1297 branch, old, old - best->cost, best, PlaneEvent::PES_RIGHT); 1298 pqueue.push(scright); 1299 } 1300 // cleanup 1301 else 1302 { 1303 delete eventsRight; 1304 } 1305 1306 newNode = branch; 1307 if (!topNode) 1308 topNode = branch; 1309 917 1310 918 1311 // update stats 919 1312 ++ mStats.mNumNodes; 920 921 // update bounding box 922 branch->_updateBounds(false); 923 924 return branch; 925 } 926 } 927 928 KdTree::Node * KdTree::pqBuild(PlaneEventList& events, int nObjects, AxisAlignedBox& aabb, KdTree::Branch * parent) 929 { 930 SplitCandidatePQ pqueue; 931 Real globalTreeCost; 932 Real globalSA; 933 934 KdTree::Node * newNode = 0, * topNode = 0; 935 // init global tree cost 936 globalTreeCost = PlaneEvent::KI * nObjects; 937 globalSA = PlaneEvent::surfaceArea(aabb); 938 939 PlaneEventList * e = new PlaneEventList(events); 940 941 // inital split candidate 942 SplitInfo * best = pqFindPlane(e, nObjects, aabb, globalSA); 943 SplitCandidate splitcandidate(e, nObjects, aabb, parent, globalTreeCost, 944 globalTreeCost - best->cost, best, PlaneEvent::PES_BOTH); 945 pqueue.push(splitcandidate); 946 947 948 /*** BEGIN ITERATIVE BUILD ***/ 949 while (!pqueue.empty()) 950 { 951 SplitCandidate sc = pqueue.top(); 952 pqueue.pop(); 953 954 // determine the depth we are on 955 int level = 0; 956 if (sc.parent) 957 { 958 level = sc.parent->getLevel() + 1; 959 } 960 961 /************************************************/ 962 /**************** BEGIN TERMINATE ***************/ 963 /************************************************/ 964 // check terminating condition 965 if (sc.decrease < 0.0 || level >= mMaxDepth) 966 { 967 // Terminating condition reached, create leaf and add renderables to list 968 KdTree::Leaf * leaf = new KdTree::Leaf(this, level, sc.aabb, sc.parent); 969 KdRenderable *rend; 970 PlaneEventList::iterator begin = sc.events->begin(); 971 PlaneEventList::iterator end = sc.events->end(); 972 PlaneEventList::iterator it = begin; 973 while (it != end) 1313 } 1314 1315 // attach new node to parent 1316 if (sc.parent) 1317 { 1318 if (sc.side == PlaneEvent::PES_LEFT) 1319 { 1320 sc.parent->mLeft = newNode; 1321 } 1322 else if (sc.side == PlaneEvent::PES_RIGHT) 1323 { 1324 sc.parent->mRight = newNode; 1325 } 1326 else 1327 { 1328 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 1329 "PQBUILD SNAFU - CHILD I AM NOT LEFT NOR RIGHT","KdTree::pqBuild"); 1330 } 1331 } 1332 1333 // update bounding boxes when geometry (leaf) was added 1334 if (newNode->isLeaf()) 1335 newNode->_updateBounds(); 1336 1337 //cleanup 1338 OGRE_DELETE(sc.events); 1339 OGRE_DELETE(sc.best); 1340 } 1341 mBuildLog->logMessage("Cost after PQBUILD " + StringConverter::toString(globalTreeCost)); 1342 return topNode; 1343 } 1344 1345 //------------------------------------------------------------------------- 1346 SplitInfo * KdTree::pqFindPlane(PlaneEventList * events, int nObjects, AxisAlignedBox& aabb, Real globalSA) 1347 { 1348 static const int dim = 3; 1349 int pStart, pOn, pEnd; 1350 int nLeft[dim], nPlane[dim], nRight[dim]; 1351 for (int i = 0; i < dim; i++) 1352 { 1353 nLeft[i] = 0; nPlane[i] = 0; nRight[i] = nObjects; 1354 } 1355 1356 SplitInfo split, best; 1357 best.cost = Math::POS_INFINITY; 1358 1359 Real parentSA = PlaneEvent::surfaceArea(aabb); 1360 1361 PlaneEventList::iterator begin = events->begin(); 1362 PlaneEventList::iterator end = events->end(); 1363 PlaneEventList::iterator it = begin; 1364 // try all planes to find the best one for the given set of objects 1365 while (it != end) 1366 { 1367 PlaneEventList::iterator p = it; 1368 pStart = pOn = pEnd = 0; 1369 while (it != end && p->equalsType(*it, PlaneEvent::PET_END)) 1370 { 1371 it++; pEnd++; 1372 } 1373 while (it != end && p->equalsType(*it, PlaneEvent::PET_ON)) 1374 { 1375 it++; pOn++; 1376 } 1377 while (it != end && p->equalsType(*it, PlaneEvent::PET_START)) 1378 { 1379 it++; pStart++; 1380 } 1381 int d = p->getDimension(); 1382 nPlane[d] = pOn; nRight[d] -= pOn; nRight[d] -= pEnd; 1383 p->pqSAH(globalSA, parentSA, nLeft[d], nPlane[d], nRight[d], aabb, split); 1384 if (split.cost < best.cost) 1385 { 1386 best = split; 1387 } 1388 nLeft[d] += pStart; nLeft[d] += pOn; nPlane[d] = 0; 1389 } 1390 return new SplitInfo(best); 1391 } 1392 1393 /************************************************************************/ 1394 /* KdTree rendering functions */ 1395 /************************************************************************/ 1396 1397 //------------------------------------------------------------------------- 1398 void KdTree::queueVisibleObjects(KdTreeCamera* cam, RenderQueue* queue, bool onlyShadowCasters, 1399 bool showBoxes, KdTree::NodeList& visibleNodes) 1400 { 1401 // debug 1402 //cam->mNumVisQueries = 0; 1403 1404 if (mKdRoot) 1405 recQueueVisibleObjects(mKdRoot, Root::getSingleton().getCurrentFrameNumber(), 1406 cam, queue, onlyShadowCasters, showBoxes, visibleNodes); 1407 1408 //mBuildLog->logMessage("Frame # " + StringConverter::toString(Root::getSingleton().getCurrentFrameNumber()) + 1409 // " ," + StringConverter::toString(cam->mNumVisQueries) + " vis queries"); 1410 } 1411 1412 //------------------------------------------------------------------------- 1413 void KdTree::recQueueVisibleObjects(KdTree::Node * node, unsigned long currentFrame, 1414 KdTreeCamera* cam, RenderQueue* queue, bool onlyShadowCasters, bool showBoxes, 1415 KdTree::NodeList& visibleNodes, bool fullVis) 1416 { 1417 KdTreeCamera::NodeVisibility vis = KdTreeCamera::KDNV_PART; 1418 // test visibility 1419 //if (cam->isVisible(node->mAABB)) 1420 if (fullVis || 1421 ((vis = (cam->*getVisibility)(node->mAABB)) != KdTreeCamera::KDNV_NONE)) 1422 //((vis = (cam->*getVisibility)(node->mAABB)) != KdTreeCamera::KDNV_NONE)) 1423 { 1424 visibleNodes.push_back(node); 1425 1426 bool v = (fullVis || vis == KdTreeCamera::KDNV_FULL); 1427 node->queueVisibleObjects(currentFrame, cam, queue, onlyShadowCasters, showBoxes, v); 1428 1429 if (!v) 1430 { 1431 1432 if (node->getLeftChild()) 1433 recQueueVisibleObjects(node->getLeftChild(), currentFrame, 1434 cam, queue, onlyShadowCasters, showBoxes, visibleNodes, v); 1435 if (node->getRightChild()) 1436 recQueueVisibleObjects(node->getRightChild(), currentFrame, 1437 cam, queue, onlyShadowCasters, showBoxes, visibleNodes, v); 1438 } 1439 } 1440 } 1441 1442 //------------------------------------------------------------------------- 1443 void KdTree::setEnhancedVis(bool enh) 1444 { 1445 if (enh) 1446 getVisibility = &KdTreeCamera::getVisibilityEnhanced; 1447 else 1448 getVisibility = &KdTreeCamera::getVisibilitySimple; 1449 } 1450 1451 //------------------------------------------------------------------------- 1452 bool KdTree::getEnhancedVis() 1453 { 1454 return getVisibility == &KdTreeCamera::getVisibilityEnhanced; 1455 } 1456 1457 //------------------------------------------------------------------------- 1458 //void KdTree::findVisibleNodes(NodeList& visibleNodes, Camera * cam) 1459 //{ 1460 // if (mKdRoot) 1461 // recFindVisibleNodes(mKdRoot, visibleNodes, cam); 1462 //} 1463 1464 ////------------------------------------------------------------------------- 1465 //void KdTree::recFindVisibleNodes(KdTree::Node * node, NodeList& visibleNodes, Camera * cam) 1466 //{ 1467 // // test visibility 1468 // if (cam->isVisible(node->mAABB)) 1469 // { 1470 // visibleNodes.push_back(node); 1471 1472 // if (node->getLeftChild()) 1473 // recFindVisibleNodes(node->getLeftChild(), visibleNodes, cam); 1474 // if (node->getRightChild()) 1475 // recFindVisibleNodes(node->getRightChild(), visibleNodes, cam); 1476 // } 1477 //} 1478 1479 void KdTree::findNodesIn(const AxisAlignedBox &box, std::list<SceneNode *> &list, SceneNode *exclude) 1480 { 1481 if (mKdRoot) 1482 recFindNodesIn(box, list, exclude, mKdRoot); 1483 } 1484 1485 void KdTree::findNodesIn(const Sphere &sphere, std::list<SceneNode *> &list, SceneNode *exclude) 1486 { 1487 if (mKdRoot) 1488 recFindNodesIn(sphere, list, exclude, mKdRoot); 1489 } 1490 1491 void KdTree::findNodesIn(const PlaneBoundedVolume &volume, std::list<SceneNode *> &list, SceneNode *exclude) 1492 { 1493 if (mKdRoot) 1494 recFindNodesIn(volume, list, exclude, mKdRoot); 1495 } 1496 1497 void KdTree::findNodesIn(const Ray &ray, std::list<SceneNode *> &list, SceneNode *exclude) 1498 { 1499 if (mKdRoot) 1500 recFindNodesIn(ray, list, exclude, mKdRoot); 1501 } 1502 1503 void KdTree::recFindNodesIn(const AxisAlignedBox &box, std::list<SceneNode *> &list, SceneNode *exclude, Node * node, bool full) 1504 { 1505 // check intersection 1506 if ( !full ) 1507 { 1508 Intersection isect = intersect(box, node->_getWorldAABB()); 1509 1510 if ( isect == OUTSIDE ) 1511 return ; 1512 1513 full = ( isect == INSIDE ); 1514 } 1515 1516 if (node->isLeaf()) 1517 { 1518 LeafPtr leaf = KDLEAFPTR_CAST(node); 1519 for (KdRenderableList::iterator it = leaf->mKdRenderables.begin(); 1520 it != leaf->mKdRenderables.end(); it ++) 1521 { 1522 SceneNode *sn = dynamic_cast<SceneNode *>(*it); 1523 1524 if (sn != exclude) 1525 { 1526 if (full) 974 1527 { 975 rend = it->getRenderable(); 976 rend->setClassified(false); 977 if (rend->attachTo(leaf, this)) 978 { 979 leaf->insert(rend); 980 } 981 it++; 982 } 983 newNode = leaf; 984 if (!topNode) 985 topNode = leaf; 986 // update stats 987 ++ mStats.mNumNodes; 988 ++ mStats.mNumLeaves; 989 } 990 991 /************************************************/ 992 /**************** BEGIN CLASSIFY ****************/ 993 /************************************************/ 994 else 995 { 996 PlaneEventList * eventsLeft = new PlaneEventList(); 997 PlaneEventList * eventsRight = new PlaneEventList(); 998 PlaneEventList::iterator begin = sc.events->begin(); 999 PlaneEventList::iterator end = sc.events->end(); 1000 PlaneEventList::iterator it = begin; 1001 // slightly redundant, since we mark each renderable up to 6 times 1002 while (it != end) 1003 { 1004 it->getRenderable()->setSide(PlaneEvent::PES_BOTH); 1005 it->getRenderable()->setClassified(false); 1006 it++; 1007 } 1008 1009 // now classify all renderables. do they belong to the left child, the right child or both? 1010 it = begin; 1011 while (it != end) 1012 { 1013 it->classify(sc.best->event, sc.best->side); 1014 it++; 1015 } 1016 1017 // divide the event lists 1018 int nLeftS = 0, nRightS = 0, nBothS = 0; 1019 it = begin; 1020 while (it != end) 1021 { 1022 // right-only events go in the right list 1023 if (it->getRenderable()->getSide() == PlaneEvent::PES_RIGHT) 1024 { 1025 if (!it->getRenderable()->isClassified()) 1026 { 1027 it->getRenderable()->setClassified(true); 1028 nRightS++; 1029 } 1030 1031 eventsRight->push_back(*it); 1032 } 1033 // left-only events go in the left list 1034 else if (it->getRenderable()->getSide() == PlaneEvent::PES_LEFT) 1035 { 1036 if (!it->getRenderable()->isClassified()) 1037 { 1038 it->getRenderable()->setClassified(true); 1039 nLeftS++; 1040 } 1041 eventsLeft->push_back(*it); 1042 } 1043 // the rest goes in both lists after being clipped 1044 else 1045 { 1046 if (!it->getRenderable()->isClassified()) 1047 { 1048 it->getRenderable()->setClassified(true); 1049 nBothS++; 1050 } 1051 1052 eventsRight->push_back(it->clip(sc.best->bright, sc.best->event.getDimension())); 1053 eventsLeft->push_back(it->clip(sc.best->bleft, sc.best->event.getDimension())); 1054 } 1055 it++; 1056 } 1057 1058 // create a new branch node 1059 KdTree::Branch * branch = new KdTree::Branch(this, level, sc.aabb, sc.parent, 1060 sc.best->event.getSplitPlane(), sc.best->side); 1061 1062 globalTreeCost -= sc.decrease; 1063 1064 1065 // now for each potential child node, compute the split plane and the cost decrease 1066 // and place them in the queue 1067 if (eventsLeft->size() > 0) 1068 { 1069 best = pqFindPlane(eventsLeft, nLeftS + nBothS, sc.best->bleft, globalSA); 1070 Real old = PlaneEvent::surfaceArea(sc.best->bleft)/globalSA*PlaneEvent::KI*(nLeftS + nBothS); 1071 SplitCandidate scleft(eventsLeft, nLeftS + nBothS, sc.best->bleft, 1072 branch, old, old - best->cost, best, PlaneEvent::PES_LEFT); 1073 pqueue.push(scleft); 1074 } 1075 // cleanup 1076 else 1077 { 1078 delete eventsLeft; 1079 } 1080 1081 if (eventsRight->size() > 0) 1082 { 1083 best = pqFindPlane(eventsRight, nBothS + nRightS, sc.best->bright, globalSA); 1084 Real old = PlaneEvent::surfaceArea(sc.best->bright)/globalSA*PlaneEvent::KI*(nBothS + nRightS); 1085 SplitCandidate scright(eventsRight, nBothS + nRightS, sc.best->bright, 1086 branch, old, old - best->cost, best, PlaneEvent::PES_RIGHT); 1087 pqueue.push(scright); 1088 } 1089 // cleanup 1090 else 1091 { 1092 delete eventsRight; 1093 } 1094 1095 newNode = branch; 1096 if (!topNode) 1097 topNode = branch; 1098 1099 1100 // update stats 1101 ++ mStats.mNumNodes; 1102 } 1103 1104 // attach new node to parent 1105 if (sc.parent) 1106 { 1107 if (sc.side == PlaneEvent::PES_LEFT) 1108 { 1109 sc.parent->mLeft = newNode; 1110 } 1111 else if (sc.side == PlaneEvent::PES_RIGHT) 1112 { 1113 sc.parent->mRight = newNode; 1528 list.push_back(sn); 1114 1529 } 1115 1530 else 1116 1531 { 1117 OGRE_EXCEPT(Exception::ERR_INTERNAL_ERROR, 1118 "PQBUILD SNAFU - CHILD I AM NOT LEFT NOR RIGHT","KdTree::pqBuild"); 1532 Intersection nsect = intersect(box, sn->_getWorldAABB()); 1533 1534 if ( nsect != OUTSIDE ) 1535 { 1536 list.push_back(sn); 1537 } 1119 1538 } 1120 1539 } 1121 1122 // update bounding boxes when geometry (leaf) was added 1123 if (newNode->isLeaf()) 1124 newNode->_updateBounds(); 1125 1126 //cleanup 1127 OGRE_DELETE(sc.events); 1128 OGRE_DELETE(sc.best); 1129 } 1130 mBuildLog->logMessage("Cost after PQBUILD " + StringConverter::toString(globalTreeCost)); 1131 return topNode; 1132 } 1133 1134 //------------------------------------------------------------------------- 1135 SplitInfo * KdTree::pqFindPlane(PlaneEventList * events, int nObjects, AxisAlignedBox& aabb, Real globalSA) 1136 { 1137 static const int dim = 3; 1138 int pStart, pOn, pEnd; 1139 int nLeft[dim], nPlane[dim], nRight[dim]; 1140 for (int i = 0; i < dim; i++) 1141 { 1142 nLeft[i] = 0; nPlane[i] = 0; nRight[i] = nObjects; 1143 } 1144 1145 SplitInfo split, best; 1146 best.cost = Math::POS_INFINITY; 1147 1148 Real parentSA = PlaneEvent::surfaceArea(aabb); 1149 1150 PlaneEventList::iterator begin = events->begin(); 1151 PlaneEventList::iterator end = events->end(); 1152 PlaneEventList::iterator it = begin; 1153 // try all planes to find the best one for the given set of objects 1540 } 1541 } 1542 else 1543 { 1544 if (node->getLeftChild()) 1545 recFindNodesIn(box, list, exclude, node->getLeftChild(), full); 1546 if (node->getRightChild()) 1547 recFindNodesIn(box, list, exclude, node->getRightChild(), full); 1548 } 1549 } 1550 1551 void KdTree::recFindNodesIn(const Sphere &sphere, std::list<SceneNode *> &list, SceneNode *exclude, Node * node, bool full) 1552 { 1553 // TODO 1554 } 1555 1556 void KdTree::recFindNodesIn(const PlaneBoundedVolume &volume, std::list<SceneNode *> &list, SceneNode *exclude, Node * node, bool full) 1557 { 1558 // TODO 1559 } 1560 1561 void KdTree::recFindNodesIn(const Ray &ray, std::list<SceneNode *> &list, SceneNode *exclude, Node * node, bool full) 1562 { 1563 // TODO 1564 } 1565 1566 /************************************************************************/ 1567 /* KdTree debug & helper functions */ 1568 /************************************************************************/ 1569 1570 //------------------------------------------------------------------------- 1571 void KdTree::dump() 1572 { 1573 //LogManager::getSingleton().logMessage("#@#@#@#@ Dumping KdTree #@#@#@#@"); 1574 mBuildLog->logMessage("#@#@#@#@ Dumping KdTree #@#@#@#@"); 1575 if (mKdRoot) 1576 dump(mKdRoot); 1577 } 1578 1579 //------------------------------------------------------------------------- 1580 void KdTree::dump(KdTree::Node * node) 1581 { 1582 //LogManager * log = LogManager::getSingletonPtr(); 1583 KdTreeSceneNode * scenenode; 1584 String pad; 1585 int p; 1586 1587 pad = ""; 1588 for (p = 0; p < node->getLevel(); p++) 1589 { 1590 pad += " "; 1591 } 1592 1593 if (node->isLeaf()) 1594 { 1595 KdTree::Leaf * leaf = KDLEAFPTR_CAST(node); 1596 KdRenderableList::iterator it = leaf->mKdRenderables.begin(); 1597 KdRenderableList::iterator end = leaf->mKdRenderables.end(); 1154 1598 while (it != end) 1155 1599 { 1156 PlaneEventList::iterator p = it; 1157 pStart = pOn = pEnd = 0; 1158 while (it != end && p->equalsType(*it, PlaneEvent::PET_END)) 1159 { 1160 it++; pEnd++; 1161 } 1162 while (it != end && p->equalsType(*it, PlaneEvent::PET_ON)) 1163 { 1164 it++; pOn++; 1165 } 1166 while (it != end && p->equalsType(*it, PlaneEvent::PET_START)) 1167 { 1168 it++; pStart++; 1169 } 1170 int d = p->getDimension(); 1171 nPlane[d] = pOn; nRight[d] -= pOn; nRight[d] -= pEnd; 1172 p->pqSAH(globalSA, parentSA, nLeft[d], nPlane[d], nRight[d], aabb, split); 1173 if (split.cost < best.cost) 1174 { 1175 best = split; 1176 } 1177 nLeft[d] += pStart; nLeft[d] += pOn; nPlane[d] = 0; 1178 } 1179 return new SplitInfo(best); 1180 } 1181 1182 /************************************************************************/ 1183 /* KdTree rendering functions */ 1184 /************************************************************************/ 1185 1186 //------------------------------------------------------------------------- 1187 void KdTree::queueVisibleObjects(KdTreeCamera* cam, RenderQueue* queue, bool onlyShadowCasters, 1188 bool showBoxes, KdTree::NodeList& visibleNodes) 1189 { 1190 // debug 1191 //cam->mNumVisQueries = 0; 1192 1193 if (mKdRoot) 1194 recQueueVisibleObjects(mKdRoot, Root::getSingleton().getCurrentFrameNumber(), 1195 cam, queue, onlyShadowCasters, showBoxes, visibleNodes); 1196 1197 //mBuildLog->logMessage("Frame # " + StringConverter::toString(Root::getSingleton().getCurrentFrameNumber()) + 1198 // " ," + StringConverter::toString(cam->mNumVisQueries) + " vis queries"); 1199 } 1200 1201 //------------------------------------------------------------------------- 1202 void KdTree::recQueueVisibleObjects(KdTree::Node * node, unsigned long currentFrame, 1203 KdTreeCamera* cam, RenderQueue* queue, bool onlyShadowCasters, bool showBoxes, 1204 KdTree::NodeList& visibleNodes, bool fullVis) 1205 { 1206 KdTreeCamera::NodeVisibility vis = KdTreeCamera::KDNV_PART; 1207 // test visibility 1208 //if (cam->isVisible(node->mAABB)) 1209 if (fullVis || 1210 ((vis = (cam->*getVisibility)(node->mAABB)) != KdTreeCamera::KDNV_NONE)) 1211 //((vis = (cam->*getVisibility)(node->mAABB)) != KdTreeCamera::KDNV_NONE)) 1212 { 1213 visibleNodes.push_back(node); 1214 1215 bool v = (fullVis || vis == KdTreeCamera::KDNV_FULL); 1216 node->queueVisibleObjects(currentFrame, cam, queue, onlyShadowCasters, showBoxes, v); 1217 1218 if (!v) 1219 { 1220 1221 if (node->getLeftChild()) 1222 recQueueVisibleObjects(node->getLeftChild(), currentFrame, 1223 cam, queue, onlyShadowCasters, showBoxes, visibleNodes, v); 1224 if (node->getRightChild()) 1225 recQueueVisibleObjects(node->getRightChild(), currentFrame, 1226 cam, queue, onlyShadowCasters, showBoxes, visibleNodes, v); 1227 } 1228 } 1229 } 1230 1231 //------------------------------------------------------------------------- 1232 void KdTree::setEnhancedVis(bool enh) 1233 { 1234 if (enh) 1235 getVisibility = &KdTreeCamera::getVisibilityEnhanced; 1236 else 1237 getVisibility = &KdTreeCamera::getVisibilitySimple; 1238 } 1239 1240 //------------------------------------------------------------------------- 1241 bool KdTree::getEnhancedVis() 1242 { 1243 return getVisibility == &KdTreeCamera::getVisibilityEnhanced; 1244 } 1245 1246 //------------------------------------------------------------------------- 1247 //void KdTree::findVisibleNodes(NodeList& visibleNodes, Camera * cam) 1248 //{ 1249 // if (mKdRoot) 1250 // recFindVisibleNodes(mKdRoot, visibleNodes, cam); 1251 //} 1252 1253 ////------------------------------------------------------------------------- 1254 //void KdTree::recFindVisibleNodes(KdTree::Node * node, NodeList& visibleNodes, Camera * cam) 1255 //{ 1256 // // test visibility 1257 // if (cam->isVisible(node->mAABB)) 1258 // { 1259 // visibleNodes.push_back(node); 1260 1261 // if (node->getLeftChild()) 1262 // recFindVisibleNodes(node->getLeftChild(), visibleNodes, cam); 1263 // if (node->getRightChild()) 1264 // recFindVisibleNodes(node->getRightChild(), visibleNodes, cam); 1265 // } 1266 //} 1267 1268 /************************************************************************/ 1269 /* KdTree debug & helper functions */ 1270 /************************************************************************/ 1271 1272 //------------------------------------------------------------------------- 1273 void KdTree::dump() 1274 { 1275 //LogManager::getSingleton().logMessage("#@#@#@#@ Dumping KdTree #@#@#@#@"); 1276 mBuildLog->logMessage("#@#@#@#@ Dumping KdTree #@#@#@#@"); 1277 if (mKdRoot) 1278 dump(mKdRoot); 1279 } 1280 1281 //------------------------------------------------------------------------- 1282 void KdTree::dump(KdTree::Node * node) 1283 { 1284 //LogManager * log = LogManager::getSingletonPtr(); 1285 KdTreeSceneNode * scenenode; 1286 String pad; 1287 int p; 1288 1289 pad = ""; 1290 for (p = 0; p < node->getLevel(); p++) 1291 { 1292 pad += " "; 1293 } 1294 1295 if (node->isLeaf()) 1296 { 1297 KdTree::Leaf * leaf = KDLEAFPTR_CAST(node); 1298 KdRenderableList::iterator it = leaf->mKdRenderables.begin(); 1299 KdRenderableList::iterator end = leaf->mKdRenderables.end(); 1300 while (it != end) 1301 { 1302 scenenode = dynamic_cast<KdTreeSceneNode *>(*it); 1303 mBuildLog->logMessage(pad + "# Leaf level " + 1304 StringConverter::toString(node->getLevel()) + 1305 " SceneNode " + scenenode->getName()); 1306 mBuildLog->logMessage(pad + "## Objects: " + scenenode->dumpToString()); 1307 it++; 1308 } 1309 } 1310 else 1311 { 1312 KdTree::Branch * branch = KDBRANCHPTR_CAST(node); 1313 if (branch->mLeft) 1314 { 1315 mBuildLog->logMessage(pad + "# Branch level " + 1316 StringConverter::toString(node->getLevel()) + " Left Child"); 1317 dump(branch->mLeft); 1318 } 1319 if (branch->mRight) 1320 { 1321 mBuildLog->logMessage(pad + "# Branch level " + 1322 StringConverter::toString(node->getLevel()) + " Right Child"); 1323 dump(branch->mRight); 1324 } 1325 } 1326 } 1327 1328 //------------------------------------------------------------------------- 1329 Real KdTree::calcCost() 1330 { 1331 if (mKdRoot) 1332 return calcCost(mKdRoot, PlaneEvent::surfaceArea(mKdRoot->mAABB)); 1333 else 1334 return 0; 1335 } 1336 1337 //------------------------------------------------------------------------- 1338 Real KdTree::calcCost(KdTree::Node * node, Real vs) 1339 { 1340 if (node == 0) 1341 return 0.0; 1342 1343 if (node->isLeaf()) 1344 { 1345 KdTree::Leaf * leaf = KDLEAFPTR_CAST(node); 1346 return (PlaneEvent::surfaceArea(node->mAABB)/vs) * 1347 PlaneEvent::KI * leaf->mKdRenderables.size(); 1348 } 1349 else 1350 { 1351 KdTree::Branch * branch = KDBRANCHPTR_CAST(node); 1352 return (PlaneEvent::surfaceArea(node->mAABB)/vs) * PlaneEvent::KT + 1353 calcCost(branch->mLeft, vs) + calcCost(branch->mRight, vs); 1354 } 1355 } 1356 1357 /************************************************************************/ 1358 /* KdTree::Node/Branch/Leaf functions */ 1359 /************************************************************************/ 1360 1361 //------------------------------------------------------------------------- 1362 KdTree::Leaf::~Leaf() 1363 { 1364 // detach all scene nodes in the case that we are rebuilding 1365 // the tree but not the scene 1366 KdRenderableList::iterator it = mKdRenderables.begin(); 1367 KdRenderableList::iterator end = mKdRenderables.end(); 1368 while (it != end) 1369 { 1370 (*it)->detachFrom(this); 1600 scenenode = dynamic_cast<KdTreeSceneNode *>(*it); 1601 mBuildLog->logMessage(pad + "# Leaf level " + 1602 StringConverter::toString(node->getLevel()) + 1603 " SceneNode " + scenenode->getName()); 1604 mBuildLog->logMessage(pad + "## Objects: " + scenenode->dumpToString()); 1371 1605 it++; 1372 1606 } 1373 mKdRenderables.clear(); 1374 } 1375 1376 //------------------------------------------------------------------------- 1377 void KdTree::Leaf::queueVisibleObjects(unsigned long currentFrame, 1378 Camera* cam, RenderQueue* queue, bool onlyShadowCasters, bool showBoxes, bool fullVis) 1379 { 1380 KdRenderableList::iterator it = mKdRenderables.begin(); 1381 KdRenderableList::iterator end = mKdRenderables.end(); 1382 while (it != end) 1383 { 1384 if (!(*it)->isQueued(currentFrame, cam)) 1385 { 1386 (*it)->queueObjects(cam, queue, onlyShadowCasters); 1387 } 1388 it++; 1389 } 1390 1391 if (showBoxes) 1392 if (mLevel == mOwner->getHiLiteLevel() || mOwner->getShowAllBoxes()) 1393 queue->addRenderable(getWireBoundingBox()); 1394 } 1395 1396 //------------------------------------------------------------------------- 1397 void KdTree::Leaf::getGeometryList(GtpVisibility::GeometryVector *geometryList) 1398 { 1399 KdRenderableList::iterator it = mKdRenderables.begin(); 1400 KdRenderableList::iterator end = mKdRenderables.end(); 1401 while (it != end) 1402 { 1403 (*it)->getGeometryList(geometryList); 1404 it++; 1405 } 1406 } 1407 1408 //------------------------------------------------------------------------- 1409 // update the world aabb based on the contained geometry 1410 void KdTree::Leaf::_updateBounds(bool recurse) 1411 { 1412 // reset box 1413 mWorldAABB.setNull(); 1414 1415 // merge boxes from attached geometry 1416 KdRenderableList::iterator it = mKdRenderables.begin(); 1417 KdRenderableList::iterator end = mKdRenderables.end(); 1418 while (it != end) 1419 { 1420 //(*it)->_updateBounds(); 1421 mWorldAABB.merge((*it)->getBoundingBox()); 1422 it++; 1423 } 1424 1425 // update parent recursively 1426 if (recurse && mParent) 1427 mParent->_updateBounds(recurse); 1428 } 1607 } 1608 else 1609 { 1610 KdTree::Branch * branch = KDBRANCHPTR_CAST(node); 1611 if (branch->mLeft) 1612 { 1613 mBuildLog->logMessage(pad + "# Branch level " + 1614 StringConverter::toString(node->getLevel()) + " Left Child"); 1615 dump(branch->mLeft); 1616 } 1617 if (branch->mRight) 1618 { 1619 mBuildLog->logMessage(pad + "# Branch level " + 1620 StringConverter::toString(node->getLevel()) + " Right Child"); 1621 dump(branch->mRight); 1622 } 1623 } 1624 } 1625 1626 //------------------------------------------------------------------------- 1627 Real KdTree::calcCost() 1628 { 1629 if (mKdRoot) 1630 return calcCost(mKdRoot, PlaneEvent::surfaceArea(mKdRoot->mAABB)); 1631 else 1632 return 0; 1633 } 1634 1635 //------------------------------------------------------------------------- 1636 Real KdTree::calcCost(KdTree::Node * node, Real vs) 1637 { 1638 if (node == 0) 1639 return 0.0; 1640 1641 if (node->isLeaf()) 1642 { 1643 KdTree::Leaf * leaf = KDLEAFPTR_CAST(node); 1644 return (PlaneEvent::surfaceArea(node->mAABB)/vs) * 1645 PlaneEvent::KI * leaf->mKdRenderables.size(); 1646 } 1647 else 1648 { 1649 KdTree::Branch * branch = KDBRANCHPTR_CAST(node); 1650 return (PlaneEvent::surfaceArea(node->mAABB)/vs) * PlaneEvent::KT + 1651 calcCost(branch->mLeft, vs) + calcCost(branch->mRight, vs); 1652 } 1653 } 1654 1655 /************************************************************************/ 1656 /* KdTree::Node/Branch/Leaf functions */ 1657 /************************************************************************/ 1658 1659 //------------------------------------------------------------------------- 1660 KdTree::Leaf::~Leaf() 1661 { 1662 // detach all scene nodes in the case that we are rebuilding 1663 // the tree but not the scene 1664 KdRenderableList::iterator it = mKdRenderables.begin(); 1665 KdRenderableList::iterator end = mKdRenderables.end(); 1666 while (it != end) 1667 { 1668 (*it)->detachFrom(this); 1669 it++; 1670 } 1671 mKdRenderables.clear(); 1672 } 1673 1674 //------------------------------------------------------------------------- 1675 void KdTree::Leaf::queueVisibleObjects(unsigned long currentFrame, 1676 Camera* cam, RenderQueue* queue, bool onlyShadowCasters, bool showBoxes, bool fullVis) 1677 { 1678 KdRenderableList::iterator it = mKdRenderables.begin(); 1679 KdRenderableList::iterator end = mKdRenderables.end(); 1680 while (it != end) 1681 { 1682 if (!(*it)->isQueued(currentFrame, cam)) 1683 { 1684 (*it)->queueObjects(cam, queue, onlyShadowCasters); 1685 } 1686 it++; 1687 } 1688 1689 if (showBoxes) 1690 if (mLevel == mOwner->getHiLiteLevel() || mOwner->getShowAllBoxes()) 1691 queue->addRenderable(getWireBoundingBox()); 1692 } 1693 1694 //------------------------------------------------------------------------- 1695 void KdTree::Leaf::getGeometryList(GtpVisibility::GeometryVector *geometryList) 1696 { 1697 KdRenderableList::iterator it = mKdRenderables.begin(); 1698 KdRenderableList::iterator end = mKdRenderables.end(); 1699 while (it != end) 1700 { 1701 (*it)->getGeometryList(geometryList); 1702 it++; 1703 } 1704 } 1705 1706 //------------------------------------------------------------------------- 1707 // update the world aabb based on the contained geometry 1708 void KdTree::Leaf::_updateBounds(bool recurse) 1709 { 1710 // reset box 1711 mWorldAABB.setNull(); 1712 1713 // merge boxes from attached geometry 1714 KdRenderableList::iterator it = mKdRenderables.begin(); 1715 KdRenderableList::iterator end = mKdRenderables.end(); 1716 while (it != end) 1717 { 1718 //(*it)->_updateBounds(); 1719 mWorldAABB.merge((*it)->getBoundingBox()); 1720 it++; 1721 } 1722 1723 // update parent recursively 1724 if (recurse && mParent) 1725 mParent->_updateBounds(recurse); 1726 } 1727 1429 1728 } // namespace Ogre -
GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreKdTreeSceneManager.cpp
r1285 r1296 18 18 #include "OgreKdTree.h" 19 19 20 #include <OgreMeshInstance.h> 21 #include <OgreBoundingBoxConverter.h> 22 #include <OgreTypeConverter.h> 20 23 #include <VisibilityEnvironment.h> 21 24 #include "OgreVisibilityOptionsManager.h" … … 51 54 mExecuteVertexProgramForAllPasses(false), 52 55 mIsHierarchicalCulling(false), 53 mDeleteQueueAfterRendering(true) 56 mDeleteQueueAfterRendering(true), 57 mViewCellsLoaded(false), 58 mUseViewCells(false), 59 mUseVisibilityFilter(false), 60 mViewCellsManager(0), 61 mElementaryViewCell(0), 62 mCurrentViewCell(0) 54 63 { 55 64 // Replace root node with my node … … 71 80 { 72 81 // DEBUG 73 if (mKdTree)74 mKdTree->dump();82 //if (mKdTree) 83 // mKdTree->dump(); 75 84 76 85 // must happen before actual scene is cleared … … 207 216 return false; 208 217 } 209 //String rm = *static_cast<const String *>(pValue);210 //if (rm == "INT")211 //{212 // mRenderMethod = KdTree::KDRM_INTERNAL;213 // return true;214 //}215 //else if (rm == "VFC")216 //{217 // mRenderMethod = KdTree::KDRM_GTP_VFC;218 // int cmt = GtpVisibility::VisibilityEnvironment::FRUSTUM_CULLING;219 // return VisibilityOptionsManager(mVisibilityManager, mHierarchyInterface)220 // .setOption("Algorithm", &cmt);221 //}222 //else if (rm == "SWC")223 //{224 // mRenderMethod = KdTree::KDRM_GTP_SWC;225 // int cmt = GtpVisibility::VisibilityEnvironment::STOP_AND_WAIT_CULLING;226 // return VisibilityOptionsManager(mVisibilityManager, mHierarchyInterface)227 // .setOption("Algorithm", &cmt);228 //}229 //else if (rm == "CHC")230 //{231 // mRenderMethod = KdTree::KDRM_GTP_CHC;232 // int cmt = GtpVisibility::VisibilityEnvironment::COHERENT_HIERARCHICAL_CULLING;233 // return VisibilityOptionsManager(mVisibilityManager, mHierarchyInterface)234 // .setOption("Algorithm", &cmt);235 //}236 //else237 //{238 // return false;239 //}240 218 } 241 219 // little hack in case someone uses "Algorithm" option from VisOptMan directly … … 368 346 return true; 369 347 } 370 348 else if (strKey == "DeleteRenderQueue") 349 { 350 mDeleteQueueAfterRendering = (*static_cast<const bool *>(pValue)); 351 return true; 352 } 353 // options for viewcells 354 else if (strKey == "LoadViewCells") 355 { 356 if (!mViewCellsLoaded) 357 { 358 String filename(static_cast<const char *>(pValue)); 359 mViewCellsLoaded = LoadViewCells(filename); 360 } 361 362 return mViewCellsLoaded; 363 } 364 else if (strKey == "UseViewCells") 365 { 366 if (mViewCellsLoaded) 367 { 368 mUseViewCells = *static_cast<const bool *>(pValue); 369 370 // reset view cell 371 OGRE_DELETE(mCurrentViewCell); 372 373 if (mUseViewCells) 374 mCurrentViewCell = mViewCellsManager->GenerateViewCell(); 375 376 mElementaryViewCell = NULL; 377 378 // if using view cells, all objects are set to false initially 379 SetObjectsVisible(!mUseViewCells); 380 381 return true; 382 } 383 else 384 { 385 return false; 386 } 387 388 } 389 else if (strKey == "UseVisibilityFilter") 390 { 391 if (mViewCellsLoaded) 392 { 393 mUseVisibilityFilter = *static_cast<const bool *>(pValue); 394 // set null =>recomputation of the pvs 395 mElementaryViewCell = NULL; 396 return true; 397 } 398 else 399 { 400 return false; 401 } 402 } 371 403 372 404 return VisibilityOptionsManager(mVisibilityManager, mHierarchyInterface) … … 401 433 else if (strKey == "BuildMethod") 402 434 { 403 //if (mBuildMethod == KdTree::KDBM_PRIORITYQUEUE)404 //{405 // *static_cast<String *>(pDestValue) = "PriorityQueue";406 //}407 //else if (mBuildMethod == KdTree::KDBM_RECURSIVE)408 //{409 // *static_cast<String *>(pDestValue) = "Recursive";410 //}411 435 *static_cast<KdTree::BuildMethod *>(pDestValue) = mBuildMethod; 412 436 return true; … … 414 438 else if (strKey == "RenderMethod") 415 439 { 416 //if (mRenderMethod == KdTree::KDRM_INTERNAL)417 //{418 // *static_cast<String *>(pDestValue) = "INT";419 //}420 //else if (mRenderMethod == KdTree::KDRM_GTP_VFC)421 //{422 // *static_cast<String *>(pDestValue) = "VFC";423 //}424 //else if (mRenderMethod == KdTree::KDRM_GTP_SWC)425 //{426 // *static_cast<String *>(pDestValue) = "SWC";427 //}428 //else if (mRenderMethod == KdTree::KDRM_GTP_CHC)429 //{430 // *static_cast<String *>(pDestValue) = "CHC";431 //}432 //else433 //{434 // return false;435 //}436 440 *static_cast<KdTree::RenderMethod *>(pDestValue) = mRenderMethod; 437 441 return true; … … 457 461 return true; 458 462 } 463 // vis options 464 else if (strKey == "NumHierarchyNodes") 465 { 466 unsigned int numnodes = 0; 467 if (mKdTree) 468 numnodes = mKdTree->getStats().mNumNodes; 469 470 * static_cast<unsigned int *>(pDestValue) = (unsigned int)numnodes; 471 return true; 472 } 473 else if (strKey == "VisibilityManager") 474 { 475 * static_cast<GtpVisibility::VisibilityManager **>(pDestValue) = 476 (GtpVisibility::VisibilityManager *)mVisibilityManager; 477 return true; 478 } 479 else if (strKey == "HierarchInterface") 480 { 481 * static_cast<GtpVisibility::HierarchyInterface **>(pDestValue) = 482 (GtpVisibility::HierarchyInterface *)mHierarchyInterface; 483 return true; 484 } 485 // view cell options 486 487 else if (strKey == "UseViewCells") 488 { 489 *static_cast<bool *>(pDestValue) = mUseViewCells; 490 return mViewCellsLoaded; 491 } 492 else if (strKey == "UseVisibilityFilter") 493 { 494 *static_cast<bool *>(pDestValue) = mUseVisibilityFilter; 495 return mViewCellsLoaded; 496 } 459 497 460 498 return VisibilityOptionsManager(mVisibilityManager, mHierarchyInterface) … … 464 502 bool KdTreeSceneManager::getOptionKeys(StringVector &refKeys) 465 503 { 504 refKeys.push_back("Algorithm"); 466 505 refKeys.push_back("BuildMethod"); 506 refKeys.push_back("DelayRenderTransparents"); 507 refKeys.push_back("DeleteRenderQueue"); 508 refKeys.push_back("DepthWrite"); 509 refKeys.push_back("EnhancedVisibility"); 510 refKeys.push_back("ExecuteVertexProgramForAllPasses"); 511 refKeys.push_back("HiLiteLevel"); 512 refKeys.push_back("HierarchInterface"); 467 513 refKeys.push_back("KI"); 468 514 refKeys.push_back("KT"); 469 515 refKeys.push_back("KdTreeMaxDepth"); 516 refKeys.push_back("LoadViewCells"); 517 refKeys.push_back("NumHierarchyNodes"); 518 refKeys.push_back("PrepareVisualization"); 470 519 refKeys.push_back("RebuildKdTree"); 471 520 refKeys.push_back("RenderMethod"); 521 refKeys.push_back("RenderNodesContentForViz"); 522 refKeys.push_back("RenderNodesForViz"); 523 refKeys.push_back("RenderTransparentsForItemBuffer"); 524 refKeys.push_back("ShowAllBoxes"); 472 525 refKeys.push_back("ShowKdTree"); 473 526 refKeys.push_back("ShowNodes"); 474 refKeys.push_back("HiLiteLevel"); 475 refKeys.push_back("ShowAllBoxes"); 527 refKeys.push_back("SkyBoxEnabled"); 528 refKeys.push_back("SkyDomeEnabled"); 529 refKeys.push_back("SkyPlaneEnabled"); 530 refKeys.push_back("UseDepthPass"); 531 refKeys.push_back("UseItemBuffer"); 532 refKeys.push_back("UseViewCells"); 533 refKeys.push_back("UseVisibilityFilter"); 534 refKeys.push_back("VisibilityManager"); 535 refKeys.push_back("VisualizeCulledNodes"); 476 536 return VisibilityOptionsManager(mVisibilityManager, mHierarchyInterface) 477 537 .getOptionKeys(refKeys); … … 652 712 653 713 654 //-- apply view cell pvs - TODO655 //updatePvs(cam);714 //-- apply view cell pvs - 715 updatePvs(cam); 656 716 } 657 717 mVisibleNodes.clear(); … … 803 863 804 864 _renderQueueGroupObjects(currentGroup, QueuedRenderableCollection::OM_PASS_GROUP); 865 } 866 867 //----------------------------------------------------------------------- 868 const Pass *KdTreeSceneManager::_setPass(const Pass* pass, bool evenIfSuppressed) 869 { 870 if (mRenderMethod == KdTree::KDRM_INTERNAL) 871 { 872 return SceneManager::_setPass(pass); 873 } 874 875 // TODO: setting vertex program is not efficient 876 //Pass *usedPass = ((mIsDepthPassPhase && !pass->hasVertexProgram()) ? mDepthPass : pass); 877 878 // set depth fill pass if we currently do not make an aabb occlusion query 879 const bool useDepthPass = 880 (mIsDepthPassPhase && !mHierarchyInterface->IsBoundingBoxQuery()); 881 882 const IlluminationRenderStage savedStage = mIlluminationStage; 883 884 // set illumination stage to NONE so no shadow material is used 885 // for depth pass or for occlusion query 886 if (mIsDepthPassPhase || mHierarchyInterface->IsBoundingBoxQuery()) 887 { 888 mIlluminationStage = IRS_NONE; 889 } 890 891 // --- set vertex program of current pass in order to set correct depth 892 if (mExecuteVertexProgramForAllPasses && 893 mIsDepthPassPhase && 894 pass->hasVertexProgram()) 895 { 896 // add vertex program of current pass to depth pass 897 mDepthPass->setVertexProgram(pass->getVertexProgramName()); 898 899 if (mDepthPass->hasVertexProgram()) 900 { 901 const GpuProgramPtr& prg = mDepthPass->getVertexProgram(); 902 // Load this program if not done already 903 if (!prg->isLoaded()) 904 prg->load(); 905 // Copy params 906 mDepthPass->setVertexProgramParameters(pass->getVertexProgramParameters()); 907 } 908 } 909 else if (mDepthPass->hasVertexProgram()) // reset vertex program 910 { 911 mDepthPass->setVertexProgram(""); 912 } 913 914 const Pass *usedPass = useDepthPass ? mDepthPass : pass; 915 916 // save old depth write: needed for item buffer 917 const bool IsDepthWrite = usedPass->getDepthWriteEnabled(); 918 919 // global option which enables / disables depth writes 920 if (!mEnableDepthWrite) 921 { 922 // usedPass->setDepthWriteEnabled(false); 923 } 924 //else if (mIsItemBufferPass) {usedPass = mItemBufferPass;} 925 926 927 //-- set actual pass here 928 const Pass *result = SceneManager::_setPass(usedPass); 929 930 931 // reset depth write 932 if (!mEnableDepthWrite) 933 { 934 // usedPass->setDepthWriteEnabled(IsDepthWrite); 935 } 936 937 // reset illumination stage 938 mIlluminationStage = savedStage; 939 940 return result; 805 941 } 806 942 //----------------------------------------------------------------------- … … 1096 1232 1097 1233 } 1234 1235 //------------------------------------------------------------------------- 1236 void KdTreeSceneManager::SetObjectsVisible(const bool visible) 1237 { 1238 GtpVisibilityPreprocessor::ObjectContainer::iterator it, it_end = mObjects.end(); 1239 1240 for (it = mObjects.begin(); it != it_end; ++ it) 1241 { 1242 OgreMeshInstance *omi = static_cast<OgreMeshInstance *>(*it); 1243 Entity *ent = omi->GetMesh(); 1244 1245 ent->setVisible(visible); 1246 } 1247 } 1248 //----------------------------------------------------------------------- 1249 bool KdTreeSceneManager::LoadViewCells(const String &filename) 1250 { 1251 // objects are set to invisible initially 1252 SetObjectsVisible(false); 1253 1254 const string bboxesFilename = mVisibilityManager->GetVisibilityEnvironment()->getViewCellsFileName(); 1255 1256 // converter between view cell ids and Ogre entites 1257 GtpVisibilityPreprocessor::IndexedBoundingBoxContainer iboxes; 1258 OgreBoundingBoxConverter bconverter(this); 1259 1260 // load the view cells assigning the found objects to the pvss 1261 mViewCellsManager = 1262 GtpVisibilityPreprocessor::ViewCellsManager::LoadViewCells(filename, &mObjects, false, &bconverter); 1263 1264 return (mViewCellsManager != NULL); 1265 } 1266 //------------------------------------------------------------------------- 1267 void KdTreeSceneManager::applyViewCellPvs(GtpVisibilityPreprocessor::ViewCell *vc, 1268 const bool load) 1269 { // NOTE: should not happen, rather apply view cell representing unbounded space then 1270 if (!vc) 1271 { 1272 // set everything visible for savety 1273 SetObjectsVisible(true); 1274 1275 return; 1276 } 1277 1278 GtpVisibilityPreprocessor::ObjectPvsMap::const_iterator oit, 1279 oit_end = vc->GetPvs().mEntries.end(); 1280 1281 //-- PVS of view cell 1282 for (oit = vc->GetPvs().mEntries.begin(); oit != oit_end; ++ oit) 1283 { 1284 if (!(*oit).first) continue; 1285 1286 OgreMeshInstance *omi = dynamic_cast<OgreMeshInstance *>((*oit).first); 1287 omi->GetMesh()->setVisible(load); 1288 //GtpVisibilityPreprocessor::Debug << "assigned id " << omi->GetId() << endl; 1289 } 1290 } 1291 //------------------------------------------------------------------------- 1292 void KdTreeSceneManager::updatePvs(Camera *cam) 1293 { 1294 if (!(mViewCellsLoaded && mUseViewCells)) 1295 return; 1296 1297 const GtpVisibilityPreprocessor::Vector3 viewPoint = 1298 OgreTypeConverter::ConvertFromOgre(cam->getDerivedPosition()); 1299 1300 GtpVisibilityPreprocessor::ViewCell *newElementary = 1301 mViewCellsManager->GetViewCell(viewPoint); 1302 1303 // elementary view cell did not change => apply same pvs 1304 if (mElementaryViewCell == newElementary) 1305 return; 1306 1307 mElementaryViewCell = newElementary; 1308 //LogManager::getSingleton().logMessage("unloading"); 1309 //-- unload old pvs 1310 applyViewCellPvs(mCurrentViewCell, false); 1311 1312 1313 //-- the new view cell 1314 1315 GtpVisibilityPreprocessor::ViewCell *viewCell; 1316 1317 1318 if (mUseVisibilityFilter) 1319 { 1320 //-- compute new filtered cell 1321 GtpVisibilityPreprocessor::PrVs prvs; 1322 mViewCellsManager->GetPrVS(viewPoint, prvs, 5); 1323 viewCell = prvs.mViewCell; 1324 } 1325 else 1326 { 1327 viewCell = newElementary; 1328 } 1329 //LogManager::getSingleton().logMessage("loading"); 1330 //-- load new pvs 1331 applyViewCellPvs(viewCell, true); 1332 1333 // store pvs 1334 mCurrentViewCell->SetPvs(viewCell->GetPvs()); 1335 1336 // delete merge tree of filtered view cell 1337 if (mUseVisibilityFilter) 1338 mViewCellsManager->DeleteLocalMergeTree(viewCell); 1339 } 1340 1098 1341 //----------------------------------------------------------------------- 1099 1342 void KdTreeSceneManager::WriteLog() … … 1105 1348 << "Use optimization: " << StringConverter::toString(mHierarchyInterface->GetTestGeometryForVisibleLeaves()) << ", " 1106 1349 << "Algorithm type: " << mVisibilityManager->GetCullingManagerType() << ", " 1107 // << "Hierarchy nodes: " << mNumOctants<< ", "1350 << "Hierarchy nodes: " << (mKdTree ? mKdTree->getStats().mNumNodes : 0) << ", " 1108 1351 << "Traversed nodes: " << mHierarchyInterface->GetNumTraversedNodes() << ", " 1109 1352 << "Rendered nodes: " << mHierarchyInterface->GetNumRenderedNodes() << ", " … … 1111 1354 << "Frustum culled nodes: " << mVisibilityManager->GetCullingManager()->GetNumFrustumCulledNodes() << ", " 1112 1355 << "Queries issued: " << mVisibilityManager->GetCullingManager()->GetNumQueriesIssued() << ", " 1113 // << "Found objects: " << (int)mVisible.size() << "\n"1356 << "Found objects: " << (int)mVisibleNodes.size() << "\n" 1114 1357 ; 1115 1358 1116 1359 LogManager::getSingleton().logMessage(d.str()); 1117 1360 } 1118 //----------------------------------------------------------------------- 1119 const Pass *KdTreeSceneManager::_setPass(const Pass* pass, bool evenIfSuppressed) 1120 { 1121 if (mRenderMethod == KdTree::KDRM_INTERNAL) 1122 { 1123 return SceneManager::_setPass(pass); 1124 } 1125 1126 // TODO: setting vertex program is not efficient 1127 //Pass *usedPass = ((mIsDepthPassPhase && !pass->hasVertexProgram()) ? mDepthPass : pass); 1128 1129 // set depth fill pass if we currently do not make an aabb occlusion query 1130 const bool useDepthPass = 1131 (mIsDepthPassPhase && !mHierarchyInterface->IsBoundingBoxQuery()); 1132 1133 const IlluminationRenderStage savedStage = mIlluminationStage; 1134 1135 // set illumination stage to NONE so no shadow material is used 1136 // for depth pass or for occlusion query 1137 if (mIsDepthPassPhase || mHierarchyInterface->IsBoundingBoxQuery()) 1138 { 1139 mIlluminationStage = IRS_NONE; 1140 } 1141 1142 // --- set vertex program of current pass in order to set correct depth 1143 if (mExecuteVertexProgramForAllPasses && 1144 mIsDepthPassPhase && 1145 pass->hasVertexProgram()) 1146 { 1147 // add vertex program of current pass to depth pass 1148 mDepthPass->setVertexProgram(pass->getVertexProgramName()); 1149 1150 if (mDepthPass->hasVertexProgram()) 1151 { 1152 const GpuProgramPtr& prg = mDepthPass->getVertexProgram(); 1153 // Load this program if not done already 1154 if (!prg->isLoaded()) 1155 prg->load(); 1156 // Copy params 1157 mDepthPass->setVertexProgramParameters(pass->getVertexProgramParameters()); 1158 } 1159 } 1160 else if (mDepthPass->hasVertexProgram()) // reset vertex program 1161 { 1162 mDepthPass->setVertexProgram(""); 1163 } 1164 1165 const Pass *usedPass = useDepthPass ? mDepthPass : pass; 1166 1167 // save old depth write: needed for item buffer 1168 const bool IsDepthWrite = usedPass->getDepthWriteEnabled(); 1169 1170 // global option which enables / disables depth writes 1171 if (!mEnableDepthWrite) 1172 { 1173 // usedPass->setDepthWriteEnabled(false); 1174 } 1175 //else if (mIsItemBufferPass) {usedPass = mItemBufferPass;} 1176 1177 1178 //-- set actual pass here 1179 const Pass *result = SceneManager::_setPass(usedPass); 1180 1181 1182 // reset depth write 1183 if (!mEnableDepthWrite) 1184 { 1185 // usedPass->setDepthWriteEnabled(IsDepthWrite); 1186 } 1187 1188 // reset illumination stage 1189 mIlluminationStage = savedStage; 1190 1191 return result; 1192 } 1193 1361 1362 /************************************************************************/ 1363 /* Factory for KdTreeSceneManager */ 1364 /************************************************************************/ 1194 1365 //----------------------------------------------------------------------- 1195 1366 //----------------------------------------------------------------------- -
GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/OgreOcclusionCullingSceneManager.cpp
r1276 r1296 540 540 return true; 541 541 } 542 else if (key == "DeleteRenderQueue") 543 { 544 mDeleteQueueAfterRendering = (*static_cast<const bool *>(val)); 545 return true; 546 } 542 547 if (key == "NodeVizScale") 543 548 { -
GTP/trunk/Lib/Vis/OnlineCullingCHC/OGRE/src/Plugin_VisibilitySceneManager.vcproj
r1288 r1296 112 112 AdditionalLibraryDirectories=""$(OGRE_PATH)\PlugIns\OctreeSceneManager\bin\$(ConfigurationName)";"$(OGRE_PATH)\OgreMain\lib\$(ConfigurationName)";"$(OGRE_PATH)\Samples\Common\CEGUIRenderer\lib";"$(OGRE_PATH)\Dependencies\lib\$(ConfigurationName)";"..\..\..\Preprocessing\lib\$(ConfigurationName)";..\..\..\..\..\..\..\NonGTP\Xerces\xercesc\lib;..\..\..\Preprocessing\src\GL;..\..\..\..\..\..\..\NonGTP\Zlib\lib;"..\..\lib\$(ConfigurationName)"" 113 113 ModuleDefinitionFile="..\misc\OgreVisibilitySceneManager.def" 114 GenerateDebugInformation=" FALSE"114 GenerateDebugInformation="TRUE" 115 115 SubSystem="2" 116 116 OptimizeReferences="2"
Note: See TracChangeset
for help on using the changeset viewer.