Changeset 1006 for GTP/trunk/Lib/Vis/Preprocessing/src/VspOspTree.cpp
- Timestamp:
- 06/09/06 01:26:46 (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
GTP/trunk/Lib/Vis/Preprocessing/src/VspOspTree.cpp
r1002 r1006 4 4 5 5 #include "Plane3.h" 6 #include "Vsp BspTree.h"6 #include "VspOspTree.h" 7 7 #include "Mesh.h" 8 8 #include "common.h" … … 25 25 //-- static members 26 26 27 28 int VspBspTree::sFrontId = 0; 29 int VspBspTree::sBackId = 0; 30 int VspBspTree::sFrontAndBackId = 0; 31 32 typedef pair<BspNode *, BspNodeGeometry *> bspNodePair; 27 int VspOspTree::sFrontId = 0; 28 int VspOspTree::sBackId = 0; 29 int VspOspTree::sFrontAndBackId = 0; 30 33 31 34 32 … … 51 49 52 50 /******************************************************************************/ 53 /* class Vsp BspTree implementation */51 /* class VspOspTree implementation */ 54 52 /******************************************************************************/ 55 53 56 54 57 Vsp BspTree::VspBspTree(Environment *env):55 VspOspTree::VspOspTree(): 58 56 mRoot(NULL), 59 mUseAreaForPvs(false),60 mCostNormalizer(Limits::Small),61 mViewCellsManager(NULL),62 57 mOutOfBoundsCell(NULL), 63 58 mStoreRays(false), 64 mRenderCostWeight(0.5),65 59 mUseRandomAxis(false), 66 60 mTimeStamp(1) 67 61 { 68 62 bool randomize = false; 69 env->GetBoolValue("VspBspTree.Construction.randomize", randomize);63 Environment::GetSingleton()->GetBoolValue("VspOspTree.Construction.randomize", randomize); 70 64 if (randomize) 71 65 Randomize(); // initialise random generator for heuristics 72 66 73 67 //-- termination criteria for autopartition 74 env->GetIntValue("VspBspTree.Termination.maxDepth", mTermMaxDepth); 75 env->GetIntValue("VspBspTree.Termination.minPvs", mTermMinPvs); 76 env->GetIntValue("VspBspTree.Termination.minRays", mTermMinRays); 77 env->GetFloatValue("VspBspTree.Termination.minProbability", mTermMinProbability); 78 env->GetFloatValue("VspBspTree.Termination.maxRayContribution", mTermMaxRayContribution); 79 env->GetFloatValue("VspBspTree.Termination.minAccRayLenght", mTermMinAccRayLength); 80 env->GetFloatValue("VspBspTree.Termination.maxCostRatio", mTermMaxCostRatio); 81 env->GetIntValue("VspBspTree.Termination.missTolerance", mTermMissTolerance); 82 env->GetIntValue("VspBspTree.Termination.maxViewCells", mMaxViewCells); 68 Environment::GetSingleton()->GetIntValue("VspOspTree.Termination.maxDepth", mTermMaxDepth); 69 Environment::GetSingleton()->GetIntValue("VspOspTree.Termination.minPvs", mTermMinPvs); 70 Environment::GetSingleton()->GetIntValue("VspOspTree.Termination.minRays", mTermMinRays); 71 Environment::GetSingleton()->GetFloatValue("VspOspTree.Termination.minProbability", mTermMinProbability); 72 Environment::GetSingleton()->GetFloatValue("VspOspTree.Termination.maxRayContribution", mTermMaxRayContribution); 73 Environment::GetSingleton()->GetFloatValue("VspOspTree.Termination.maxCostRatio", mTermMaxCostRatio); 74 Environment::GetSingleton()->GetIntValue("VspOspTree.Termination.missTolerance", mTermMissTolerance); 75 Environment::GetSingleton()->GetIntValue("VspOspTree.Termination.maxViewCells", mMaxViewCells); 83 76 84 77 //-- max cost ratio for early tree termination 85 env->GetFloatValue("VspBspTree.Termination.maxCostRatio", mTermMaxCostRatio);86 87 env->GetFloatValue("VspBspTree.Termination.minGlobalCostRatio", mTermMinGlobalCostRatio);88 env->GetIntValue("VspBspTree.Termination.globalCostMissTolerance", mTermGlobalCostMissTolerance);78 Environment::GetSingleton()->GetFloatValue("VspOspTree.Termination.maxCostRatio", mTermMaxCostRatio); 79 80 Environment::GetSingleton()->GetFloatValue("VspOspTree.Termination.minGlobalCostRatio", mTermMinGlobalCostRatio); 81 Environment::GetSingleton()->GetIntValue("VspOspTree.Termination.globalCostMissTolerance", mTermGlobalCostMissTolerance); 89 82 90 83 // HACK//mTermMinPolygons = 25; 91 84 92 85 //-- factors for bsp tree split plane heuristics 93 env->GetFloatValue("VspBspTree.Factor.pvs", mPvsFactor); 94 env->GetFloatValue("VspBspTree.Termination.ct_div_ci", mCtDivCi); 95 86 Environment::GetSingleton()->GetFloatValue("VspOspTree.Termination.ct_div_ci", mCtDivCi); 96 87 97 88 //-- partition criteria 98 env->GetIntValue("VspBspTree.maxPolyCandidates", mMaxPolyCandidates); 99 env->GetIntValue("VspBspTree.maxRayCandidates", mMaxRayCandidates); 100 env->GetIntValue("VspBspTree.splitPlaneStrategy", mSplitPlaneStrategy); 101 102 env->GetFloatValue("VspBspTree.Construction.epsilon", mEpsilon); 103 env->GetIntValue("VspBspTree.maxTests", mMaxTests); 89 Environment::GetSingleton()->GetFloatValue("VspOspTree.Construction.epsilon", mEpsilon); 104 90 105 91 // if only the driving axis is used for axis aligned split 106 env->GetBoolValue("VspBspTree.splitUseOnlyDrivingAxis", mOnlyDrivingAxis); 107 108 //-- termination criteria for axis aligned split 109 env->GetFloatValue("VspBspTree.Termination.AxisAligned.maxRayContribution", 110 mTermMaxRayContriForAxisAligned); 111 env->GetIntValue("VspBspTree.Termination.AxisAligned.minRays", 112 mTermMinRaysForAxisAligned); 113 114 //env->GetFloatValue("VspBspTree.maxTotalMemory", mMaxTotalMemory); 115 env->GetFloatValue("VspBspTree.maxStaticMemory", mMaxMemory); 116 117 env->GetFloatValue("VspBspTree.Construction.renderCostWeight", mRenderCostWeight); 118 env->GetBoolValue("VspBspTree.usePolygonSplitIfAvailable", mUsePolygonSplitIfAvailable); 119 120 env->GetBoolValue("VspBspTree.useCostHeuristics", mUseCostHeuristics); 121 env->GetBoolValue("VspBspTree.useSplitCostQueue", mUseSplitCostQueue); 122 env->GetBoolValue("VspBspTree.simulateOctree", mCirculatingAxis); 123 env->GetBoolValue("VspBspTree.useRandomAxis", mUseRandomAxis); 124 env->GetIntValue("VspBspTree.nodePriorityQueueType", mNodePriorityQueueType); 125 126 env->GetBoolValue("ViewCells.PostProcess.emptyViewCellsMerge", mEmptyViewCellsMergeAllowed); 92 Environment::GetSingleton()->GetBoolValue("VspOspTree.splitUseOnlyDrivingAxis", mOnlyDrivingAxis); 93 94 //Environment::GetSingleton()->GetFloatValue("VspOspTree.maxTotalMemory", mMaxTotalMemory); 95 Environment::GetSingleton()->GetFloatValue("VspOspTree.maxStaticMemory", mMaxMemory); 96 97 Environment::GetSingleton()->GetBoolValue("VspOspTree.useCostHeuristics", mUseCostHeuristics); 98 Environment::GetSingleton()->GetBoolValue("VspOspTree.simulateOctree", mCirculatingAxis); 99 Environment::GetSingleton()->GetBoolValue("VspOspTree.useRandomAxis", mUseRandomAxis); 100 Environment::GetSingleton()->GetIntValue("VspOspTree.nodePriorityQueueType", mNodePriorityQueueType); 127 101 128 102 char subdivisionStatsLog[100]; 129 env->GetStringValue("VspBspTree.subdivisionStats", subdivisionStatsLog);103 Environment::GetSingleton()->GetStringValue("VspOspTree.subdivisionStats", subdivisionStatsLog); 130 104 mSubdivisionStats.open(subdivisionStatsLog); 131 105 132 env->GetFloatValue("VspBspTree.Construction.minBand", mMinBand);133 env->GetFloatValue("VspBspTree.Construction.maxBand", mMaxBand);134 env->GetBoolValue("VspBspTree.Construction.useDrivingAxisForMaxCost", mUseDrivingAxisForMaxCost);106 Environment::GetSingleton()->GetFloatValue("VspOspTree.Construction.minBand", mMinBand); 107 Environment::GetSingleton()->GetFloatValue("VspOspTree.Construction.maxBand", mMaxBand); 108 135 109 136 110 //-- debug output … … 145 119 Debug << "miss tolerance: " << mTermMissTolerance << endl; 146 120 Debug << "max view cells: " << mMaxViewCells << endl; 147 Debug << "max polygon candidates: " << mMaxPolyCandidates << endl;148 //Debug << "max plane candidates: " << mMaxRayCandidates << endl;149 121 Debug << "randomize: " << randomize << endl; 150 122 151 Debug << "using area for pvs: " << mUseAreaForPvs << endl;152 Debug << "render cost weight: " << mRenderCostWeight << endl;153 123 Debug << "min global cost ratio: " << mTermMinGlobalCostRatio << endl; 154 124 Debug << "global cost miss tolerance: " << mTermGlobalCostMissTolerance << endl; 155 125 Debug << "only driving axis: " << mOnlyDrivingAxis << endl; 156 126 Debug << "max memory: " << mMaxMemory << endl; 157 Debug << "use poly split if available: " << mUsePolygonSplitIfAvailable << endl;158 127 Debug << "use cost heuristics: " << mUseCostHeuristics << endl; 159 Debug << "use split cost queue: " << mUseSplitCostQueue << endl;160 128 Debug << "subdivision stats log: " << subdivisionStatsLog << endl; 161 129 Debug << "use random axis: " << mUseRandomAxis << endl; 162 130 Debug << "priority queue type: " << mNodePriorityQueueType << endl; 163 Debug << "empty view cells merge: " << mEmptyViewCellsMergeAllowed << endl;164 131 Debug << "circulating axis: " << mCirculatingAxis << endl; 165 132 Debug << "minband: " << mMinBand << endl; 166 133 Debug << "maxband: " << mMaxBand << endl; 167 Debug << "use driving axis for max cost: " << mUseDrivingAxisForMaxCost << endl; 168 169 Debug << "Split plane strategy: "; 170 171 if (mSplitPlaneStrategy & RANDOM_POLYGON) 172 { 173 Debug << "random polygon "; 174 } 175 if (mSplitPlaneStrategy & AXIS_ALIGNED) 176 { 177 Debug << "axis aligned "; 178 } 179 if (mSplitPlaneStrategy & LEAST_RAY_SPLITS) 180 { 181 mCostNormalizer += mLeastRaySplitsFactor; 182 Debug << "least ray splits "; 183 } 184 if (mSplitPlaneStrategy & BALANCED_RAYS) 185 { 186 mCostNormalizer += mBalancedRaysFactor; 187 Debug << "balanced rays "; 188 } 189 if (mSplitPlaneStrategy & PVS) 190 { 191 mCostNormalizer += mPvsFactor; 192 Debug << "pvs"; 193 } 194 134 195 135 196 136 mSplitCandidates = new vector<SortableEntry>; … … 199 139 } 200 140 201 VspBspTree::VspBspTree(): 202 mRoot(NULL), 203 mUseAreaForPvs(false), 204 mCostNormalizer(Limits::Small), 205 mViewCellsManager(NULL), 206 mOutOfBoundsCell(NULL), 207 mStoreRays(false), 208 mRenderCostWeight(0.5), 209 mUseRandomAxis(false), 210 mTimeStamp(1), 211 mEpsilon(1e-6f) 212 { 213 } 214 215 BspViewCell *VspBspTree::GetOutOfBoundsCell() 141 142 BspViewCell *VspOspTree::GetOutOfBoundsCell() 216 143 { 217 144 return mOutOfBoundsCell; … … 219 146 220 147 221 BspViewCell *Vsp BspTree::GetOrCreateOutOfBoundsCell()148 BspViewCell *VspOspTree::GetOrCreateOutOfBoundsCell() 222 149 { 223 150 if (!mOutOfBoundsCell) … … 232 159 233 160 234 const BspTreeStatistics &Vsp BspTree::GetStatistics() const161 const BspTreeStatistics &VspOspTree::GetStatistics() const 235 162 { 236 163 return mBspStats; … … 238 165 239 166 240 Vsp BspTree::~VspBspTree()167 VspOspTree::~VspOspTree() 241 168 { 242 169 DEL_PTR(mRoot); … … 244 171 } 245 172 246 247 int VspBspTree::AddMeshToPolygons(Mesh *mesh, 248 PolygonContainer &polys, 249 MeshInstance *parent) 250 { 251 FaceContainer::const_iterator fi; 252 253 // copy the face data to polygons 254 for (fi = mesh->mFaces.begin(); fi != mesh->mFaces.end(); ++ fi) 255 { 256 Polygon3 *poly = new Polygon3((*fi), mesh); 257 258 if (poly->Valid(mEpsilon)) 259 { 260 poly->mParent = parent; // set parent intersectable 261 polys.push_back(poly); 262 } 263 else 264 DEL_PTR(poly); 265 } 266 return (int)mesh->mFaces.size(); 267 } 268 269 270 int VspBspTree::AddToPolygonSoup(const ViewCellContainer &viewCells, 271 PolygonContainer &polys, 272 int maxObjects) 273 { 274 int limit = (maxObjects > 0) ? 275 Min((int)viewCells.size(), maxObjects) : (int)viewCells.size(); 276 277 int polysSize = 0; 278 279 for (int i = 0; i < limit; ++ i) 280 { 281 if (viewCells[i]->GetMesh()) // copy the mesh data to polygons 282 { 283 mBox.Include(viewCells[i]->GetBox()); // add to BSP tree aabb 284 polysSize += 285 AddMeshToPolygons(viewCells[i]->GetMesh(), 286 polys, 287 viewCells[i]); 288 } 289 } 290 291 return polysSize; 292 } 293 294 295 int VspBspTree::AddToPolygonSoup(const ObjectContainer &objects, 296 PolygonContainer &polys, 297 int maxObjects) 298 { 299 int limit = (maxObjects > 0) ? 300 Min((int)objects.size(), maxObjects) : (int)objects.size(); 301 302 for (int i = 0; i < limit; ++i) 303 { 304 Intersectable *object = objects[i];//*it; 305 Mesh *mesh = NULL; 306 307 switch (object->Type()) // extract the meshes 308 { 309 case Intersectable::MESH_INSTANCE: 310 mesh = dynamic_cast<MeshInstance *>(object)->GetMesh(); 311 break; 312 case Intersectable::VIEW_CELL: 313 mesh = dynamic_cast<ViewCell *>(object)->GetMesh(); 314 break; 315 case Intersectable::TRANSFORMED_MESH_INSTANCE: 316 { 317 TransformedMeshInstance *mi = dynamic_cast<TransformedMeshInstance *>(object); 318 319 if (!mi->GetMesh()) 320 break; 321 322 mesh = new Mesh(*mi->GetMesh()); 323 324 Matrix4x4 m; 325 mi->GetWorldTransform(m); 326 327 mesh->ApplyTransformation(m); 328 329 break; 330 } 331 default: 332 Debug << "intersectable type not supported" << endl; 333 break; 334 } 335 336 if (mesh) // copy the mesh data to polygons 337 { 338 mBox.Include(object->GetBox()); // add to BSP tree aabb 339 AddMeshToPolygons(mesh, polys, NULL); 340 341 // cleanup 342 if (object->Type() == Intersectable::TRANSFORMED_MESH_INSTANCE) 343 DEL_PTR(mesh); 344 } 345 } 346 347 return (int)polys.size(); 348 } 349 350 351 void VspBspTree::Construct(const VssRayContainer &sampleRays, 173 void VspOspTree::Construct(const VssRayContainer &sampleRays, 352 174 AxisAlignedBox3 *forcedBoundingBox) 353 175 { … … 371 193 int numObj = 0; 372 194 373 //-- extract polygons intersected by the rays374 for (rit = sampleRays.begin(); rit != rit_end; ++ rit)375 {376 VssRay *ray = *rit;377 378 if ((mBox.IsInside(ray->mTermination) || !forcedBoundingBox) &&379 ray->mTerminationObject &&380 !ray->mTerminationObject->Mailed())381 {382 ray->mTerminationObject->Mail();383 MeshInstance *obj = dynamic_cast<MeshInstance *>(ray->mTerminationObject);384 AddMeshToPolygons(obj->GetMesh(), polys, obj);385 ++ numObj;386 387 //-- compute bounding box388 if (!forcedBoundingBox)389 mBox.Include(ray->mTermination);390 }391 392 if ((mBox.IsInside(ray->mOrigin) || !forcedBoundingBox) &&393 ray->mOriginObject &&394 !ray->mOriginObject->Mailed())395 {396 ray->mOriginObject->Mail();397 MeshInstance *obj = dynamic_cast<MeshInstance *>(ray->mOriginObject);398 AddMeshToPolygons(obj->GetMesh(), polys, obj);399 ++ numObj;400 401 //-- compute bounding box402 if (!forcedBoundingBox)403 mBox.Include(ray->mOrigin);404 }405 }406 407 Debug << "maximal pvs (i.e., pvs still considered as valid) : "408 << mViewCellsManager->GetMaxPvsSize() << endl;409 410 195 //-- store rays 411 196 for (rit = sampleRays.begin(); rit != rit_end; ++ rit) … … 430 215 } 431 216 432 // normalize 433 if (mUseAreaForPvs) 434 mTermMinProbability *= mBox.SurfaceArea(); 435 else 436 mTermMinProbability *= mBox.GetVolume(); 437 438 // throw out unnecessary polygons 439 PreprocessPolygons(polys); 440 441 mBspStats.polys = (int)polys.size(); 217 mTermMinProbability *= mBox.GetVolume(); 218 442 219 mGlobalCostMisses = 0; 443 220 444 221 cout << "finished" << endl; 445 222 446 Debug << "\nPolygon extraction: " << (int)polys.size() << " polys extracted from "447 << (int)sampleRays.size() << " rays in "448 << TimeDiff(startTime, GetTime())*1e-3 << " secs" << endl << endl;449 450 223 // use split cost priority queue 451 if (mUseSplitCostQueue) 452 { 453 ConstructWithSplitQueue(polys, rays); 454 } 455 else 456 { 457 Construct(polys, rays); 458 } 459 460 // clean up polygons 461 CLEAR_CONTAINER(polys); 224 Construct(rays); 462 225 } 463 226 464 227 465 228 // TODO: return memory usage in MB 466 float Vsp BspTree::GetMemUsage() const229 float VspOspTree::GetMemUsage() const 467 230 { 468 231 return (float) 469 (sizeof(Vsp BspTree) +232 (sizeof(VspOspTree) + 470 233 mBspStats.Leaves() * sizeof(BspLeaf) + 471 234 mCreatedViewCells * sizeof(BspViewCell) + … … 476 239 477 240 478 479 void VspBspTree::Construct(const PolygonContainer &polys, RayInfoContainer *rays) 480 { 481 VspBspTraversalQueue tQueue; 241 void VspOspTree::Construct(RayInfoContainer *rays) 242 { 243 VspOspSplitQueue tQueue; 482 244 483 245 mRoot = new BspLeaf(); 484 246 485 // constrruct root node geometry 486 BspNodeGeometry *geom = new BspNodeGeometry(); 487 ConstructGeometry(mRoot, *geom); 488 489 const float prop = mUseAreaForPvs ? geom->GetArea() : geom->GetVolume(); 490 491 VspBspTraversalData tData(mRoot, 492 new PolygonContainer(polys), 247 const float prop = mBox.GetVolume(); 248 249 VspOspTraversalData tData(mRoot, 493 250 0, 494 251 rays, 495 252 ComputePvsSize(*rays), 496 253 prop, 497 geom); 498 499 EvalPriority(tData); 500 501 502 // first node is kd node, i.e. an axis aligned box 503 if (1) 504 tData.mIsKdNode = true; 505 else 506 tData.mIsKdNode = false; 507 508 tQueue.push(tData); 509 510 511 mTotalCost = tData.mPvs * tData.mProbability / mBox.GetVolume(); 512 mTotalPvsSize = tData.mPvs; 513 514 mSubdivisionStats 515 << "#ViewCells\n1" << endl 516 << "#RenderCostDecrease\n0" << endl 517 << "#TotalRenderCost\n" << mTotalCost << endl 518 << "#AvgRenderCost\n" << mTotalPvsSize << endl; 519 520 Debug << "total cost: " << mTotalCost << endl; 521 522 523 mBspStats.Start(); 524 cout << "Constructing vsp bsp tree ... \n"; 525 526 long startTime = GetTime(); 527 int nLeaves = 500; 528 int nViewCells = 500; 529 530 // used for intermediate time measurements and progress 531 long interTime = GetTime(); 532 533 mOutOfMemory = false; 534 535 mCreatedViewCells = 0; 536 537 while (!tQueue.empty()) 538 { 539 tData = tQueue.top(); 540 tQueue.pop(); 541 542 if (0 && !mOutOfMemory) 543 { 544 float mem = GetMemUsage(); 545 546 if (mem > mMaxMemory) 547 { 548 mOutOfMemory = true; 549 Debug << "memory limit reached: " << mem << endl; 550 } 551 } 552 553 // subdivide leaf node 554 BspNode *r = Subdivide(tQueue, tData); 555 556 if (r == mRoot) 557 Debug << "VSP BSP tree construction time spent at root: " 558 << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl; 559 560 if (mBspStats.Leaves() >= nLeaves) 561 { 562 nLeaves += 500; 563 564 cout << "leaves=" << mBspStats.Leaves() << endl; 565 Debug << "needed " 566 << TimeDiff(interTime, GetTime())*1e-3 567 << " secs to create 500 view cells" << endl; 568 interTime = GetTime(); 569 } 570 571 if (mCreatedViewCells >= nViewCells) 572 { 573 nViewCells += 500; 574 575 cout << "generated " << mCreatedViewCells << " viewcells" << endl; 576 } 577 } 578 579 Debug << "Used Memory: " << GetMemUsage() << " MB" << endl << endl; 580 cout << "finished\n"; 581 582 mBspStats.Stop(); 583 } 584 585 586 587 void VspBspTree::ConstructWithSplitQueue(const PolygonContainer &polys, 588 RayInfoContainer *rays) 589 { 590 VspBspSplitQueue tQueue; 591 592 mRoot = new BspLeaf(); 593 594 // constrruct root node geometry 595 BspNodeGeometry *geom = new BspNodeGeometry(); 596 ConstructGeometry(mRoot, *geom); 597 598 const float prop = mUseAreaForPvs ? geom->GetArea() : geom->GetVolume(); 599 600 VspBspTraversalData tData(mRoot, 601 new PolygonContainer(polys), 602 0, 603 rays, 604 ComputePvsSize(*rays), 605 prop, 606 geom); 254 mBox); 607 255 608 256 609 257 // compute first split candidate 610 Vsp BspSplitCandidate splitCandidate;258 VspOspSplitCandidate splitCandidate; 611 259 EvalSplitCandidate(tData, splitCandidate); 612 260 … … 697 345 698 346 699 bool Vsp BspTree::LocalTerminationCriteriaMet(const VspBspTraversalData &data) const347 bool VspOspTree::LocalTerminationCriteriaMet(const VspOspTraversalData &data) const 700 348 { 701 349 return … … 708 356 709 357 710 bool Vsp BspTree::GlobalTerminationCriteriaMet(const VspBspTraversalData &data) const358 bool VspOspTree::GlobalTerminationCriteriaMet(const VspOspTraversalData &data) const 711 359 { 712 360 return … … 718 366 719 367 720 721 BspNode *VspBspTree::Subdivide(VspBspTraversalQueue &tQueue,722 VspBspTraversalData &tData)723 {724 BspNode *newNode = tData.mNode;725 726 if (!LocalTerminationCriteriaMet(tData) && !GlobalTerminationCriteriaMet(tData))727 {728 PolygonContainer coincident;729 730 VspBspTraversalData tFrontData;731 VspBspTraversalData tBackData;732 733 // create new interior node and two leaf nodes734 // or return leaf as it is (if maxCostRatio missed)735 int splitAxis;736 bool splitFurther = true;737 int maxCostMisses = tData.mMaxCostMisses;738 739 Plane3 splitPlane;740 BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode);741 742 // choose next split plane743 if (!SelectPlane(splitPlane, leaf, tData, tFrontData, tBackData, splitAxis))744 {745 ++ maxCostMisses;746 747 if (maxCostMisses > mTermMissTolerance)748 {749 // terminate branch because of max cost750 ++ mBspStats.maxCostNodes;751 splitFurther = false;752 }753 }754 755 // if this a valid split => subdivide this node further756 if (splitFurther) //-- continue subdivision757 {758 newNode = SubdivideNode(splitPlane, tData, tFrontData, tBackData, coincident);759 760 if (splitAxis < 3)761 ++ mBspStats.splits[splitAxis];762 else763 ++ mBspStats.polySplits;764 765 // if it was a kd node (i.e., a box) and the split axis is axis aligned, it is still a kd node766 tFrontData.mIsKdNode = tBackData.mIsKdNode = (tData.mIsKdNode && (splitAxis < 3));767 tFrontData.mAxis = tBackData.mAxis = splitAxis;768 769 // how often was max cost ratio missed in this branch?770 tFrontData.mMaxCostMisses = maxCostMisses;771 tBackData.mMaxCostMisses = maxCostMisses;772 773 EvalPriority(tFrontData);774 EvalPriority(tBackData);775 776 // evaluate subdivision stats777 if (1)778 {779 float cFront = (float)tFrontData.mPvs * tFrontData.mProbability;780 float cBack = (float)tBackData.mPvs * tBackData.mProbability;781 float cData = (float)tData.mPvs * tData.mProbability;;782 783 float costDecr = (cFront + cBack - cData) / mBox.GetVolume();784 785 mTotalCost += costDecr;786 mTotalPvsSize += tFrontData.mPvs + tBackData.mPvs - tData.mPvs;787 788 mSubdivisionStats789 << "#ViewCells\n" << mBspStats.Leaves() << endl790 << "#RenderCostDecrease\n" << -costDecr << endl791 << "#TotalRenderCost\n" << mTotalCost << endl792 << "#AvgRenderCost\n" << (float)mTotalPvsSize / (float)mBspStats.Leaves() << endl;793 }794 795 // push the children on the stack796 tQueue.push(tFrontData);797 tQueue.push(tBackData);798 799 // delete old leaf node800 DEL_PTR(tData.mNode);801 }802 }803 804 //-- terminate traversal and create new view cell805 if (newNode->IsLeaf())806 {807 BspLeaf *leaf = dynamic_cast<BspLeaf *>(newNode);808 BspViewCell *viewCell = new BspViewCell();809 810 leaf->SetViewCell(viewCell);811 812 //-- update pvs813 int conSamp = 0;814 float sampCon = 0.0f;815 AddToPvs(leaf, *tData.mRays, sampCon, conSamp);816 817 // update scalar pvs size lookup818 mViewCellsManager->SetScalarPvsSize(viewCell, viewCell->GetPvs().GetSize());819 820 821 mBspStats.contributingSamples += conSamp;822 mBspStats.sampleContributions +=(int) sampCon;823 824 //-- store additional info825 if (mStoreRays)826 {827 RayInfoContainer::const_iterator it, it_end = tData.mRays->end();828 for (it = tData.mRays->begin(); it != it_end; ++ it)829 {830 (*it).mRay->Ref();831 leaf->mVssRays.push_back((*it).mRay);832 }833 }834 835 // should I check here?836 if (0 && !mViewCellsManager->CheckValidity(viewCell, 0, mViewCellsManager->GetMaxPvsSize()))837 {838 viewCell->SetValid(false);839 leaf->SetTreeValid(false);840 PropagateUpValidity(leaf);841 842 ++ mBspStats.invalidLeaves;843 }844 845 viewCell->mLeaf = leaf;846 847 if (mUseAreaForPvs)848 viewCell->SetArea(tData.mProbability);849 else850 viewCell->SetVolume(tData.mProbability);851 852 leaf->mProbability = tData.mProbability;853 854 EvaluateLeafStats(tData);855 }856 857 //-- cleanup858 tData.Clear();859 860 return newNode;861 }862 863 368 // subdivide using a split plane queue 864 BspNode *Vsp BspTree::Subdivide(VspBspSplitQueue &tQueue,865 Vsp BspSplitCandidate &splitCandidate)866 { 867 Vsp BspTraversalData &tData = splitCandidate.mParentData;369 BspNode *VspOspTree::Subdivide(VspOspSplitQueue &tQueue, 370 VspOspSplitCandidate &splitCandidate) 371 { 372 VspOspTraversalData &tData = splitCandidate.mParentData; 868 373 869 374 BspNode *newNode = tData.mNode; … … 871 376 if (!LocalTerminationCriteriaMet(tData) && !GlobalTerminationCriteriaMet(tData)) 872 377 { 873 PolygonContainer coincident; 874 875 VspBspTraversalData tFrontData; 876 VspBspTraversalData tBackData; 378 VspOspTraversalData tFrontData; 379 VspOspTraversalData tBackData; 877 380 878 381 //-- continue subdivision 879 382 880 383 // create new interior node and two leaf node 881 const Plane3 splitPlane = splitCandidate.mSplitPlane; 384 //TODO 385 const Plane3 splitPlane;// = splitCandidate.mSplitPlane; 882 386 883 newNode = SubdivideNode(splitPlane, tData, tFrontData, tBackData, coincident); 884 885 const int splitAxis = splitCandidate.mSplitAxis; 387 newNode = SubdivideNode(splitPlane, tData, tFrontData, tBackData); 388 886 389 const int maxCostMisses = splitCandidate.mMaxCostMisses; 887 390 888 if (splitAxis < 3)889 ++ mBspStats.splits[splitAxis];890 else891 ++ mBspStats.polySplits;892 893 tFrontData.mIsKdNode = tBackData.mIsKdNode = (tData.mIsKdNode && (splitAxis < 3));894 tFrontData.mAxis = tBackData.mAxis = splitAxis;895 391 896 392 // how often was max cost ratio missed in this branch? … … 922 418 923 419 //-- push the new split candidates on the stack 924 Vsp BspSplitCandidate frontCandidate;925 Vsp BspSplitCandidate backCandidate;420 VspOspSplitCandidate frontCandidate; 421 VspOspSplitCandidate backCandidate; 926 422 927 423 EvalSplitCandidate(tFrontData, frontCandidate); … … 969 465 viewCell->mLeaf = leaf; 970 466 971 if (mUseAreaForPvs) 972 viewCell->SetArea(tData.mProbability); 973 else 974 viewCell->SetVolume(tData.mProbability); 975 467 viewCell->SetVolume(tData.mProbability); 976 468 leaf->mProbability = tData.mProbability; 977 469 … … 986 478 987 479 988 void VspBspTree::EvalPriority(VspBspTraversalData &tData) const 989 { 990 switch (mNodePriorityQueueType) 991 { 992 case BREATH_FIRST: 993 tData.mPriority = (float)-tData.mDepth; 994 break; 995 case DEPTH_FIRST: 996 tData.mPriority = (float)tData.mDepth; 997 break; 998 default: 999 tData.mPriority = tData.mPvs * tData.mProbability; 1000 //Debug << "priority: " << tData.mPriority << endl; 1001 break; 1002 } 1003 } 1004 1005 1006 void VspBspTree::EvalSplitCandidate(VspBspTraversalData &tData, 1007 VspBspSplitCandidate &splitData) 1008 { 1009 VspBspTraversalData frontData; 1010 VspBspTraversalData backData; 480 void VspOspTree::EvalSplitCandidate(VspOspTraversalData &tData, 481 VspOspSplitCandidate &splitData) 482 { 483 VspOspTraversalData frontData; 484 VspOspTraversalData backData; 1011 485 1012 486 BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode); 1013 487 1014 488 // compute locally best split plane 1015 bool success = SelectPlane(splitData.mSplitPlane, leaf, tData, 1016 frontData, backData, splitData.mSplitAxis); 1017 1018 // TODO: reuse 1019 DEL_PTR(frontData.mGeometry); 1020 DEL_PTR(backData.mGeometry); 1021 489 // TODO 490 const bool success =0;/// SelectPlane(splitData.mSplitPlane, tData, 491 // frontData, backData); 492 //TODO 1022 493 // compute global decrease in render cost 1023 splitData.mRenderCost = EvalRenderCostDecrease(splitData.mSplitPlane, tData);494 splitData.mRenderCost = 0;//EvalRenderCostDecrease(splitData.mSplitPlane, tData); 1024 495 splitData.mParentData = tData; 1025 496 splitData.mMaxCostMisses = success ? tData.mMaxCostMisses : tData.mMaxCostMisses + 1; … … 1027 498 1028 499 1029 BspInterior *VspBspTree::SubdivideNode(const Plane3 &splitPlane, 1030 VspBspTraversalData &tData, 1031 VspBspTraversalData &frontData, 1032 VspBspTraversalData &backData, 1033 PolygonContainer &coincident) 500 BspInterior *VspOspTree::SubdivideNode(const Plane3 &splitPlane, 501 VspOspTraversalData &tData, 502 VspOspTraversalData &frontData, 503 VspOspTraversalData &backData) 1034 504 { 1035 505 BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode); … … 1037 507 //-- the front and back traversal data is filled with the new values 1038 508 frontData.mDepth = tData.mDepth + 1; 1039 frontData.mPolygons = new PolygonContainer();1040 509 frontData.mRays = new RayInfoContainer(); 1041 510 1042 511 backData.mDepth = tData.mDepth + 1; 1043 backData.mPolygons = new PolygonContainer();1044 512 backData.mRays = new RayInfoContainer(); 1045 513 … … 1059 527 1060 528 // if geometry was not already computed 1061 if (!frontData.mGeometry && !backData.mGeometry) 1062 { 1063 frontData.mGeometry = new BspNodeGeometry(); 1064 backData.mGeometry = new BspNodeGeometry(); 1065 1066 tData.mGeometry->SplitGeometry(*frontData.mGeometry, 1067 *backData.mGeometry, 1068 splitPlane, 1069 mBox, 1070 //0.0f); 1071 mEpsilon); 1072 1073 if (mUseAreaForPvs) 1074 { 1075 frontData.mProbability = frontData.mGeometry->GetArea(); 1076 backData.mProbability = backData.mGeometry->GetArea(); 1077 } 1078 else 1079 { 1080 frontData.mProbability = frontData.mGeometry->GetVolume(); 1081 backData.mProbability = tData.mProbability - frontData.mProbability; 1082 1083 // should never come here: wrong volume !!! 1084 if (0) 1085 { 1086 if (frontData.mProbability < -0.00001) 1087 Debug << "fatal error f: " << frontData.mProbability << endl; 1088 if (backData.mProbability < -0.00001) 1089 Debug << "fatal error b: " << backData.mProbability << endl; 1090 1091 // clamp because of precision issues 1092 if (frontData.mProbability < 0) frontData.mProbability = 0; 1093 if (backData.mProbability < 0) backData.mProbability = 0; 1094 } 1095 } 1096 } 1097 1098 1099 // subdivide polygons 1100 SplitPolygons(splitPlane, 1101 *tData.mPolygons, 1102 *frontData.mPolygons, 1103 *backData.mPolygons, 1104 coincident); 1105 1106 1107 1108 /////////////////////////////////////// 529 // TODO 530 531 #if TODO 532 tData.mBoundingBox.Split(splitPlane.mAxis, splitPlane.mPosition, 533 frontData.mBoundingBox, backData.mBoundingBox); 534 535 #endif 536 537 frontData.mProbability = frontData.mBoundingBox.GetVolume(); 538 backData.mProbability = tData.mProbability - frontData.mProbability; 539 540 541 /////////////////////////////////////////// 1109 542 // subdivide further 1110 543 … … 1149 582 interior->mTimeStamp = mTimeStamp ++; 1150 583 1151 1152 //DEL_PTR(leaf);1153 584 return interior; 1154 585 } 1155 586 1156 587 1157 void Vsp BspTree::AddToPvs(BspLeaf *leaf,588 void VspOspTree::AddToPvs(BspLeaf *leaf, 1158 589 const RayInfoContainer &rays, 1159 590 float &sampleContributions, … … 1200 631 1201 632 1202 void Vsp BspTree::SortSplitCandidates(const RayInfoContainer &rays,633 void VspOspTree::SortSplitCandidates(const RayInfoContainer &rays, 1203 634 const int axis, 1204 635 float minBand, … … 1251 682 1252 683 1253 float Vsp BspTree::BestCostRatioHeuristics(const RayInfoContainer &rays,684 float VspOspTree::BestCostRatioHeuristics(const RayInfoContainer &rays, 1254 685 const AxisAlignedBox3 &box, 1255 686 const int pvsSize, … … 1413 844 if (splitPlaneFound) 1414 845 { 1415 ratio = mPvsFactor *newRenderCost / (oldRenderCost + Limits::Small);846 ratio = newRenderCost / (oldRenderCost + Limits::Small); 1416 847 } 1417 848 //if (axis != 1) … … 1423 854 1424 855 1425 float VspBspTree::SelectAxisAlignedPlane(Plane3 &plane, 1426 const VspBspTraversalData &tData, 1427 int &axis, 1428 BspNodeGeometry **frontGeom, 1429 BspNodeGeometry **backGeom, 1430 float &pFront, 1431 float &pBack, 1432 const bool isKdNode) 856 float VspOspTree::SelectPlane(const VspOspTraversalData &tData, 857 AxisAlignedPlane &plane, 858 float &pFront, 859 float &pBack) 1433 860 { 1434 861 float nPosition[3]; … … 1437 864 float nProbBack[3]; 1438 865 1439 BspNodeGeometry *nFrontGeom[3];1440 BspNodeGeometry *nBackGeom[3];1441 1442 // set to NULL, so I can find out which gemetry was stored1443 for (int i = 0; i < 3; ++ i)1444 {1445 nFrontGeom[i] = NULL;1446 nBackGeom[i] = NULL;1447 }1448 1449 866 // create bounding box of node geometry 1450 AxisAlignedBox3 box; 1451 1452 //TODO: for kd split geometry already is box => only take minmax vertices 1453 if (1) 1454 { 1455 // get bounding box from geometry 1456 tData.mGeometry->GetBoundingBox(box); 1457 } 1458 else 1459 { 1460 box.Initialize(); 1461 RayInfoContainer::const_iterator ri, ri_end = tData.mRays->end(); 1462 1463 for(ri = tData.mRays->begin(); ri < ri_end; ++ ri) 1464 box.Include((*ri).ExtrapTermination()); 1465 } 1466 867 AxisAlignedBox3 box = tData.mBoundingBox; 868 1467 869 int sAxis = 0; 1468 int bestAxis; 1469 1470 // if max cost ratio is exceeded, take split along longest axis instead 1471 const float maxCostRatioForArbitraryAxis = 0.9f; 1472 1473 if (mUseDrivingAxisForMaxCost) 1474 bestAxis = box.Size().DrivingAxis(); 1475 else 1476 bestAxis = -1; 870 int bestAxis = -1; 1477 871 1478 872 #if 0 … … 1493 887 sAxis = box.Size().DrivingAxis(); 1494 888 1495 1496 //Debug << "use special axis: " << useSpecialAxis << endl; 1497 //Debug << "axis: " << sAxis << " drivingaxis: " << box.Size().DrivingAxis(); 1498 1499 for (axis = 0; axis < 3 ; ++ axis) 889 890 for (int axis = 0; axis < 3 ; ++ axis) 1500 891 { 1501 892 if (!useSpecialAxis || (axis == sAxis)) … … 1512 903 nPosition[axis]); 1513 904 } 1514 1515 //-- split plane position is spatial median 1516 1517 1518 // also use median split if cost ratio very low as 1519 // there are not enough visibility cues 1520 //if (!mUseCostHeuristics || (nCostRatio[axis] > maxCostRatioForHeur)) 1521 else 1522 { 1523 905 else //-- split plane position is spatial median 906 { 1524 907 nPosition[axis] = (box.Min()[axis] + box.Max()[axis]) * 0.5f; 1525 Vector3 normal(0,0,0); normal[axis] = 1.0f; 1526 1527 // allows faster split because we have axis aligned kd tree boxes 1528 if (isKdNode) 1529 { 1530 nCostRatio[axis] = EvalAxisAlignedSplitCost(tData, 1531 box, 1532 axis, 1533 nPosition[axis], 1534 nProbFront[axis], 1535 nProbBack[axis]); 1536 1537 Vector3 pos; 1538 1539 // create back geometry from box 1540 // NOTE: the geometry is saved when possible 1541 pos = box.Max(); pos[axis] = nPosition[axis]; 1542 AxisAlignedBox3 bBox(box.Min(), pos); 1543 PolygonContainer fPolys; 1544 bBox.ExtractPolys(fPolys); 1545 1546 nBackGeom[axis] = new BspNodeGeometry(fPolys); 1547 1548 //-- create front geometry from box 1549 pos = box.Min(); pos[axis] = nPosition[axis]; 1550 AxisAlignedBox3 fBox(pos, box.Max()); 1551 1552 PolygonContainer bPolys; 1553 fBox.ExtractPolys(bPolys); 1554 nFrontGeom[axis] = new BspNodeGeometry(bPolys); 1555 } 1556 else 1557 { 1558 nFrontGeom[axis] = new BspNodeGeometry(); 1559 nBackGeom[axis] = new BspNodeGeometry(); 1560 1561 nCostRatio[axis] = 1562 EvalSplitPlaneCost(Plane3(normal, nPosition[axis]), 1563 tData, *nFrontGeom[axis], *nBackGeom[axis], 1564 nProbFront[axis], nProbBack[axis]); 1565 } 908 909 nCostRatio[axis] = EvalSplitCost(tData, 910 box, 911 axis, 912 nPosition[axis], 913 nProbFront[axis], 914 nProbBack[axis]); 1566 915 } 1567 916 1568 1569 if (mUseDrivingAxisForMaxCost) 1570 { 1571 // we take longest axis split if cost ratio exceeds threshold 1572 if (nCostRatio[axis] < min(maxCostRatioForArbitraryAxis, nCostRatio[bestAxis])) 1573 { 1574 bestAxis = axis; 1575 } 1576 else if (nCostRatio[axis] < nCostRatio[bestAxis]) 1577 Debug << "taking split along longest axis (" << bestAxis << ") instead of (" << axis << ")" << endl; 1578 1579 } 1580 else 1581 { 1582 if (bestAxis == -1) 1583 { 1584 bestAxis = axis; 1585 } 1586 else if (nCostRatio[axis] < nCostRatio[bestAxis]) 1587 { 1588 bestAxis = axis; 1589 } 917 if (bestAxis == -1) 918 { 919 bestAxis = axis; 920 } 921 else if (nCostRatio[axis] < nCostRatio[bestAxis]) 922 { 923 bestAxis = axis; 1590 924 } 1591 925 } … … 1593 927 1594 928 //-- assign values 1595 axis = bestAxis;929 plane.mAxis = bestAxis; 1596 930 pFront = nProbFront[bestAxis]; 1597 931 pBack = nProbBack[bestAxis]; 1598 932 1599 // assign best split nodes geometry 1600 *frontGeom = nFrontGeom[bestAxis]; 1601 *backGeom = nBackGeom[bestAxis]; 1602 1603 // and delete other geometry 1604 DEL_PTR(nFrontGeom[(bestAxis + 1) % 3]); 1605 DEL_PTR(nBackGeom[(bestAxis + 2) % 3]); 1606 1607 //-- split plane 1608 Vector3 normal(0,0,0); normal[bestAxis] = 1; 1609 plane = Plane3(normal, nPosition[bestAxis]); 1610 1611 //Debug << "best axis: " << bestAxis << " pos " << nPosition[bestAxis] << endl; 1612 //Debug << "!!!!!!!!!!!!!!" << endl; 933 //-- split plane position 934 plane.mPosition = nPosition[bestAxis]; 935 1613 936 return nCostRatio[bestAxis]; 1614 937 } 1615 938 1616 939 1617 bool VspBspTree::SelectPlane(Plane3 &bestPlane, 1618 BspLeaf *leaf, 1619 VspBspTraversalData &data, 1620 VspBspTraversalData &frontData, 1621 VspBspTraversalData &backData, 1622 int &splitAxis) 1623 { 1624 // HACK matt: subdivide regularily to certain depth 1625 if (data.mDepth < 0) 1626 { 1627 cout << "d: " << data.mDepth << endl; 1628 // return axis aligned split 1629 AxisAlignedBox3 box; 1630 box.Initialize(); 1631 1632 // create bounding box of region 1633 data.mGeometry->GetBoundingBox(box); 1634 1635 const int axis = box.Size().DrivingAxis(); 1636 const Vector3 position = (box.Min()[axis] + box.Max()[axis]) * 0.5f; 1637 1638 Vector3 norm(0,0,0); norm[axis] = 1.0f; 1639 bestPlane = Plane3(norm, position); 1640 splitAxis = axis; 1641 return true; 1642 } 1643 1644 // simplest strategy: just take next polygon 1645 if (mSplitPlaneStrategy & RANDOM_POLYGON) 1646 { 1647 if (!data.mPolygons->empty()) 1648 { 1649 const int randIdx = 1650 (int)RandomValue(0, (Real)((int)data.mPolygons->size() - 1)); 1651 Polygon3 *nextPoly = (*data.mPolygons)[randIdx]; 1652 1653 bestPlane = nextPoly->GetSupportingPlane(); 1654 return true; 1655 } 1656 } 1657 1658 //-- use heuristics to find appropriate plane 1659 1660 // intermediate plane 1661 Plane3 plane; 1662 float lowestCost = MAX_FLOAT; 1663 1664 // decides if the first few splits should be only axisAligned 1665 const bool onlyAxisAligned = 1666 (mSplitPlaneStrategy & AXIS_ALIGNED) && 1667 ((int)data.mRays->size() > mTermMinRaysForAxisAligned) && 1668 ((int)data.GetAvgRayContribution() < mTermMaxRayContriForAxisAligned); 1669 1670 const int limit = onlyAxisAligned ? 0 : 1671 Min((int)data.mPolygons->size(), mMaxPolyCandidates); 1672 1673 float candidateCost; 1674 1675 int maxIdx = (int)data.mPolygons->size(); 1676 1677 for (int i = 0; i < limit; ++ i) 1678 { 1679 // the already taken candidates are stored behind maxIdx 1680 // => assure that no index is taken twice 1681 const int candidateIdx = (int)RandomValue(0, (Real)(-- maxIdx)); 1682 Polygon3 *poly = (*data.mPolygons)[candidateIdx]; 1683 1684 // swap candidate to the end to avoid testing same plane 1685 std::swap((*data.mPolygons)[maxIdx], (*data.mPolygons)[candidateIdx]); 1686 //Polygon3 *poly = (*data.mPolygons)[(int)RandomValue(0, (int)polys.size() - 1)]; 1687 1688 // evaluate current candidate 1689 BspNodeGeometry fGeom, bGeom; 1690 float fArea, bArea; 1691 plane = poly->GetSupportingPlane(); 1692 candidateCost = EvalSplitPlaneCost(plane, data, fGeom, bGeom, fArea, bArea); 1693 1694 if (candidateCost < lowestCost) 1695 { 1696 bestPlane = plane; 1697 lowestCost = candidateCost; 1698 } 1699 } 1700 1701 //-- evaluate axis aligned splits 1702 int axis; 1703 BspNodeGeometry *fGeom, *bGeom; 1704 float pFront, pBack; 1705 1706 candidateCost = 99999999.0f; 1707 1708 // option: axis aligned split only if no polygon available 1709 if (!mUsePolygonSplitIfAvailable || data.mPolygons->empty()) 1710 { 1711 candidateCost = SelectAxisAlignedPlane(plane, 1712 data, 1713 axis, 1714 &fGeom, 1715 &bGeom, 1716 pFront, 1717 pBack, 1718 data.mIsKdNode); 1719 } 1720 1721 splitAxis = 3; 1722 1723 if (candidateCost < lowestCost) 1724 { 1725 bestPlane = plane; 1726 lowestCost = candidateCost; 1727 splitAxis = axis; 1728 1729 // assign already computed values 1730 // we can do this because we always save the 1731 // computed values from the axis aligned splits 1732 1733 if (fGeom && bGeom) 1734 { 1735 frontData.mGeometry = fGeom; 1736 backData.mGeometry = bGeom; 1737 1738 frontData.mProbability = pFront; 1739 backData.mProbability = pBack; 1740 } 1741 } 1742 else 1743 { 1744 DEL_PTR(fGeom); 1745 DEL_PTR(bGeom); 1746 } 1747 1748 #ifdef _DEBUG 1749 Debug << "plane lowest cost: " << lowestCost << endl; 1750 #endif 1751 1752 // exeeded relative max cost ratio 1753 if (lowestCost > mTermMaxCostRatio) 1754 { 1755 return false; 1756 } 1757 1758 return true; 1759 } 1760 1761 1762 Plane3 VspBspTree::ChooseCandidatePlane(const RayInfoContainer &rays) const 1763 { 1764 const int candidateIdx = (int)RandomValue(0, (Real)((int)rays.size() - 1)); 1765 1766 const Vector3 minPt = rays[candidateIdx].ExtrapOrigin(); 1767 const Vector3 maxPt = rays[candidateIdx].ExtrapTermination(); 1768 1769 const Vector3 pt = (maxPt + minPt) * 0.5; 1770 const Vector3 normal = Normalize(rays[candidateIdx].mRay->GetDir()); 1771 1772 return Plane3(normal, pt); 1773 } 1774 1775 1776 Plane3 VspBspTree::ChooseCandidatePlane2(const RayInfoContainer &rays) const 1777 { 1778 Vector3 pt[3]; 1779 1780 int idx[3]; 1781 int cmaxT = 0; 1782 int cminT = 0; 1783 bool chooseMin = false; 1784 1785 for (int j = 0; j < 3; ++ j) 1786 { 1787 idx[j] = (int)RandomValue(0, (Real)((int)rays.size() * 2 - 1)); 1788 1789 if (idx[j] >= (int)rays.size()) 1790 { 1791 idx[j] -= (int)rays.size(); 1792 1793 chooseMin = (cminT < 2); 1794 } 1795 else 1796 chooseMin = (cmaxT < 2); 1797 1798 RayInfo rayInf = rays[idx[j]]; 1799 pt[j] = chooseMin ? rayInf.ExtrapOrigin() : rayInf.ExtrapTermination(); 1800 } 1801 1802 return Plane3(pt[0], pt[1], pt[2]); 1803 } 1804 1805 1806 Plane3 VspBspTree::ChooseCandidatePlane3(const RayInfoContainer &rays) const 1807 { 1808 Vector3 pt[3]; 1809 1810 int idx1 = (int)RandomValue(0, (Real)((int)rays.size() - 1)); 1811 int idx2 = (int)RandomValue(0, (Real)((int)rays.size() - 1)); 1812 1813 // check if rays different 1814 if (idx1 == idx2) 1815 idx2 = (idx2 + 1) % (int)rays.size(); 1816 1817 const RayInfo ray1 = rays[idx1]; 1818 const RayInfo ray2 = rays[idx2]; 1819 1820 // normal vector of the plane parallel to both lines 1821 const Vector3 norm = Normalize(CrossProd(ray1.mRay->GetDir(), ray2.mRay->GetDir())); 1822 1823 // vector from line 1 to line 2 1824 const Vector3 vd = ray2.ExtrapOrigin() - ray1.ExtrapOrigin(); 1825 1826 // project vector on normal to get distance 1827 const float dist = DotProd(vd, norm); 1828 1829 // point on plane lies halfway between the two planes 1830 const Vector3 planePt = ray1.ExtrapOrigin() + norm * dist * 0.5; 1831 1832 return Plane3(norm, planePt); 1833 } 1834 1835 1836 inline void VspBspTree::GenerateUniqueIdsForPvs() 940 inline void VspOspTree::GenerateUniqueIdsForPvs() 1837 941 { 1838 942 Intersectable::NewMail(); sBackId = Intersectable::sMailId; … … 1842 946 1843 947 1844 float Vsp BspTree::EvalRenderCostDecrease(const Plane3 &candidatePlane,1845 const Vsp BspTraversalData &data) const948 float VspOspTree::EvalRenderCostDecrease(const Plane3 &candidatePlane, 949 const VspOspTraversalData &data) const 1846 950 { 1847 951 float pvsFront = 0; … … 1874 978 BspNodeGeometry geomFront; 1875 979 BspNodeGeometry geomBack; 1876 1877 // construct child geometry with regard to the candidate split plane 1878 data.mGeometry->SplitGeometry(geomFront, 1879 geomBack, 1880 candidatePlane, 1881 mBox, 1882 //0.0f); 1883 mEpsilon); 1884 1885 if (!mUseAreaForPvs) // use front and back cell areas to approximate volume 1886 { 1887 pFront = geomFront.GetVolume(); 1888 pBack = pOverall - pFront; 1889 1890 // something is wrong with the volume 1891 if ((pFront < 0.0) || (pBack < 0.0)) 1892 { 1893 Debug << "ERROR in volume:\n" 1894 << "volume f :" << pFront << " b: " << pBack << " p: " << pOverall 1895 << ", real volume f: " << pFront << " b: " << geomBack.GetVolume() 1896 << ", #polygons f: " << geomFront.Size() << " b: " << geomBack.Size() << " p: " << data.mGeometry->Size() << endl; 1897 } 1898 } 1899 else 1900 { 1901 pFront = geomFront.GetArea(); 1902 pBack = geomBack.GetArea(); 1903 } 1904 980 981 pFront = geomFront.GetVolume(); 982 pBack = pOverall - pFront; 983 984 1905 985 1906 986 // -- pvs rendering heuristics … … 1921 1001 1922 1002 #if 1 1923 // take render cost of node into account 1003 // take render cost of node into account to avoid being stuck in a local minimum 1924 1004 const float normalizedOldRenderCost = oldRenderCost / mBox.GetVolume(); 1925 //Debug << "rendercostdecr: " << 0.99f * renderCostDecrease << " old render cost: " << 0.01f * normalizedOldRenderCost << endl;1926 //return 0.5f * renderCostDecrease + 0.5f * normalizedOldRenderCost;1927 1005 return 0.99f * renderCostDecrease + 0.01f * normalizedOldRenderCost; 1928 1006 #else … … 1932 1010 1933 1011 1934 float VspBspTree::EvalSplitPlaneCost(const Plane3 &candidatePlane, 1935 const VspBspTraversalData &data, 1936 BspNodeGeometry &geomFront, 1937 BspNodeGeometry &geomBack, 1938 float &pFront, 1939 float &pBack) const 1940 { 1941 float cost = 0; 1942 1943 float totalPvs = 0; 1944 float pvsFront = 0; 1945 float pvsBack = 0; 1946 1947 // probability that view point lies in back / front node 1948 float pOverall = 0; 1949 pFront = 0; 1950 pBack = 0; 1951 1952 1953 int limit; 1954 bool useRand; 1955 1956 // create unique ids for pvs heuristics 1957 GenerateUniqueIdsForPvs(); 1958 1959 // choose test rays randomly if too much 1960 if ((int)data.mRays->size() > mMaxTests) 1961 { 1962 useRand = true; 1963 limit = mMaxTests; 1964 } 1965 else 1966 { 1967 useRand = false; 1968 limit = (int)data.mRays->size(); 1969 } 1970 1971 for (int i = 0; i < limit; ++ i) 1972 { 1973 const int testIdx = useRand ? 1974 (int)RandomValue(0, (Real)((int)data.mRays->size() - 1)) : i; 1975 RayInfo rayInf = (*data.mRays)[testIdx]; 1976 1977 float t; 1978 VssRay *ray = rayInf.mRay; 1979 const int cf = rayInf.ComputeRayIntersection(candidatePlane, t); 1980 1981 // find front and back pvs for origing and termination object 1982 AddObjToPvs(ray->mTerminationObject, cf, pvsFront, pvsBack, totalPvs); 1983 AddObjToPvs(ray->mOriginObject, cf, pvsFront, pvsBack, totalPvs); 1984 } 1985 1986 // construct child geometry with regard to the candidate split plane 1987 bool splitSuccessFull = data.mGeometry->SplitGeometry(geomFront, 1988 geomBack, 1989 candidatePlane, 1990 mBox, 1991 //0.0f); 1992 mEpsilon); 1993 1994 pOverall = data.mProbability; 1995 1996 if (!mUseAreaForPvs) // use front and back cell areas to approximate volume 1997 { 1998 pFront = geomFront.GetVolume(); 1999 pBack = pOverall - pFront; 2000 2001 // HACK: precision issues possible for unbalanced split => don't take this split! 2002 if (1 && 2003 (!splitSuccessFull || (pFront <= 0) || (pBack <= 0) || 2004 !geomFront.Valid() || !geomBack.Valid())) 2005 { 2006 //Debug << "error f: " << pFront << " b: " << pBack << endl; 2007 // high penalty for this split 2008 return 99999.9f; 2009 } 2010 } 2011 else 2012 { 2013 pFront = geomFront.GetArea(); 2014 pBack = geomBack.GetArea(); 2015 } 2016 2017 2018 // -- pvs rendering heuristics 2019 const int lowerPvsLimit = mViewCellsManager->GetMinPvsSize(); 2020 const int upperPvsLimit = mViewCellsManager->GetMaxPvsSize(); 2021 2022 // only render cost heuristics or combined with standard deviation 2023 const float penaltyOld = EvalPvsPenalty((int)totalPvs, lowerPvsLimit, upperPvsLimit); 2024 const float penaltyFront = EvalPvsPenalty((int)pvsFront, lowerPvsLimit, upperPvsLimit); 2025 const float penaltyBack = EvalPvsPenalty((int)pvsBack, lowerPvsLimit, upperPvsLimit); 2026 2027 const float oldRenderCost = pOverall * penaltyOld; 2028 const float newRenderCost = penaltyFront * pFront + penaltyBack * pBack; 2029 2030 float oldCost, newCost; 2031 2032 // only render cost 2033 if (1) 2034 { 2035 oldCost = oldRenderCost; 2036 newCost = newRenderCost; 2037 } 2038 else // also considering standard deviation 2039 { 2040 // standard deviation is difference of back and front pvs 2041 const float expectedCost = 0.5f * (penaltyFront + penaltyBack); 2042 2043 const float newDeviation = 0.5f * 2044 fabs(penaltyFront - expectedCost) + fabs(penaltyBack - expectedCost); 2045 2046 const float oldDeviation = penaltyOld; 2047 2048 newCost = mRenderCostWeight * newRenderCost + (1.0f - mRenderCostWeight) * newDeviation; 2049 oldCost = mRenderCostWeight * oldRenderCost + (1.0f - mRenderCostWeight) * oldDeviation; 2050 } 2051 2052 cost += mPvsFactor * newCost / (oldCost + Limits::Small); 2053 2054 2055 #ifdef _DEBUG 2056 Debug << "totalpvs: " << data.mPvs << " ptotal: " << pOverall 2057 << " frontpvs: " << pvsFront << " pFront: " << pFront 2058 << " backpvs: " << pvsBack << " pBack: " << pBack << endl << endl; 2059 Debug << "cost: " << cost << endl; 2060 #endif 2061 2062 return cost; 2063 } 2064 2065 2066 int VspBspTree::ComputeBoxIntersections(const AxisAlignedBox3 &box, 2067 ViewCellContainer &viewCells) const 2068 { 2069 stack<bspNodePair> nodeStack; 2070 BspNodeGeometry *rgeom = new BspNodeGeometry(); 2071 2072 ConstructGeometry(mRoot, *rgeom); 2073 2074 nodeStack.push(bspNodePair(mRoot, rgeom)); 2075 2076 ViewCell::NewMail(); 2077 2078 while (!nodeStack.empty()) 2079 { 2080 BspNode *node = nodeStack.top().first; 2081 BspNodeGeometry *geom = nodeStack.top().second; 2082 nodeStack.pop(); 2083 2084 const int side = geom->ComputeIntersection(box); 2085 2086 switch (side) 2087 { 2088 case -1: 2089 // node geometry is contained in box 2090 CollectViewCells(node, true, viewCells, true); 2091 break; 2092 2093 case 0: 2094 if (node->IsLeaf()) 2095 { 2096 BspLeaf *leaf = dynamic_cast<BspLeaf *>(node); 2097 2098 if (!leaf->GetViewCell()->Mailed() && leaf->TreeValid()) 2099 { 2100 leaf->GetViewCell()->Mail(); 2101 viewCells.push_back(leaf->GetViewCell()); 2102 } 2103 } 2104 else 2105 { 2106 BspInterior *interior = dynamic_cast<BspInterior *>(node); 2107 2108 BspNode *first = interior->GetFront(); 2109 BspNode *second = interior->GetBack(); 2110 2111 BspNodeGeometry *firstGeom = new BspNodeGeometry(); 2112 BspNodeGeometry *secondGeom = new BspNodeGeometry(); 2113 2114 geom->SplitGeometry(*firstGeom, 2115 *secondGeom, 2116 interior->GetPlane(), 2117 mBox, 2118 //0.0000001f); 2119 mEpsilon); 2120 2121 nodeStack.push(bspNodePair(first, firstGeom)); 2122 nodeStack.push(bspNodePair(second, secondGeom)); 2123 } 2124 2125 break; 2126 default: 2127 // default: cull 2128 break; 2129 } 2130 2131 DEL_PTR(geom); 2132 2133 } 2134 2135 return (int)viewCells.size(); 2136 } 2137 2138 2139 float VspBspTree::EvalAxisAlignedSplitCost(const VspBspTraversalData &data, 2140 const AxisAlignedBox3 &box, 2141 const int axis, 2142 const float &position, 2143 float &pFront, 2144 float &pBack) const 1012 1013 float VspOspTree::EvalSplitCost(const VspOspTraversalData &data, 1014 const AxisAlignedBox3 &box, 1015 const int axis, 1016 const float &position, 1017 float &pFront, 1018 float &pBack) const 2145 1019 { 2146 1020 float pvsTotal = 0; … … 2158 1032 for(rit = data.mRays->begin(); rit != rit_end; ++ rit) 2159 1033 { 2160 //if (!(*rit).mRay->IsActive()) continue;2161 2162 1034 // determine the side of this ray with respect to the plane 2163 1035 float t; … … 2175 1047 2176 1048 pOverall = data.mProbability; 2177 2178 if (!mUseAreaForPvs) 2179 { // volume 2180 pBack = pFront = pOverall * 0.5f; 2181 2182 #if 0 2183 // box length substitute for probability 2184 const float minBox = box.Min(axis); 2185 const float maxBox = box.Max(axis); 2186 2187 pBack = position - minBox; 2188 pFront = maxBox - position; 2189 pOverall = maxBox - minBox; 2190 #endif 2191 } 2192 else //-- area substitute for probability 2193 { 2194 const int axis2 = (axis + 1) % 3; 2195 const int axis3 = (axis + 2) % 3; 2196 2197 const float faceArea = 2198 (box.Max(axis2) - box.Min(axis2)) * 2199 (box.Max(axis3) - box.Min(axis3)); 2200 2201 pBack = pFront = pOverall * 0.5f + faceArea; 2202 } 2203 1049 pBack = pFront = pOverall * 0.5f; 1050 1051 2204 1052 #ifdef _DEBUG 2205 1053 Debug << axis << " " << pvsSize << " " << pvsBack << " " << pvsFront << endl; … … 2215 1063 2216 1064 2217 void Vsp BspTree::AddObjToPvs(Intersectable *obj,1065 void VspOspTree::AddObjToPvs(Intersectable *obj, 2218 1066 const int cf, 2219 1067 float &frontPvs, … … 2268 1116 2269 1117 2270 void Vsp BspTree::CollectLeaves(vector<BspLeaf *> &leaves,1118 void VspOspTree::CollectLeaves(vector<BspLeaf *> &leaves, 2271 1119 const bool onlyUnmailed, 2272 1120 const int maxPvsSize) const … … 2302 1150 2303 1151 2304 AxisAlignedBox3 Vsp BspTree::GetBoundingBox() const1152 AxisAlignedBox3 VspOspTree::GetBoundingBox() const 2305 1153 { 2306 1154 return mBox; … … 2308 1156 2309 1157 2310 BspNode *Vsp BspTree::GetRoot() const1158 BspNode *VspOspTree::GetRoot() const 2311 1159 { 2312 1160 return mRoot; … … 2314 1162 2315 1163 2316 void Vsp BspTree::EvaluateLeafStats(const VspBspTraversalData &data)1164 void VspOspTree::EvaluateLeafStats(const VspOspTraversalData &data) 2317 1165 { 2318 1166 // the node became a leaf -> evaluate stats for leafs … … 2370 1218 2371 1219 2372 int Vsp BspTree::CastRay(Ray &ray)1220 int VspOspTree::CastRay(Ray &ray) 2373 1221 { 2374 1222 int hits = 0; … … 2439 1287 if (!leaf->GetViewCell()->Mailed()) 2440 1288 { 2441 //ray.bspIntersections.push_back(Ray::Vsp BspIntersection(maxt, leaf));1289 //ray.bspIntersections.push_back(Ray::VspOspIntersection(maxt, leaf)); 2442 1290 leaf->GetViewCell()->Mail(); 2443 1291 ++ hits; … … 2468 1316 2469 1317 2470 void Vsp BspTree::CollectViewCells(ViewCellContainer &viewCells, bool onlyValid) const1318 void VspOspTree::CollectViewCells(ViewCellContainer &viewCells, bool onlyValid) const 2471 1319 { 2472 1320 ViewCell::NewMail(); … … 2476 1324 2477 1325 2478 void Vsp BspTree::CollapseViewCells()1326 void VspOspTree::CollapseViewCells() 2479 1327 { 2480 1328 // TODO … … 2531 1379 2532 1380 2533 void Vsp BspTree::CollectRays(VssRayContainer &rays)1381 void VspOspTree::CollectRays(VssRayContainer &rays) 2534 1382 { 2535 1383 vector<BspLeaf *> leaves; … … 2548 1396 2549 1397 2550 void Vsp BspTree::ValidateTree()1398 void VspOspTree::ValidateTree() 2551 1399 { 2552 1400 stack<BspNode *> nodeStack; … … 2591 1439 2592 1440 2593 void Vsp BspTree::CollectViewCells(BspNode *root,1441 void VspOspTree::CollectViewCells(BspNode *root, 2594 1442 bool onlyValid, 2595 1443 ViewCellContainer &viewCells, … … 2635 1483 2636 1484 2637 void VspBspTree::PreprocessPolygons(PolygonContainer &polys) 2638 { 2639 // preprocess: throw out polygons coincident to the view space box (not needed) 2640 PolygonContainer boxPolys; 2641 mBox.ExtractPolys(boxPolys); 2642 vector<Plane3> boxPlanes; 2643 2644 PolygonContainer::iterator pit, pit_end = boxPolys.end(); 2645 2646 // extract planes of box 2647 // TODO: can be done more elegantly than first extracting polygons 2648 // and take their planes 2649 for (pit = boxPolys.begin(); pit != pit_end; ++ pit) 2650 { 2651 boxPlanes.push_back((*pit)->GetSupportingPlane()); 2652 } 2653 2654 pit_end = polys.end(); 2655 2656 for (pit = polys.begin(); pit != pit_end; ++ pit) 2657 { 2658 vector<Plane3>::const_iterator bit, bit_end = boxPlanes.end(); 2659 2660 for (bit = boxPlanes.begin(); (bit != bit_end) && (*pit); ++ bit) 2661 { 2662 const int cf = (*pit)->ClassifyPlane(*bit, mEpsilon); 2663 2664 if (cf == Polygon3::COINCIDENT) 2665 { 2666 DEL_PTR(*pit); 2667 //Debug << "coincident!!" << endl; 2668 } 2669 } 2670 } 2671 2672 // remove deleted entries 2673 for (int i = 0; i < (int)polys.size(); ++ i) 2674 { 2675 while (!polys[i] && (i < (int)polys.size())) 2676 { 2677 swap(polys[i], polys.back()); 2678 polys.pop_back(); 2679 } 2680 } 2681 } 2682 2683 2684 float VspBspTree::AccumulatedRayLength(const RayInfoContainer &rays) const 2685 { 2686 float len = 0; 2687 2688 RayInfoContainer::const_iterator it, it_end = rays.end(); 2689 2690 for (it = rays.begin(); it != it_end; ++ it) 2691 len += (*it).SegmentLength(); 2692 2693 return len; 2694 } 2695 2696 2697 int VspBspTree::SplitRays(const Plane3 &plane, 1485 int VspOspTree::SplitRays(const Plane3 &plane, 2698 1486 RayInfoContainer &rays, 2699 1487 RayInfoContainer &frontRays, … … 2725 1513 { 2726 1514 //-- split ray 2727 // 1515 //-- test if start point behind or in front of plane 2728 1516 const int side = plane.Side(bRay.ExtrapOrigin()); 2729 1517 … … 2750 1538 2751 1539 2752 void VspBspTree::ExtractHalfSpaces(BspNode *n, vector<Plane3> &halfSpaces) const 2753 { 2754 BspNode *lastNode; 2755 2756 do 2757 { 2758 lastNode = n; 2759 2760 // want to get planes defining geometry of this node => don't take 2761 // split plane of node itself 2762 n = n->GetParent(); 2763 2764 if (n) 2765 { 2766 BspInterior *interior = dynamic_cast<BspInterior *>(n); 2767 Plane3 halfSpace = dynamic_cast<BspInterior *>(interior)->GetPlane(); 2768 2769 if (interior->GetBack() != lastNode) 2770 halfSpace.ReverseOrientation(); 2771 2772 halfSpaces.push_back(halfSpace); 2773 } 2774 } 2775 while (n); 2776 } 2777 2778 2779 void VspBspTree::ConstructGeometry(BspNode *n, 2780 BspNodeGeometry &geom) const 2781 { 2782 vector<Plane3> halfSpaces; 2783 ExtractHalfSpaces(n, halfSpaces); 2784 2785 PolygonContainer candidatePolys; 2786 vector<Plane3> candidatePlanes; 2787 2788 vector<Plane3>::const_iterator pit, pit_end = halfSpaces.end(); 2789 2790 // bounded planes are added to the polygons 2791 for (pit = halfSpaces.begin(); pit != pit_end; ++ pit) 2792 { 2793 Polygon3 *p = GetBoundingBox().CrossSection(*pit); 2794 2795 if (p->Valid(mEpsilon)) 2796 { 2797 candidatePolys.push_back(p); 2798 candidatePlanes.push_back(*pit); 2799 } 2800 } 2801 2802 // add faces of bounding box (also could be faces of the cell) 2803 for (int i = 0; i < 6; ++ i) 2804 { 2805 VertexContainer vertices; 2806 2807 for (int j = 0; j < 4; ++ j) 2808 vertices.push_back(mBox.GetFace(i).mVertices[j]); 2809 2810 Polygon3 *poly = new Polygon3(vertices); 2811 2812 candidatePolys.push_back(poly); 2813 candidatePlanes.push_back(poly->GetSupportingPlane()); 2814 } 2815 2816 for (int i = 0; i < (int)candidatePolys.size(); ++ i) 2817 { 2818 // polygon is split by all other planes 2819 for (int j = 0; (j < (int)halfSpaces.size()) && candidatePolys[i]; ++ j) 2820 { 2821 if (i == j) // polygon and plane are coincident 2822 continue; 2823 2824 VertexContainer splitPts; 2825 Polygon3 *frontPoly, *backPoly; 2826 2827 const int cf = 2828 candidatePolys[i]->ClassifyPlane(halfSpaces[j], 2829 mEpsilon); 2830 2831 switch (cf) 2832 { 2833 case Polygon3::SPLIT: 2834 frontPoly = new Polygon3(); 2835 backPoly = new Polygon3(); 2836 2837 candidatePolys[i]->Split(halfSpaces[j], 2838 *frontPoly, 2839 *backPoly, 2840 mEpsilon); 2841 2842 DEL_PTR(candidatePolys[i]); 2843 2844 if (backPoly->Valid(mEpsilon)) 2845 candidatePolys[i] = backPoly; 2846 else 2847 DEL_PTR(backPoly); 2848 2849 // outside, don't need this 2850 DEL_PTR(frontPoly); 2851 break; 2852 // polygon outside of halfspace 2853 case Polygon3::FRONT_SIDE: 2854 DEL_PTR(candidatePolys[i]); 2855 break; 2856 // just take polygon as it is 2857 case Polygon3::BACK_SIDE: 2858 case Polygon3::COINCIDENT: 2859 default: 2860 break; 2861 } 2862 } 2863 2864 if (candidatePolys[i]) 2865 { 2866 geom.Add(candidatePolys[i], candidatePlanes[i]); 2867 // geom.mPolys.push_back(candidates[i]); 2868 } 2869 } 2870 } 2871 2872 2873 void VspBspTree::ConstructGeometry(ViewCell *vc, 2874 BspNodeGeometry &vcGeom) const 2875 { 2876 ViewCellContainer leaves; 2877 2878 mViewCellsTree->CollectLeaves(vc, leaves); 2879 2880 ViewCellContainer::const_iterator it, it_end = leaves.end(); 2881 2882 for (it = leaves.begin(); it != it_end; ++ it) 2883 { 2884 BspLeaf *l = dynamic_cast<BspViewCell *>(*it)->mLeaf; 2885 2886 ConstructGeometry(l, vcGeom); 2887 } 2888 } 2889 2890 2891 int VspBspTree::FindNeighbors(BspNode *n, vector<BspLeaf *> &neighbors, 1540 int VspOspTree::FindNeighbors(BspNode *n, vector<BspLeaf *> &neighbors, 2892 1541 const bool onlyUnmailed) const 2893 1542 { 2894 stack<bspNodePair> nodeStack; 2895 2896 BspNodeGeometry nodeGeom; 2897 ConstructGeometry(n, nodeGeom); 2898 // const float eps = 0.5f; 2899 const float eps = 0.01f; 2900 // split planes from the root to this node 2901 // needed to verify that we found neighbor leaf 2902 // TODO: really needed? 2903 vector<Plane3> halfSpaces; 2904 ExtractHalfSpaces(n, halfSpaces); 2905 2906 2907 BspNodeGeometry *rgeom = new BspNodeGeometry(); 2908 ConstructGeometry(mRoot, *rgeom); 2909 2910 nodeStack.push(bspNodePair(mRoot, rgeom)); 2911 2912 while (!nodeStack.empty()) 2913 { 2914 BspNode *node = nodeStack.top().first; 2915 BspNodeGeometry *geom = nodeStack.top().second; 2916 2917 nodeStack.pop(); 2918 2919 if (node->IsLeaf()) 2920 { 2921 // test if this leaf is in valid view space 2922 if (node->TreeValid() && 2923 (node != n) && 2924 (!onlyUnmailed || !node->Mailed())) 2925 { 2926 bool isAdjacent = true; 2927 2928 if (1) 2929 { 2930 // test all planes of current node if still adjacent 2931 for (int i = 0; (i < halfSpaces.size()) && isAdjacent; ++ i) 2932 { 2933 const int cf = 2934 Polygon3::ClassifyPlane(geom->GetPolys(), 2935 halfSpaces[i], 2936 eps); 2937 2938 if (cf == Polygon3::FRONT_SIDE) 2939 { 2940 isAdjacent = false; 2941 } 2942 } 2943 } 2944 else 2945 { 2946 // TODO: why is this wrong?? 2947 // test all planes of current node if still adjacent 2948 for (int i = 0; (i < nodeGeom.Size()) && isAdjacent; ++ i) 2949 { 2950 Polygon3 *poly = nodeGeom.GetPolys()[i]; 2951 2952 const int cf = 2953 Polygon3::ClassifyPlane(geom->GetPolys(), 2954 poly->GetSupportingPlane(), 2955 eps); 2956 2957 if (cf == Polygon3::FRONT_SIDE) 2958 { 2959 isAdjacent = false; 2960 } 2961 } 2962 } 2963 // neighbor was found 2964 if (isAdjacent) 2965 { 2966 neighbors.push_back(dynamic_cast<BspLeaf *>(node)); 2967 } 2968 } 2969 } 2970 else 2971 { 2972 BspInterior *interior = dynamic_cast<BspInterior *>(node); 2973 2974 const int cf = Polygon3::ClassifyPlane(nodeGeom.GetPolys(), 2975 interior->GetPlane(), 2976 eps); 2977 2978 BspNode *front = interior->GetFront(); 2979 BspNode *back = interior->GetBack(); 2980 2981 BspNodeGeometry *fGeom = new BspNodeGeometry(); 2982 BspNodeGeometry *bGeom = new BspNodeGeometry(); 2983 2984 geom->SplitGeometry(*fGeom, 2985 *bGeom, 2986 interior->GetPlane(), 2987 mBox, 2988 //0.0000001f); 2989 eps); 2990 2991 if (cf == Polygon3::BACK_SIDE) 2992 { 2993 nodeStack.push(bspNodePair(interior->GetBack(), bGeom)); 2994 DEL_PTR(fGeom); 2995 } 2996 else 2997 { 2998 if (cf == Polygon3::FRONT_SIDE) 2999 { 3000 nodeStack.push(bspNodePair(interior->GetFront(), fGeom)); 3001 DEL_PTR(bGeom); 3002 } 3003 else 3004 { // random decision 3005 nodeStack.push(bspNodePair(front, fGeom)); 3006 nodeStack.push(bspNodePair(back, bGeom)); 3007 } 3008 } 3009 } 3010 3011 DEL_PTR(geom); 3012 } 3013 3014 return (int)neighbors.size(); 3015 } 3016 3017 3018 3019 int VspBspTree::FindApproximateNeighbors(BspNode *n, 3020 vector<BspLeaf *> &neighbors, 3021 const bool onlyUnmailed) const 3022 { 3023 stack<bspNodePair> nodeStack; 3024 3025 BspNodeGeometry nodeGeom; 3026 ConstructGeometry(n, nodeGeom); 3027 3028 float eps = 0.01f; 3029 // split planes from the root to this node 3030 // needed to verify that we found neighbor leaf 3031 // TODO: really needed? 3032 vector<Plane3> halfSpaces; 3033 ExtractHalfSpaces(n, halfSpaces); 3034 3035 3036 BspNodeGeometry *rgeom = new BspNodeGeometry(); 3037 ConstructGeometry(mRoot, *rgeom); 3038 3039 nodeStack.push(bspNodePair(mRoot, rgeom)); 3040 3041 while (!nodeStack.empty()) 3042 { 3043 BspNode *node = nodeStack.top().first; 3044 BspNodeGeometry *geom = nodeStack.top().second; 3045 3046 nodeStack.pop(); 3047 3048 if (node->IsLeaf()) 3049 { 3050 // test if this leaf is in valid view space 3051 if (node->TreeValid() && 3052 (node != n) && 3053 (!onlyUnmailed || !node->Mailed())) 3054 { 3055 bool isAdjacent = true; 3056 3057 // neighbor was found 3058 if (isAdjacent) 3059 { 3060 neighbors.push_back(dynamic_cast<BspLeaf *>(node)); 3061 } 3062 } 3063 } 3064 else 3065 { 3066 BspInterior *interior = dynamic_cast<BspInterior *>(node); 3067 3068 const int cf = Polygon3::ClassifyPlane(nodeGeom.GetPolys(), 3069 interior->GetPlane(), 3070 eps); 3071 3072 BspNode *front = interior->GetFront(); 3073 BspNode *back = interior->GetBack(); 3074 3075 BspNodeGeometry *fGeom = new BspNodeGeometry(); 3076 BspNodeGeometry *bGeom = new BspNodeGeometry(); 3077 3078 geom->SplitGeometry(*fGeom, 3079 *bGeom, 3080 interior->GetPlane(), 3081 mBox, 3082 //0.0000001f); 3083 eps); 3084 3085 if (cf == Polygon3::BACK_SIDE) 3086 { 3087 nodeStack.push(bspNodePair(interior->GetBack(), bGeom)); 3088 DEL_PTR(fGeom); 3089 } 3090 else 3091 { 3092 if (cf == Polygon3::FRONT_SIDE) 3093 { 3094 nodeStack.push(bspNodePair(interior->GetFront(), fGeom)); 3095 DEL_PTR(bGeom); 3096 } 3097 else 3098 { // random decision 3099 nodeStack.push(bspNodePair(front, fGeom)); 3100 nodeStack.push(bspNodePair(back, bGeom)); 3101 } 3102 } 3103 } 3104 3105 DEL_PTR(geom); 3106 } 3107 3108 return (int)neighbors.size(); 3109 } 3110 3111 3112 3113 BspLeaf *VspBspTree::GetRandomLeaf(const Plane3 &halfspace) 3114 { 1543 // TODO 1544 return 0; 1545 } 1546 1547 1548 BspLeaf *VspOspTree::GetRandomLeaf(const Plane3 &halfspace) 1549 { 1550 #if TODO 3115 1551 stack<BspNode *> nodeStack; 3116 1552 nodeStack.push(mRoot); … … 3157 1593 } 3158 1594 } 3159 1595 #endif 3160 1596 return NULL; 3161 1597 } 3162 1598 3163 1599 3164 BspLeaf *Vsp BspTree::GetRandomLeaf(const bool onlyUnmailed)1600 BspLeaf *VspOspTree::GetRandomLeaf(const bool onlyUnmailed) 3165 1601 { 3166 1602 stack<BspNode *> nodeStack; … … 3198 1634 3199 1635 3200 int Vsp BspTree::ComputePvsSize(const RayInfoContainer &rays) const1636 int VspOspTree::ComputePvsSize(const RayInfoContainer &rays) const 3201 1637 { 3202 1638 int pvsSize = 0; … … 3232 1668 3233 1669 3234 float Vsp BspTree::GetEpsilon() const1670 float VspOspTree::GetEpsilon() const 3235 1671 { 3236 1672 return mEpsilon; … … 3238 1674 3239 1675 3240 int VspBspTree::SplitPolygons(const Plane3 &plane, 3241 PolygonContainer &polys, 3242 PolygonContainer &frontPolys, 3243 PolygonContainer &backPolys, 3244 PolygonContainer &coincident) const 3245 { 3246 int splits = 0; 3247 3248 PolygonContainer::const_iterator it, it_end = polys.end(); 3249 3250 for (it = polys.begin(); it != polys.end(); ++ it) 3251 { 3252 Polygon3 *poly = *it; 3253 3254 // classify polygon 3255 const int cf = poly->ClassifyPlane(plane, mEpsilon); 3256 3257 switch (cf) 3258 { 3259 case Polygon3::COINCIDENT: 3260 coincident.push_back(poly); 3261 break; 3262 case Polygon3::FRONT_SIDE: 3263 frontPolys.push_back(poly); 3264 break; 3265 case Polygon3::BACK_SIDE: 3266 backPolys.push_back(poly); 3267 break; 3268 case Polygon3::SPLIT: 3269 backPolys.push_back(poly); 3270 frontPolys.push_back(poly); 3271 ++ splits; 3272 break; 3273 default: 3274 Debug << "SHOULD NEVER COME HERE\n"; 3275 break; 3276 } 3277 } 3278 3279 return splits; 3280 } 3281 3282 3283 int VspBspTree::CastLineSegment(const Vector3 &origin, 1676 1677 int VspOspTree::CastLineSegment(const Vector3 &origin, 3284 1678 const Vector3 &termination, 3285 1679 ViewCellContainer &viewcells) … … 3387 1781 3388 1782 3389 3390 int VspBspTree::TreeDistance(BspNode *n1, BspNode *n2) const 3391 { 3392 std::deque<BspNode *> path1; 3393 BspNode *p1 = n1; 3394 3395 // create path from node 1 to root 3396 while (p1) 3397 { 3398 if (p1 == n2) // second node on path 3399 return (int)path1.size(); 3400 3401 path1.push_front(p1); 3402 p1 = p1->GetParent(); 3403 } 3404 3405 int depth = n2->GetDepth(); 3406 int d = depth; 3407 3408 BspNode *p2 = n2; 3409 3410 // compare with same depth 3411 while (1) 3412 { 3413 if ((d < (int)path1.size()) && (p2 == path1[d])) 3414 return (depth - d) + ((int)path1.size() - 1 - d); 3415 3416 -- d; 3417 p2 = p2->GetParent(); 3418 } 3419 3420 return 0; // never come here 3421 } 3422 3423 3424 BspNode *VspBspTree::CollapseTree(BspNode *node, int &collapsed) 1783 BspNode *VspOspTree::CollapseTree(BspNode *node, int &collapsed) 3425 1784 { 3426 1785 // TODO … … 3464 1823 3465 1824 3466 int Vsp BspTree::CollapseTree()1825 int VspOspTree::CollapseTree() 3467 1826 { 3468 1827 int collapsed = 0; … … 3478 1837 3479 1838 3480 void Vsp BspTree::RepairViewCellsLeafLists()1839 void VspOspTree::RepairViewCellsLeafLists() 3481 1840 { 3482 1841 // TODO … … 3521 1880 3522 1881 3523 typedef pair<BspNode *, BspNodeGeometry *> bspNodePair; 3524 3525 3526 int VspBspTree::CastBeam(Beam &beam) 3527 { 3528 stack<bspNodePair> nodeStack; 3529 BspNodeGeometry *rgeom = new BspNodeGeometry(); 3530 ConstructGeometry(mRoot, *rgeom); 3531 3532 nodeStack.push(bspNodePair(mRoot, rgeom)); 3533 3534 ViewCell::NewMail(); 3535 3536 while (!nodeStack.empty()) 3537 { 3538 BspNode *node = nodeStack.top().first; 3539 BspNodeGeometry *geom = nodeStack.top().second; 3540 nodeStack.pop(); 3541 3542 AxisAlignedBox3 box; 3543 geom->GetBoundingBox(box); 3544 3545 const int side = beam.ComputeIntersection(box); 3546 3547 switch (side) 3548 { 3549 case -1: 3550 CollectViewCells(node, true, beam.mViewCells, true); 3551 break; 3552 case 0: 3553 3554 if (node->IsLeaf()) 3555 { 3556 BspLeaf *leaf = dynamic_cast<BspLeaf *>(node); 3557 3558 if (!leaf->GetViewCell()->Mailed() && leaf->TreeValid()) 3559 { 3560 leaf->GetViewCell()->Mail(); 3561 beam.mViewCells.push_back(leaf->GetViewCell()); 3562 } 3563 } 3564 else 3565 { 3566 BspInterior *interior = dynamic_cast<BspInterior *>(node); 3567 3568 BspNode *first = interior->GetFront(); 3569 BspNode *second = interior->GetBack(); 3570 3571 BspNodeGeometry *firstGeom = new BspNodeGeometry(); 3572 BspNodeGeometry *secondGeom = new BspNodeGeometry(); 3573 3574 geom->SplitGeometry(*firstGeom, 3575 *secondGeom, 3576 interior->GetPlane(), 3577 mBox, 3578 //0.0000001f); 3579 mEpsilon); 3580 3581 // decide on the order of the nodes 3582 if (DotProd(beam.mPlanes[0].mNormal, 3583 interior->GetPlane().mNormal) > 0) 3584 { 3585 swap(first, second); 3586 swap(firstGeom, secondGeom); 3587 } 3588 3589 nodeStack.push(bspNodePair(first, firstGeom)); 3590 nodeStack.push(bspNodePair(second, secondGeom)); 3591 } 3592 3593 break; 3594 default: 3595 // default: cull 3596 break; 3597 } 3598 3599 DEL_PTR(geom); 3600 3601 } 3602 3603 return (int)beam.mViewCells.size(); 3604 } 3605 3606 3607 void VspBspTree::SetViewCellsManager(ViewCellsManager *vcm) 3608 { 3609 mViewCellsManager = vcm; 3610 } 3611 3612 3613 int VspBspTree::CollectMergeCandidates(const vector<BspLeaf *> leaves, 3614 vector<MergeCandidate> &candidates) 3615 { 3616 BspLeaf::NewMail(); 3617 3618 vector<BspLeaf *>::const_iterator it, it_end = leaves.end(); 3619 3620 int numCandidates = 0; 3621 3622 // find merge candidates and push them into queue 3623 for (it = leaves.begin(); it != it_end; ++ it) 3624 { 3625 BspLeaf *leaf = *it; 3626 3627 // the same leaves must not be part of two merge candidates 3628 leaf->Mail(); 3629 3630 vector<BspLeaf *> neighbors; 3631 3632 // appoximate neighbor search has slightl relaxed constraints 3633 if (1) 3634 FindNeighbors(leaf, neighbors, true); 3635 else 3636 FindApproximateNeighbors(leaf, neighbors, true); 3637 3638 vector<BspLeaf *>::const_iterator nit, nit_end = neighbors.end(); 3639 3640 // TODO: test if at least one ray goes from one leaf to the other 3641 for (nit = neighbors.begin(); nit != nit_end; ++ nit) 3642 { 3643 if ((*nit)->GetViewCell() != leaf->GetViewCell()) 3644 { 3645 MergeCandidate mc(leaf->GetViewCell(), (*nit)->GetViewCell()); 3646 3647 // dont't merge view cells if they are empty and not front and back leaf of the same parent 3648 // in the tree? 3649 if (mEmptyViewCellsMergeAllowed || 3650 !leaf->GetViewCell()->GetPvs().Empty() || 3651 !(*nit)->GetViewCell()->GetPvs().Empty() || 3652 leaf->IsSibling(*nit)) 3653 { 3654 candidates.push_back(mc); 3655 } 3656 3657 ++ numCandidates; 3658 if ((numCandidates % 1000) == 0) 3659 { 3660 cout << "collected " << numCandidates << " merge candidates" << endl; 3661 } 3662 } 3663 } 3664 } 3665 3666 Debug << "merge queue: " << (int)candidates.size() << endl; 3667 Debug << "leaves in queue: " << numCandidates << endl; 3668 3669 3670 return (int)leaves.size(); 3671 } 3672 3673 3674 int VspBspTree::CollectMergeCandidates(const VssRayContainer &rays, 3675 vector<MergeCandidate> &candidates) 3676 { 3677 ViewCell::NewMail(); 3678 long startTime = GetTime(); 3679 3680 map<BspLeaf *, vector<BspLeaf*> > neighborMap; 3681 ViewCellContainer::const_iterator iit; 3682 3683 int numLeaves = 0; 3684 3685 BspLeaf::NewMail(); 3686 3687 for (int i = 0; i < (int)rays.size(); ++ i) 3688 { 3689 VssRay *ray = rays[i]; 3690 3691 // traverse leaves stored in the rays and compare and 3692 // merge consecutive leaves (i.e., the neighbors in the tree) 3693 if (ray->mViewCells.size() < 2) 3694 continue; 3695 //TODO viewcellhierarchy 3696 iit = ray->mViewCells.begin(); 3697 BspViewCell *bspVc = dynamic_cast<BspViewCell *>(*(iit ++)); 3698 BspLeaf *leaf = bspVc->mLeaf; 3699 3700 // traverse intersections 3701 // consecutive leaves are neighbors => add them to queue 3702 for (; iit != ray->mViewCells.end(); ++ iit) 3703 { 3704 // next pair 3705 BspLeaf *prevLeaf = leaf; 3706 bspVc = dynamic_cast<BspViewCell *>(*iit); 3707 leaf = bspVc->mLeaf; 3708 3709 // view space not valid or same view cell 3710 if (!leaf->TreeValid() || !prevLeaf->TreeValid() || 3711 (leaf->GetViewCell() == prevLeaf->GetViewCell())) 3712 continue; 3713 3714 vector<BspLeaf *> &neighbors = neighborMap[leaf]; 3715 3716 bool found = false; 3717 3718 // both leaves inserted in queue already => 3719 // look if double pair already exists 3720 if (leaf->Mailed() && prevLeaf->Mailed()) 3721 { 3722 vector<BspLeaf *>::const_iterator it, it_end = neighbors.end(); 3723 3724 for (it = neighbors.begin(); !found && (it != it_end); ++ it) 3725 if (*it == prevLeaf) 3726 found = true; // already in queue 3727 } 3728 3729 if (!found) 3730 { 3731 // this pair is not in map yet 3732 // => insert into the neighbor map and the queue 3733 neighbors.push_back(prevLeaf); 3734 neighborMap[prevLeaf].push_back(leaf); 3735 3736 leaf->Mail(); 3737 prevLeaf->Mail(); 3738 3739 MergeCandidate mc(leaf->GetViewCell(), prevLeaf->GetViewCell()); 3740 3741 candidates.push_back(mc); 3742 3743 if (((int)candidates.size() % 1000) == 0) 3744 { 3745 cout << "collected " << (int)candidates.size() << " merge candidates" << endl; 3746 } 3747 } 3748 } 3749 } 3750 3751 Debug << "neighbormap size: " << (int)neighborMap.size() << endl; 3752 Debug << "merge queue: " << (int)candidates.size() << endl; 3753 Debug << "leaves in queue: " << numLeaves << endl; 3754 3755 3756 //-- collect the leaves which haven't been found by ray casting 3757 if (0) 3758 { 3759 cout << "finding additional merge candidates using geometry" << endl; 3760 vector<BspLeaf *> leaves; 3761 CollectLeaves(leaves, true); 3762 Debug << "found " << (int)leaves.size() << " new leaves" << endl << endl; 3763 CollectMergeCandidates(leaves, candidates); 3764 } 3765 3766 return numLeaves; 3767 } 3768 3769 3770 3771 3772 ViewCell *VspBspTree::GetViewCell(const Vector3 &point, const bool active) 1882 1883 ViewCell *VspOspTree::GetViewCell(const Vector3 &point, const bool active) 3773 1884 { 3774 1885 if (mRoot == NULL) … … 3809 1920 3810 1921 3811 bool Vsp BspTree::ViewPointValid(const Vector3 &viewPoint) const1922 bool VspOspTree::ViewPointValid(const Vector3 &viewPoint) const 3812 1923 { 3813 1924 BspNode *node = mRoot; … … 3839 1950 3840 1951 3841 void Vsp BspTree::PropagateUpValidity(BspNode *node)1952 void VspOspTree::PropagateUpValidity(BspNode *node) 3842 1953 { 3843 1954 const bool isValid = node->TreeValid(); … … 3868 1979 3869 1980 #if ZIPPED_VIEWCELLS 3870 bool Vsp BspTree::Export(ogzstream &stream)1981 bool VspOspTree::Export(ogzstream &stream) 3871 1982 #else 3872 bool Vsp BspTree::Export(ofstream &stream)1983 bool VspOspTree::Export(ofstream &stream) 3873 1984 #endif 3874 1985 { … … 3878 1989 } 3879 1990 1991 3880 1992 #if ZIPPED_VIEWCELLS 3881 void Vsp BspTree::ExportNode(BspNode *node, ogzstream &stream)1993 void VspOspTree::ExportNode(BspNode *node, ogzstream &stream) 3882 1994 #else 3883 void Vsp BspTree::ExportNode(BspNode *node, ofstream &stream)1995 void VspOspTree::ExportNode(BspNode *node, ofstream &stream) 3884 1996 #endif 3885 1997 {
Note: See TracChangeset
for help on using the changeset viewer.