- Timestamp:
- 11/18/05 14:02:49 (19 years ago)
- Location:
- trunk/VUT
- Files:
-
- 10 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/VUT/GtpVisibilityPreprocessor/scripts/default.env
r420 r421 73 73 74 74 height 5.0 75 75 maxViewCells 0 76 76 77 77 PostProcessing { -
trunk/VUT/GtpVisibilityPreprocessor/src/Environment.cpp
r419 r421 1175 1175 "bspTree"); 1176 1176 1177 RegisterOption("ViewCells.maxViewCells", 1178 optInt, 1179 "-view_cells_max_view_cells", 1180 "0"); 1181 1177 1182 RegisterOption("ViewCells.PostProcessing.minPvsDif", 1178 1183 optInt, -
trunk/VUT/GtpVisibilityPreprocessor/src/SamplingPreprocessor.cpp
r420 r421 61 61 ObjectContainer objects; 62 62 63 switch ( mBspTree->mConstructionMethod)63 switch (BspTree::sConstructionMethod) 64 64 { 65 65 case BspTree::FROM_INPUT_VIEW_CELLS: … … 779 779 if (!mBspTree) 780 780 { 781 if ((BspTree:: mConstructionMethod == BspTree::FROM_RAYS) &&781 if ((BspTree::sConstructionMethod == BspTree::FROM_RAYS) && 782 782 ((int)mSampleRays.size() < mBspConstructionSamples)) 783 783 { … … 889 889 outRays.push_back(mSampleRays[i]); 890 890 } 891 if (BspTree:: mConstructionMethod == BspTree::FROM_RAYS)891 if (BspTree::sConstructionMethod == BspTree::FROM_RAYS) 892 892 { 893 893 // export rays -
trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellBsp.cpp
r420 r421 14 14 #include "Plane3.h" 15 15 16 int BspNode::mailID = 1; 16 //-- static members 17 18 int BspNode::sMailId = 1; 17 19 18 20 /** Evaluates split plane classification with respect to the plane's 19 21 contribution for a minimum number splits in the tree. 20 22 */ 21 float BspTree::sLeastPolySplitsTable[] = {0, 0, 1, 0};23 const float BspTree::sLeastPolySplitsTable[] = {0, 0, 1, 0}; 22 24 /** Evaluates split plane classification with respect to the plane's 23 25 contribution for a balanced tree. 24 26 */ 25 float BspTree::sBalancedPolysTable[] = {1, -1, 0, 0};27 const float BspTree::sBalancedPolysTable[] = {1, -1, 0, 0}; 26 28 27 29 /** Evaluates split plane classification with respect to the plane's 28 30 contribution for a minimum number of ray splits. 29 31 */ 30 float BspTree::sLeastRaySplitsTable[] = {0, 0, 1, 1, 0};32 const float BspTree::sLeastRaySplitsTable[] = {0, 0, 1, 1, 0}; 31 33 /** Evaluates split plane classification with respect to the plane's 32 34 contribution for balanced rays. 33 35 */ 34 float BspTree::sBalancedRaysTable[] = {1, -1, 0, 0, 0}; 36 const float BspTree::sBalancedRaysTable[] = {1, -1, 0, 0, 0}; 37 38 int BspTree::sConstructionMethod = FROM_INPUT_VIEW_CELLS; 39 35 40 36 41 /****************************************************************/ … … 283 288 mPvsUseArea(true) 284 289 { 285 ParseEnvironment();286 290 Randomize(); // initialise random generator for heuristics 287 } 288 289 const BspTreeStatistics &BspTree::GetStatistics() const 290 { 291 return mStat; 292 } 293 294 void BspTreeStatistics::Print(ostream &app) const 295 { 296 app << "===== BspTree statistics ===============\n"; 297 298 app << setprecision(4); 299 300 app << "#N_CTIME ( Construction time [s] )\n" << Time() << " \n"; 301 302 app << "#N_NODES ( Number of nodes )\n" << nodes << "\n"; 303 304 app << "#N_INTERIORS ( Number of interior nodes )\n" << Interior() << "\n"; 305 306 app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n"; 307 308 app << "#N_SPLITS ( Number of splits )\n" << splits << "\n"; 309 310 app << "#N_PMAXDEPTHLEAVES ( Percentage of leaves at maxdepth )\n"<< 311 maxDepthNodes * 100 / (double)Leaves() << endl; 312 313 app << "#N_PMAXDEPTH ( Maximal reached depth )\n" << maxDepth << endl; 314 315 app << "#N_PMINDEPTH ( Minimal reached depth )\n" << minDepth << endl; 316 317 app << "#AVGDEPTH ( average depth )\n" << AvgDepth() << endl; 318 319 app << "#N_INPUT_POLYGONS (number of input polygons )\n" << polys << endl; 320 321 //app << "#N_PVS: " << pvs << endl; 322 323 app << "#N_ROUTPUT_INPUT_POLYGONS ( ratio polygons after subdivision / input polygons )\n" << 324 (polys + splits) / (double)polys << endl; 325 326 app << "===== END OF BspTree statistics ==========\n"; 327 } 328 329 330 BspTree::~BspTree() 331 { 332 DEL_PTR(mRoot); 333 } 334 335 void BspTree::InsertViewCell(ViewCell *viewCell) 336 { 337 PolygonContainer *polys = new PolygonContainer(); 338 339 // extract polygons that guide the split process 340 mStat.polys += AddMeshToPolygons(viewCell->GetMesh(), *polys, viewCell); 341 mBox.Include(viewCell->GetBox()); // add to BSP aabb 342 343 InsertPolygons(polys); 344 } 345 346 void BspTree::InsertPolygons(PolygonContainer *polys) 347 { 348 std::stack<BspTraversalData> tStack; 349 350 // traverse existing tree or create new tree 351 if (!mRoot) 352 mRoot = new BspLeaf(); 353 354 tStack.push(BspTraversalData(mRoot, polys, 0, mRootCell, new BoundedRayContainer(), 0, 355 mBox.SurfaceArea(), new BspNodeGeometry())); 356 357 while (!tStack.empty()) 358 { 359 // filter polygons donw the tree 360 BspTraversalData tData = tStack.top(); 361 tStack.pop(); 362 363 if (!tData.mNode->IsLeaf()) 364 { 365 BspInterior *interior = dynamic_cast<BspInterior *>(tData.mNode); 366 367 //-- filter view cell polygons down the tree until a leaf is reached 368 if (!tData.mPolygons->empty()) 369 { 370 PolygonContainer *frontPolys = new PolygonContainer(); 371 PolygonContainer *backPolys = new PolygonContainer(); 372 PolygonContainer coincident; 373 374 int splits = 0; 375 376 // split viewcell polygons with respect to split plane 377 splits += interior->SplitPolygons(*tData.mPolygons, 378 *frontPolys, 379 *backPolys, 380 coincident); 381 382 // extract view cells associated with the split polygons 383 ViewCell *frontViewCell = mRootCell; 384 ViewCell *backViewCell = mRootCell; 385 386 BspTraversalData frontData(interior->GetFront(), 387 frontPolys, 388 tData.mDepth + 1, 389 mRootCell, 390 tData.mRays, 391 tData.mPvs, 392 mBox.SurfaceArea(), 393 new BspNodeGeometry()); 394 395 BspTraversalData backData(interior->GetBack(), 396 backPolys, 397 tData.mDepth + 1, 398 mRootCell, 399 tData.mRays, 400 tData.mPvs, 401 mBox.SurfaceArea(), 402 new BspNodeGeometry()); 403 404 if (!mGenerateViewCells) 405 { 406 ExtractViewCells(frontData, 407 backData, 408 coincident, 409 interior->mPlane); 410 } 411 412 // don't need coincident polygons anymore 413 CLEAR_CONTAINER(coincident); 414 415 mStat.splits += splits; 416 417 // push the children on the stack 418 tStack.push(frontData); 419 tStack.push(backData); 420 } 421 422 // cleanup 423 DEL_PTR(tData.mPolygons); 424 } 425 else 426 { 427 // reached leaf => subdivide current viewcell 428 BspNode *subRoot = Subdivide(tStack, tData); 429 } 430 } 431 } 432 433 int BspTree::AddMeshToPolygons(Mesh *mesh, PolygonContainer &polys, MeshInstance *parent) 434 { 435 FaceContainer::const_iterator fi; 436 437 // copy the face data to polygons 438 for (fi = mesh->mFaces.begin(); fi != mesh->mFaces.end(); ++ fi) 439 { 440 Polygon3 *poly = new Polygon3((*fi), mesh); 441 442 if (poly->Valid()) 443 { 444 poly->mParent = parent; // set parent intersectable 445 polys.push_back(poly); 446 } 447 else 448 DEL_PTR(poly); 449 } 450 return (int)mesh->mFaces.size(); 451 } 452 453 int BspTree::AddToPolygonSoup(const ViewCellContainer &viewCells, 454 PolygonContainer &polys, 455 int maxObjects) 456 { 457 int limit = (maxObjects > 0) ? 458 Min((int)viewCells.size(), maxObjects) : (int)viewCells.size(); 459 460 int polysSize = 0; 461 462 for (int i = 0; i < limit; ++ i) 463 { 464 if (viewCells[i]->GetMesh()) // copy the mesh data to polygons 465 { 466 mBox.Include(viewCells[i]->GetBox()); // add to BSP tree aabb 467 polysSize += AddMeshToPolygons(viewCells[i]->GetMesh(), polys, viewCells[i]); 468 } 469 } 470 471 return polysSize; 472 } 473 474 int BspTree::AddToPolygonSoup(const ObjectContainer &objects, PolygonContainer &polys, int maxObjects) 475 { 476 int limit = (maxObjects > 0) ? Min((int)objects.size(), maxObjects) : (int)objects.size(); 477 478 for (int i = 0; i < limit; ++i) 479 { 480 Intersectable *object = objects[i];//*it; 481 Mesh *mesh = NULL; 482 483 switch (object->Type()) // extract the meshes 484 { 485 case Intersectable::MESH_INSTANCE: 486 mesh = dynamic_cast<MeshInstance *>(object)->GetMesh(); 487 break; 488 case Intersectable::VIEW_CELL: 489 mesh = dynamic_cast<ViewCell *>(object)->GetMesh(); 490 break; 491 // TODO: handle transformed mesh instances 492 default: 493 Debug << "intersectable type not supported" << endl; 494 break; 495 } 496 497 if (mesh) // copy the mesh data to polygons 498 { 499 mBox.Include(object->GetBox()); // add to BSP tree aabb 500 AddMeshToPolygons(mesh, polys, mRootCell); 501 } 502 } 503 504 return (int)polys.size(); 505 } 506 507 void BspTree::Construct(const ViewCellContainer &viewCells) 508 { 509 mStat.nodes = 1; 510 mBox.Initialize(); // initialise bsp tree bounding box 511 512 // copy view cell meshes into one big polygon soup 513 PolygonContainer *polys = new PolygonContainer(); 514 mStat.polys = AddToPolygonSoup(viewCells, *polys); 515 516 // construct tree from the view cell polygons 517 Construct(polys, new BoundedRayContainer()); 518 } 519 520 521 void BspTree::Construct(const ObjectContainer &objects) 522 { 523 mStat.nodes = 1; 524 mBox.Initialize(); // initialise bsp tree bounding box 525 526 PolygonContainer *polys = new PolygonContainer(); 527 528 // copy mesh instance polygons into one big polygon soup 529 mStat.polys = AddToPolygonSoup(objects, *polys); 530 531 // construct tree from polygon soup 532 Construct(polys, new BoundedRayContainer()); 533 } 534 535 void BspTree::Construct(const RayContainer &sampleRays) 536 { 537 mStat.nodes = 1; 538 mBox.Initialize(); // initialise BSP tree bounding box 539 540 PolygonContainer *polys = new PolygonContainer(); 541 BoundedRayContainer *rays = new BoundedRayContainer(); 542 543 RayContainer::const_iterator rit, rit_end = sampleRays.end(); 544 545 long startTime = GetTime(); 546 547 Debug << "**** Extracting polygons from rays ****\n"; 548 549 std::map<Face *, Polygon3 *> facePolyMap; 550 551 //-- extract polygons intersected by the rays 552 for (rit = sampleRays.begin(); rit != rit_end; ++ rit) 553 { 554 Ray *ray = *rit; 555 556 // get ray-face intersection. Store polygon representing the rays together 557 // with rays intersecting the face. 558 if (!ray->intersections.empty()) 559 { 560 MeshInstance *obj = dynamic_cast<MeshInstance *>(ray->intersections[0].mObject); 561 Face *face = obj->GetMesh()->mFaces[ray->intersections[0].mFace]; 562 563 std::map<Face *, Polygon3 *>::iterator it = facePolyMap.find(face); 564 565 if (it != facePolyMap.end()) 566 { 567 //store rays if needed for heuristics 568 if (mSplitPlaneStrategy & BLOCKED_RAYS) 569 (*it).second->mPiercingRays.push_back(ray); 570 } 571 else 572 { //store rays if needed for heuristics 573 Polygon3 *poly = new Polygon3(face, obj->GetMesh()); 574 poly->mParent = obj; 575 polys->push_back(poly); 576 577 if (mSplitPlaneStrategy & BLOCKED_RAYS) 578 poly->mPiercingRays.push_back(ray); 579 580 facePolyMap[face] = poly; 581 } 582 } 583 } 584 585 facePolyMap.clear(); 586 587 // compue bounding box 588 Polygon3::IncludeInBox(*polys, mBox); 589 590 //-- store rays 591 for (rit = sampleRays.begin(); rit != rit_end; ++ rit) 592 { 593 Ray *ray = *rit; 594 ray->SetId(-1); // reset id 595 596 float minT, maxT; 597 if (BoundRay(*ray, minT, maxT)) 598 rays->push_back(new BoundedRay(ray, minT, maxT)); 599 } 600 601 mStat.polys = (int)polys->size(); 602 603 Debug << "**** Finished polygon extraction ****" << endl; 604 Debug << (int)polys->size() << " polys extracted from " << (int)sampleRays.size() << " rays" << endl; 605 Debug << "extraction time: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl; 606 607 Construct(polys, rays); 608 } 609 610 void BspTree::Construct(PolygonContainer *polys, BoundedRayContainer *rays) 611 { 612 std::stack<BspTraversalData> tStack; 613 614 mRoot = new BspLeaf(); 615 616 BspNodeGeometry *cell = new BspNodeGeometry(); 617 ConstructGeometry(mRoot, *cell); 618 619 BspTraversalData tData(mRoot, polys, 0, mRootCell, rays, 620 ComputePvsSize(*rays), cell->GetArea(), cell); 621 622 tStack.push(tData); 623 624 mStat.Start(); 625 cout << "**** Contructing bsp tree ****\n"; 626 627 while (!tStack.empty()) 628 { 629 tData = tStack.top(); 630 tStack.pop(); 631 632 // subdivide leaf node 633 BspNode *subRoot = Subdivide(tStack, tData); 634 } 635 636 mStat.Stop(); 637 } 638 639 bool BspTree::TerminationCriteriaMet(const BspTraversalData &data) const 640 { 641 return 642 (((int)data.mPolygons->size() <= mTermMaxPolygons) || 643 ((int)data.mRays->size() <= mTermMaxRays) || 644 (data.mPvs <= mTermMinPvs) || 645 (data.mArea <= mTermMinArea) || 646 (data.mDepth >= mTermMaxDepth) || 647 (((float)data.mPvs / ((float)data.mRays->size() + Limits::Small)) < 648 mTermMaxRayContribution)); 649 } 650 651 BspNode *BspTree::Subdivide(BspTraversalStack &tStack, BspTraversalData &tData) 652 { 653 //-- terminate traversal 654 if (TerminationCriteriaMet(tData)) 655 { 656 BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode); 657 658 BspViewCell *viewCell; 659 660 // generate new view cell for each leaf 661 if (mGenerateViewCells) 662 { 663 viewCell = dynamic_cast<BspViewCell *>(ViewCell::Generate()); 664 } 665 else 666 { 667 // add view cell to leaf 668 viewCell = dynamic_cast<BspViewCell *>(tData.mViewCell); 669 } 670 671 leaf->SetViewCell(viewCell); 672 viewCell->mBspLeaves.push_back(leaf); 673 674 //-- add pvs 675 if (viewCell != mRootCell) 676 { 677 int conSamp = 0, sampCon = 0; 678 leaf->AddToPvs(*tData.mRays, conSamp, sampCon); 679 680 mStat.contributingSamples += conSamp; 681 mStat.sampleContributions += sampCon; 682 } 683 684 EvaluateLeafStats(tData); 685 686 //-- clean up 687 688 // discard polygons 689 CLEAR_CONTAINER(*tData.mPolygons); 690 // discard rays 691 CLEAR_CONTAINER(*tData.mRays); 692 693 DEL_PTR(tData.mPolygons); 694 DEL_PTR(tData.mRays); 695 DEL_PTR(tData.mGeometry); 696 697 return leaf; 698 } 699 700 //-- continue subdivision 701 PolygonContainer coincident; 702 703 PolygonContainer *frontPolys = new PolygonContainer(); 704 PolygonContainer *backPolys = new PolygonContainer(); 705 706 BoundedRayContainer *frontRays = new BoundedRayContainer(); 707 BoundedRayContainer *backRays = new BoundedRayContainer(); 708 709 BspTraversalData tFrontData(NULL, new PolygonContainer(), tData.mDepth + 1, mRootCell, 710 new BoundedRayContainer(), 0, 0, new BspNodeGeometry()); 711 BspTraversalData tBackData(NULL, new PolygonContainer(), tData.mDepth + 1, mRootCell, 712 new BoundedRayContainer(), 0, 0, new BspNodeGeometry()); 713 714 // create new interior node and two leaf nodes 715 BspInterior *interior = SubdivideNode(tData, 716 tFrontData, 717 tBackData, 718 coincident); 719 720 #ifdef _DEBUG 721 if (frontPolys->empty() && backPolys->empty() && (coincident.size() > 2)) 722 { for (PolygonContainer::iterator it = coincident.begin(); it != coincident.end(); ++it) 723 Debug << (*it) << " " << (*it)->GetArea() << " " << (*it)->mParent << endl ; 724 Debug << endl;} 725 #endif 726 727 // extract view cells from coincident polygons according to plane normal 728 // only if front or back polygons are empty 729 if (!mGenerateViewCells) 730 { 731 ExtractViewCells(tFrontData, 732 tBackData, 733 coincident, 734 interior->mPlane); 735 736 } 737 738 // don't need coincident polygons anymory 739 CLEAR_CONTAINER(coincident); 740 741 // push the children on the stack 742 tStack.push(tFrontData); 743 tStack.push(tBackData); 744 745 // cleanup 746 DEL_PTR(tData.mNode); 747 DEL_PTR(tData.mPolygons); 748 DEL_PTR(tData.mRays); 749 DEL_PTR(tData.mGeometry); 750 751 return interior; 752 } 753 754 void BspTree::ExtractViewCells(BspTraversalData &frontData, 755 BspTraversalData &backData, 756 const PolygonContainer &coincident, 757 const Plane3 splitPlane) const 758 { 759 // if not empty, tree is further subdivided => don't have to find view cell 760 bool foundFront = !frontData.mPolygons->empty(); 761 bool foundBack = !frontData.mPolygons->empty(); 762 763 PolygonContainer::const_iterator it = 764 coincident.begin(), it_end = coincident.end(); 765 766 //-- find first view cells in front and back leafs 767 for (; !(foundFront && foundBack) && (it != it_end); ++ it) 768 { 769 if (DotProd((*it)->GetNormal(), splitPlane.mNormal) > 0) 770 { 771 backData.mViewCell = dynamic_cast<ViewCell *>((*it)->mParent); 772 foundBack = true; 773 } 774 else 775 { 776 frontData.mViewCell = dynamic_cast<ViewCell *>((*it)->mParent); 777 foundFront = true; 778 } 779 } 780 } 781 782 BspInterior *BspTree::SubdivideNode(BspTraversalData &tData, 783 BspTraversalData &frontData, 784 BspTraversalData &backData, 785 PolygonContainer &coincident) 786 { 787 mStat.nodes += 2; 788 789 BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode); 790 // select subdivision plane 791 BspInterior *interior = 792 new BspInterior(SelectPlane(leaf, tData)); 793 794 #ifdef _DEBUG 795 Debug << interior << endl; 796 #endif 797 798 // subdivide rays into front and back rays 799 SplitRays(interior->mPlane, *tData.mRays, *frontData.mRays, *backData.mRays); 800 801 // subdivide polygons with plane 802 mStat.splits += interior->SplitPolygons(*tData.mPolygons, 803 *frontData.mPolygons, 804 *backData.mPolygons, 805 coincident); 806 807 // compute pvs 808 frontData.mPvs = ComputePvsSize(*frontData.mRays); 809 backData.mPvs = ComputePvsSize(*backData.mRays); 810 811 // split geometry and compute area 812 if (1) 813 { 814 tData.mGeometry->SplitGeometry(*frontData.mGeometry, 815 *backData.mGeometry, 816 *this, 817 interior->mPlane); 818 819 820 frontData.mArea = frontData.mGeometry->GetArea(); 821 backData.mArea = backData.mGeometry->GetArea(); 822 } 823 824 // compute accumulated ray length 825 //frontData.mAccRayLength = AccumulatedRayLength(*frontData.mRays); 826 //backData.mAccRayLength = AccumulatedRayLength(*backData.mRays); 827 828 //-- create front and back leaf 829 830 BspInterior *parent = leaf->GetParent(); 831 832 // replace a link from node's parent 833 if (!leaf->IsRoot()) 834 { 835 parent->ReplaceChildLink(leaf, interior); 836 interior->SetParent(parent); 837 } 838 else // new root 839 { 840 mRoot = interior; 841 } 842 843 // and setup child links 844 interior->SetupChildLinks(new BspLeaf(interior), new BspLeaf(interior)); 845 846 frontData.mNode = interior->mFront; 847 backData.mNode = interior->mBack; 848 849 //DEL_PTR(leaf); 850 return interior; 851 } 852 853 void BspTree::SortSplitCandidates(const PolygonContainer &polys, 854 const int axis, 855 vector<SortableEntry> &splitCandidates) const 856 { 857 splitCandidates.clear(); 858 859 int requestedSize = 2 * (int)polys.size(); 860 // creates a sorted split candidates array 861 splitCandidates.reserve(requestedSize); 862 863 PolygonContainer::const_iterator it, it_end = polys.end(); 864 865 AxisAlignedBox3 box; 866 867 // insert all queries 868 for(it = polys.begin(); it != it_end; ++ it) 869 { 870 box.Initialize(); 871 box.Include(*(*it)); 872 873 splitCandidates.push_back(SortableEntry(SortableEntry::POLY_MIN, box.Min(axis), *it)); 874 splitCandidates.push_back(SortableEntry(SortableEntry::POLY_MAX, box.Max(axis), *it)); 875 } 876 877 stable_sort(splitCandidates.begin(), splitCandidates.end()); 878 } 879 880 881 float BspTree::BestCostRatio(const PolygonContainer &polys, 882 const AxisAlignedBox3 &box, 883 const int axis, 884 float &position, 885 int &objectsBack, 886 int &objectsFront) const 887 { 888 vector<SortableEntry> splitCandidates; 889 890 SortSplitCandidates(polys, axis, splitCandidates); 891 892 // go through the lists, count the number of objects left and right 893 // and evaluate the following cost funcion: 894 // C = ct_div_ci + (ol + or)/queries 895 896 int objectsLeft = 0, objectsRight = (int)polys.size(); 897 898 float minBox = box.Min(axis); 899 float maxBox = box.Max(axis); 900 float boxArea = box.SurfaceArea(); 901 902 float minBand = minBox + mSplitBorder * (maxBox - minBox); 903 float maxBand = minBox + (1.0f - mSplitBorder) * (maxBox - minBox); 904 905 float minSum = 1e20f; 906 vector<SortableEntry>::const_iterator ci, ci_end = splitCandidates.end(); 907 908 for(ci = splitCandidates.begin(); ci != ci_end; ++ ci) 909 { 910 switch ((*ci).type) 911 { 912 case SortableEntry::POLY_MIN: 913 ++ objectsLeft; 914 break; 915 case SortableEntry::POLY_MAX: 916 -- objectsRight; 917 break; 918 default: 919 break; 920 } 921 922 if ((*ci).value > minBand && (*ci).value < maxBand) 923 { 924 AxisAlignedBox3 lbox = box; 925 AxisAlignedBox3 rbox = box; 926 lbox.SetMax(axis, (*ci).value); 927 rbox.SetMin(axis, (*ci).value); 928 929 float sum = objectsLeft * lbox.SurfaceArea() + 930 objectsRight * rbox.SurfaceArea(); 931 932 if (sum < minSum) 933 { 934 minSum = sum; 935 position = (*ci).value; 936 937 objectsBack = objectsLeft; 938 objectsFront = objectsRight; 939 } 940 } 941 } 942 943 float oldCost = (float)polys.size(); 944 float newCost = mCt_div_ci + minSum / boxArea; 945 float ratio = newCost / oldCost; 946 947 948 #if 0 949 Debug << "====================" << endl; 950 Debug << "costRatio=" << ratio << " pos=" << position<<" t=" << (position - minBox)/(maxBox - minBox) 951 << "\t o=(" << objectsBack << "," << objectsFront << ")" << endl; 952 #endif 953 return ratio; 954 } 955 956 bool BspTree::SelectAxisAlignedPlane(Plane3 &plane, 957 const PolygonContainer &polys) const 958 { 959 AxisAlignedBox3 box; 960 box.Initialize(); 961 962 // create bounding box of region 963 Polygon3::IncludeInBox(polys, box); 964 965 int objectsBack = 0, objectsFront = 0; 966 int axis = 0; 967 float costRatio = MAX_FLOAT; 968 Vector3 position; 969 970 //-- area subdivision 971 for (int i = 0; i < 3; ++ i) 972 { 973 float p = 0; 974 float r = BestCostRatio(polys, box, i, p, objectsBack, objectsFront); 975 976 if (r < costRatio) 977 { 978 costRatio = r; 979 axis = i; 980 position = p; 981 } 982 } 983 984 if (costRatio >= mMaxCostRatio) 985 return false; 986 987 Vector3 norm(0,0,0); norm[axis] = 1.0f; 988 plane = Plane3(norm, position); 989 990 return true; 991 } 992 993 Plane3 BspTree::SelectPlane(BspLeaf *leaf, BspTraversalData &data) 994 { 995 if (data.mPolygons->empty() && data.mRays->empty()) 996 { 997 Debug << "Warning: No autopartition polygon candidate available\n"; 998 999 // return axis aligned split 1000 AxisAlignedBox3 box; 1001 box.Initialize(); 1002 1003 // create bounding box of region 1004 Polygon3::IncludeInBox(*data.mPolygons, box); 1005 1006 const int axis = box.Size().DrivingAxis(); 1007 const Vector3 position = (box.Min()[axis] + box.Max()[axis])*0.5f; 1008 1009 Vector3 norm(0,0,0); norm[axis] = 1.0f; 1010 return Plane3(norm, position); 1011 } 1012 1013 if ((mSplitPlaneStrategy & AXIS_ALIGNED) && 1014 ((int)data.mPolygons->size() > mTermMaxPolysForAxisAligned) && 1015 ((int)data.mRays->size() > mTermMaxRaysForAxisAligned) && 1016 ((mTermMaxObjectsForAxisAligned < 0) || 1017 (Polygon3::ParentObjectsSize(*data.mPolygons) > mTermMaxObjectsForAxisAligned))) 1018 { 1019 Plane3 plane; 1020 if (SelectAxisAlignedPlane(plane, *data.mPolygons)) 1021 return plane; 1022 } 1023 1024 // simplest strategy: just take next polygon 1025 if (mSplitPlaneStrategy & RANDOM_POLYGON) 1026 { 1027 if (!data.mPolygons->empty()) 1028 { 1029 Polygon3 *nextPoly = (*data.mPolygons)[Random((int)data.mPolygons->size())]; 1030 return nextPoly->GetSupportingPlane(); 1031 } 1032 else 1033 { 1034 const int candidateIdx = Random((int)data.mRays->size()); 1035 BoundedRay *bRay = (*data.mRays)[candidateIdx]; 1036 1037 Ray *ray = bRay->mRay; 1038 1039 const Vector3 minPt = ray->Extrap(bRay->mMinT); 1040 const Vector3 maxPt = ray->Extrap(bRay->mMaxT); 1041 1042 const Vector3 pt = (maxPt + minPt) * 0.5; 1043 1044 const Vector3 normal = ray->GetDir(); 1045 1046 return Plane3(normal, pt); 1047 } 1048 1049 return Plane3(); 1050 } 1051 1052 // use heuristics to find appropriate plane 1053 return SelectPlaneHeuristics(leaf, data); 1054 } 1055 1056 Plane3 BspTree::SelectPlaneHeuristics(BspLeaf *leaf, BspTraversalData &data) 1057 { 1058 float lowestCost = MAX_FLOAT; 1059 Plane3 bestPlane; 1060 Plane3 plane; 1061 1062 int limit = Min((int)data.mPolygons->size(), mMaxPolyCandidates); 1063 1064 int candidateIdx = limit; 1065 1066 for (int i = 0; i < limit; ++ i) 1067 { 1068 candidateIdx = GetNextCandidateIdx(candidateIdx, *data.mPolygons); 1069 1070 Polygon3 *poly = (*data.mPolygons)[candidateIdx]; 1071 // evaluate current candidate 1072 const float candidateCost = 1073 SplitPlaneCost(poly->GetSupportingPlane(), data); 1074 1075 if (candidateCost < lowestCost) 1076 { 1077 bestPlane = poly->GetSupportingPlane(); 1078 lowestCost = candidateCost; 1079 } 1080 } 1081 1082 //Debug << "lowest: " << lowestCost << endl; 1083 1084 //-- choose candidate planes extracted from rays 1085 // we currently use two methods 1086 // 1) take 3 ray endpoints, where two are minimum and one a maximum 1087 // point or the other way round 1088 // 2) take plane normal as plane normal and the midpoint of the ray. 1089 // PROBLEM: does not resemble any point where visibility is likely to change 1090 const BoundedRayContainer *rays = data.mRays; 1091 1092 for (int i = 0; i < mMaxRayCandidates / 2; ++ i) 1093 { 1094 candidateIdx = Random((int)rays->size()); 1095 BoundedRay *bRay = (*rays)[candidateIdx]; 1096 1097 Ray *ray = bRay->mRay; 1098 1099 const Vector3 minPt = ray->Extrap(bRay->mMinT); 1100 const Vector3 maxPt = ray->Extrap(bRay->mMaxT); 1101 1102 const Vector3 pt = (maxPt + minPt) * 0.5; 1103 1104 const Vector3 normal = ray->GetDir(); 1105 1106 plane = Plane3(normal, pt); 1107 1108 const float candidateCost = SplitPlaneCost(plane, data); 1109 1110 if (candidateCost < lowestCost) 1111 { 1112 bestPlane = plane; 1113 1114 lowestCost = candidateCost; 1115 } 1116 } 1117 1118 //Debug << "lowest: " << lowestCost << endl; 1119 for (int i = 0; i < mMaxRayCandidates / 2; ++ i) 1120 { 1121 Vector3 pt[3]; 1122 int idx[3]; 1123 int cmaxT = 0; 1124 int cminT = 0; 1125 bool chooseMin = false; 1126 1127 for (int j = 0; j < 3; j ++) 1128 { 1129 idx[j] = Random((int)rays->size() * 2); 1130 1131 if (idx[j] >= (int)rays->size()) 1132 { 1133 idx[j] -= (int)rays->size(); 1134 1135 chooseMin = (cminT < 2); 1136 } 1137 else 1138 chooseMin = (cmaxT < 2); 1139 1140 BoundedRay *bRay = (*rays)[idx[j]]; 1141 pt[j] = chooseMin ? bRay->mRay->Extrap(bRay->mMinT) : bRay->mRay->Extrap(bRay->mMaxT); 1142 } 1143 1144 plane = Plane3(pt[0], pt[1], pt[2]); 1145 1146 const float candidateCost = SplitPlaneCost(plane, data); 1147 1148 if (candidateCost < lowestCost) 1149 { 1150 //Debug << "choose ray plane 2: " << candidateCost << endl; 1151 bestPlane = plane; 1152 1153 lowestCost = candidateCost; 1154 } 1155 } 1156 1157 #ifdef _DEBUG 1158 Debug << "plane lowest cost: " << lowestCost << endl; 1159 #endif 1160 return bestPlane; 1161 } 1162 1163 int BspTree::GetNextCandidateIdx(int currentIdx, PolygonContainer &polys) 1164 { 1165 const int candidateIdx = Random(currentIdx --); 1166 1167 // swap candidates to avoid testing same plane 2 times 1168 std::swap(polys[currentIdx], polys[candidateIdx]); 1169 1170 return currentIdx; 1171 //return Random((int)polys.size()); 1172 } 1173 1174 float BspTree::SplitPlaneCost(const Plane3 &candidatePlane, 1175 const PolygonContainer &polys) const 1176 { 1177 float val = 0; 1178 1179 float sumBalancedPolys = 0; 1180 float sumSplits = 0; 1181 float sumPolyArea = 0; 1182 float sumBalancedViewCells = 0; 1183 float sumBlockedRays = 0; 1184 float totalBlockedRays = 0; 1185 //float totalArea = 0; 1186 int totalViewCells = 0; 1187 1188 // need three unique ids for each type of view cell 1189 // for balanced view cells criterium 1190 ViewCell::NewMail(); 1191 const int backId = ViewCell::sMailId; 1192 ViewCell::NewMail(); 1193 const int frontId = ViewCell::sMailId; 1194 ViewCell::NewMail(); 1195 const int frontAndBackId = ViewCell::sMailId; 1196 1197 PolygonContainer::const_iterator it, it_end = polys.end(); 1198 1199 for (it = polys.begin(); it != it_end; ++ it) 1200 { 1201 const int classification = (*it)->ClassifyPlane(candidatePlane); 1202 1203 if (mSplitPlaneStrategy & BALANCED_POLYS) 1204 sumBalancedPolys += sBalancedPolysTable[classification]; 1205 1206 if (mSplitPlaneStrategy & LEAST_SPLITS) 1207 sumSplits += sLeastPolySplitsTable[classification]; 1208 1209 if (mSplitPlaneStrategy & LARGEST_POLY_AREA) 1210 { 1211 if (classification == Polygon3::COINCIDENT) 1212 sumPolyArea += (*it)->GetArea(); 1213 //totalArea += area; 1214 } 1215 1216 if (mSplitPlaneStrategy & BLOCKED_RAYS) 1217 { 1218 const float blockedRays = (float)(*it)->mPiercingRays.size(); 1219 1220 if (classification == Polygon3::COINCIDENT) 1221 sumBlockedRays += blockedRays; 1222 1223 totalBlockedRays += blockedRays; 1224 } 1225 1226 // assign view cells to back or front according to classificaion 1227 if (mSplitPlaneStrategy & BALANCED_VIEW_CELLS) 1228 { 1229 MeshInstance *viewCell = (*it)->mParent; 1230 1231 // assure that we only count a view cell 1232 // once for the front and once for the back side of the plane 1233 if (classification == Polygon3::FRONT_SIDE) 1234 { 1235 if ((viewCell->mMailbox != frontId) && 1236 (viewCell->mMailbox != frontAndBackId)) 1237 { 1238 sumBalancedViewCells += 1.0; 1239 1240 if (viewCell->mMailbox != backId) 1241 viewCell->mMailbox = frontId; 1242 else 1243 viewCell->mMailbox = frontAndBackId; 1244 1245 ++ totalViewCells; 1246 } 1247 } 1248 else if (classification == Polygon3::BACK_SIDE) 1249 { 1250 if ((viewCell->mMailbox != backId) && 1251 (viewCell->mMailbox != frontAndBackId)) 1252 { 1253 sumBalancedViewCells -= 1.0; 1254 1255 if (viewCell->mMailbox != frontId) 1256 viewCell->mMailbox = backId; 1257 else 1258 viewCell->mMailbox = frontAndBackId; 1259 1260 ++ totalViewCells; 1261 } 1262 } 1263 } 1264 } 1265 1266 const float polysSize = (float)polys.size() + Limits::Small; 1267 1268 // all values should be approx. between 0 and 1 so they can be combined 1269 // and scaled with the factors according to their importance 1270 if (mSplitPlaneStrategy & BALANCED_POLYS) 1271 val += sBalancedPolysFactor * fabs(sumBalancedPolys) / polysSize; 1272 1273 if (mSplitPlaneStrategy & LEAST_SPLITS) 1274 val += sLeastSplitsFactor * sumSplits / polysSize; 1275 1276 if (mSplitPlaneStrategy & LARGEST_POLY_AREA) 1277 // HACK: polys.size should be total area so scaling is between 0 and 1 1278 val += sLargestPolyAreaFactor * (float)polys.size() / sumPolyArea; 1279 1280 if (mSplitPlaneStrategy & BLOCKED_RAYS) 1281 if (totalBlockedRays != 0) 1282 val += sBlockedRaysFactor * (totalBlockedRays - sumBlockedRays) / totalBlockedRays; 1283 1284 if (mSplitPlaneStrategy & BALANCED_VIEW_CELLS) 1285 val += sBalancedViewCellsFactor * fabs(sumBalancedViewCells) / 1286 ((float)totalViewCells + Limits::Small); 1287 1288 return val; 1289 } 1290 1291 bool BspTree::BoundRay(const Ray &ray, float &minT, float &maxT) const 1292 { 1293 maxT = 1e6; 1294 minT = 0; 1295 1296 // test with tree bounding box 1297 if (!mBox.GetMinMaxT(ray, &minT, &maxT)) 1298 return false; 1299 1300 if (minT < 0) // start ray from origin 1301 minT = 0; 1302 1303 // bound ray or line segment 1304 if ((ray.GetType() == Ray::LOCAL_RAY) && 1305 !ray.intersections.empty() && 1306 (ray.intersections[0].mT <= maxT)) 1307 { 1308 maxT = ray.intersections[0].mT; 1309 } 1310 1311 return true; 1312 } 1313 1314 float BspTree::SplitPlaneCost(const Plane3 &candidatePlane, 1315 const BoundedRayContainer &rays, 1316 const int pvs, 1317 const float area, 1318 const BspNodeGeometry &cell) const 1319 { 1320 float val = 0; 1321 1322 float sumBalancedRays = 0; 1323 float sumRaySplits = 0; 1324 1325 int backId = 0; 1326 int frontId = 0; 1327 int frontAndBackId = 0; 1328 1329 int frontPvs = 0; 1330 int backPvs = 0; 1331 1332 // probability that view point lies in child 1333 float pOverall = 0; 1334 float pFront = 0; 1335 float pBack = 0; 1336 1337 if (mSplitPlaneStrategy & PVS) 1338 { 1339 // create three unique ids for pvs heuristics 1340 Intersectable::NewMail(); backId = ViewCell::sMailId; 1341 Intersectable::NewMail(); frontId = ViewCell::sMailId; 1342 Intersectable::NewMail(); frontAndBackId = ViewCell::sMailId; 1343 1344 if (mPvsUseArea) // use front and back cell areas to approximate volume 1345 { 1346 // construct child geometry with regard to the candidate split plane 1347 BspNodeGeometry frontCell; 1348 BspNodeGeometry backCell; 1349 1350 cell.SplitGeometry(frontCell, backCell, *this, candidatePlane); 1351 1352 pFront = frontCell.GetArea(); 1353 pBack = backCell.GetArea(); 1354 1355 pOverall = area; 1356 } 1357 } 1358 1359 BoundedRayContainer::const_iterator rit, rit_end = rays.end(); 1360 1361 for (rit = rays.begin(); rit != rays.end(); ++ rit) 1362 { 1363 Ray *ray = (*rit)->mRay; 1364 const float minT = (*rit)->mMinT; 1365 const float maxT = (*rit)->mMaxT; 1366 1367 Vector3 entP, extP; 1368 1369 const int cf = 1370 ray->ClassifyPlane(candidatePlane, minT, maxT, entP, extP); 1371 1372 if (mSplitPlaneStrategy & LEAST_RAY_SPLITS) 1373 { 1374 sumBalancedRays += sBalancedRaysTable[cf]; 1375 } 1376 1377 if (mSplitPlaneStrategy & BALANCED_RAYS) 1378 { 1379 sumRaySplits += sLeastRaySplitsTable[cf]; 1380 } 1381 1382 if (mSplitPlaneStrategy & PVS) 1383 { 1384 if (!ray->intersections.empty()) 1385 { 1386 // in case the ray intersects an objcrs 1387 // assure that we only count a object 1388 // once for the front and once for the back side of the plane 1389 IncPvs(*ray->intersections[0].mObject, frontPvs, backPvs, 1390 cf, frontId, backId, frontAndBackId); 1391 } 1392 1393 // the source object in the origin of the ray 1394 if (ray->sourceObject.mObject) 1395 { 1396 IncPvs(*ray->sourceObject.mObject, frontPvs, backPvs, 1397 cf, frontId, backId, frontAndBackId); 1398 } 1399 1400 if (!mPvsUseArea) // use front and back cell areas to approximate volume 1401 { 1402 float len = Distance(entP, extP); 1403 pOverall += len; 1404 1405 // use length of rays to approximate volume 1406 switch (cf) 1407 { 1408 case Ray::COINCIDENT: 1409 pBack += len; 1410 pFront += len; 1411 break; 1412 case Ray::BACK: 1413 pBack += len; 1414 break; 1415 case Ray::FRONT: 1416 pFront += len; 1417 break; 1418 case Ray::FRONT_BACK: 1419 { 1420 // find intersection of ray segment with plane 1421 const Vector3 extp = ray->Extrap(maxT); 1422 const float t = candidatePlane.FindT(ray->GetLoc(), extp); 1423 1424 const float newT = t * maxT; 1425 float newLen = Distance(ray->Extrap(newT), extp); 1426 1427 pFront += len - newLen; 1428 pBack += newLen; 1429 } 1430 break; 1431 case Ray::BACK_FRONT: 1432 { 1433 // find intersection of ray segment with plane 1434 const Vector3 extp = ray->Extrap(maxT); 1435 const float t = candidatePlane.FindT(ray->GetLoc(), extp); 1436 1437 const float newT = t * maxT; 1438 float newLen = Distance(ray->Extrap(newT), extp); 1439 1440 pFront += len; 1441 pBack += len - newLen; 1442 } 1443 break; 1444 default: 1445 Debug << "Should not come here" << endl; 1446 break; 1447 } 1448 } 1449 } 1450 } 1451 1452 const float raysSize = (float)rays.size() + Limits::Small; 1453 if (mSplitPlaneStrategy & LEAST_RAY_SPLITS) 1454 val += sLeastRaySplitsFactor * sumRaySplits / raysSize; 1455 1456 if (mSplitPlaneStrategy & BALANCED_RAYS) 1457 val += sBalancedRaysFactor * fabs(sumBalancedRays) / raysSize; 1458 1459 float denom = pOverall * (float)pvs * 2.0f + Limits::Small; 1460 if ((mSplitPlaneStrategy & PVS) && area && pvs) 1461 { 1462 val += sPvsFactor * (frontPvs * pFront + (backPvs * pBack)) / denom; 1463 1464 // give penalty to unbalanced split 1465 if (0) 1466 if (((pFront * 0.2 + Limits::Small) > pBack) || (pFront < (pBack * 0.2 + Limits::Small))) 1467 val += 0.5; 1468 } 1469 1470 #ifdef _DEBUG 1471 Debug << "totalpvs: " << pvs << " ptotal: " << pOverall 1472 << " frontpvs: " << frontPvs << " pFront: " << pFront 1473 << " backpvs: " << backPvs << " pBack: " << pBack << endl << endl; 1474 #endif 1475 return val; 1476 } 1477 1478 void BspTree::IncPvs(Intersectable &obj, 1479 int &frontPvs, 1480 int &backPvs, 1481 const int cf, 1482 const int frontId, 1483 const int backId, 1484 const int frontAndBackId) const 1485 { 1486 // TODO: does this really belong to no pvs? 1487 //if (cf == Ray::COINCIDENT) return; 1488 1489 if (cf == Ray::FRONT) 1490 { 1491 if ((obj.mMailbox != frontId) && 1492 (obj.mMailbox != frontAndBackId)) 1493 { 1494 ++ frontPvs; 1495 1496 if (obj.mMailbox != backId) 1497 obj.mMailbox = frontId; 1498 else 1499 obj.mMailbox = frontAndBackId; 1500 } 1501 } 1502 else if (cf == Ray::BACK) 1503 { 1504 if ((obj.mMailbox != backId) && 1505 (obj.mMailbox != frontAndBackId)) 1506 { 1507 ++ backPvs; 1508 1509 if (obj.mMailbox != frontId) 1510 obj.mMailbox = backId; 1511 else 1512 obj.mMailbox = frontAndBackId; 1513 } 1514 } 1515 // object belongs to both PVS 1516 else if ((cf == Ray::FRONT_BACK) || (cf == Ray::BACK_FRONT) ||(cf == Ray::COINCIDENT)) 1517 { 1518 if (obj.mMailbox != frontAndBackId) 1519 { 1520 if (obj.mMailbox != frontId) 1521 ++ frontPvs; 1522 if (obj.mMailbox != backId) 1523 ++ backPvs; 1524 1525 obj.mMailbox = frontAndBackId; 1526 } 1527 } 1528 } 1529 1530 float BspTree::SplitPlaneCost(const Plane3 &candidatePlane, 1531 BspTraversalData &data) const 1532 { 1533 float val = 0; 1534 1535 if (mSplitPlaneStrategy & VERTICAL_AXIS) 1536 { 1537 Vector3 tinyAxis(0,0,0); tinyAxis[mBox.Size().TinyAxis()] = 1.0f; 1538 // we put a penalty on the dot product between the "tiny" vertical axis 1539 // and the split plane axis 1540 val += sVerticalSplitsFactor * 1541 fabs(DotProd(candidatePlane.mNormal, tinyAxis)); 1542 } 1543 1544 // the following criteria loop over all polygons to find the cost value 1545 if ((mSplitPlaneStrategy & BALANCED_POLYS) || 1546 (mSplitPlaneStrategy & LEAST_SPLITS) || 1547 (mSplitPlaneStrategy & LARGEST_POLY_AREA) || 1548 (mSplitPlaneStrategy & BALANCED_VIEW_CELLS) || 1549 (mSplitPlaneStrategy & BLOCKED_RAYS)) 1550 { 1551 val += SplitPlaneCost(candidatePlane, *data.mPolygons); 1552 } 1553 1554 // the following criteria loop over all rays to find the cost value 1555 if ((mSplitPlaneStrategy & BALANCED_RAYS) || 1556 (mSplitPlaneStrategy & LEAST_RAY_SPLITS) || 1557 (mSplitPlaneStrategy & PVS)) 1558 { 1559 val += SplitPlaneCost(candidatePlane, *data.mRays, data.mPvs, 1560 data.mArea, *data.mGeometry); 1561 } 1562 1563 // return linear combination of the sums 1564 return val; 1565 } 1566 1567 void BspTree::ParseEnvironment() 1568 { 1569 //-- parse bsp cell tree construction method 1570 /*char constructionMethodStr[60]; 1571 1572 environment->GetStringValue("BspTree.Construction.input", constructionMethodStr); 1573 1574 mConstructionMethod = FROM_INPUT_VIEW_CELLS; 1575 1576 if (strcmp(constructionMethodStr, "fromViewCells") == 0) 1577 mConstructionMethod = FROM_INPUT_VIEW_CELLS; 1578 else if (strcmp(constructionMethodStr, "fromSceneGeometry") == 0) 1579 mConstructionMethod = FROM_SCENE_GEOMETRY; 1580 else if (strcmp(constructionMethodStr, "fromRays") == 0) 1581 mConstructionMethod = FROM_RAYS; 1582 else 1583 { 1584 cerr << "Wrong construction method " << constructionMethodStr << endl; 1585 exit(1); 1586 } 1587 1588 Debug << "Construction method: " << constructionMethodStr << endl; 1589 */ 291 1590 292 //-- termination criteria for autopartition 1591 293 environment->GetIntValue("BspTree.Termination.maxDepth", mTermMaxDepth); … … 1651 353 if (mSplitPlaneStrategy & PVS) 1652 354 Debug << "pvs"; 355 1653 356 Debug << endl; 357 } 358 359 void BspTree::ParseEnvironment() 360 { 361 //-- parse bsp cell tree construction method 362 char constructionMethodStr[60]; 363 364 environment->GetStringValue("BspTree.Construction.input", constructionMethodStr); 365 366 sConstructionMethod = FROM_INPUT_VIEW_CELLS; 367 368 if (strcmp(constructionMethodStr, "fromViewCells") == 0) 369 sConstructionMethod = FROM_INPUT_VIEW_CELLS; 370 else if (strcmp(constructionMethodStr, "fromSceneGeometry") == 0) 371 sConstructionMethod = FROM_SCENE_GEOMETRY; 372 else if (strcmp(constructionMethodStr, "fromRays") == 0) 373 sConstructionMethod = FROM_RAYS; 374 else 375 { 376 cerr << "Wrong construction method " << constructionMethodStr << endl; 377 exit(1); 378 } 379 380 Debug << "Construction method: " << constructionMethodStr << endl; 381 } 382 383 const BspTreeStatistics &BspTree::GetStatistics() const 384 { 385 return mStat; 386 } 387 388 void BspTreeStatistics::Print(ostream &app) const 389 { 390 app << "===== BspTree statistics ===============\n"; 391 392 app << setprecision(4); 393 394 app << "#N_CTIME ( Construction time [s] )\n" << Time() << " \n"; 395 396 app << "#N_NODES ( Number of nodes )\n" << nodes << "\n"; 397 398 app << "#N_INTERIORS ( Number of interior nodes )\n" << Interior() << "\n"; 399 400 app << "#N_LEAVES ( Number of leaves )\n" << Leaves() << "\n"; 401 402 app << "#N_SPLITS ( Number of splits )\n" << splits << "\n"; 403 404 app << "#N_PMAXDEPTHLEAVES ( Percentage of leaves at maxdepth )\n"<< 405 maxDepthNodes * 100 / (double)Leaves() << endl; 406 407 app << "#N_PMAXDEPTH ( Maximal reached depth )\n" << maxDepth << endl; 408 409 app << "#N_PMINDEPTH ( Minimal reached depth )\n" << minDepth << endl; 410 411 app << "#AVGDEPTH ( average depth )\n" << AvgDepth() << endl; 412 413 app << "#N_INPUT_POLYGONS (number of input polygons )\n" << polys << endl; 414 415 //app << "#N_PVS: " << pvs << endl; 416 417 app << "#N_ROUTPUT_INPUT_POLYGONS ( ratio polygons after subdivision / input polygons )\n" << 418 (polys + splits) / (double)polys << endl; 419 420 app << "===== END OF BspTree statistics ==========\n"; 421 } 422 423 424 BspTree::~BspTree() 425 { 426 DEL_PTR(mRoot); 427 } 428 429 void BspTree::InsertViewCell(ViewCell *viewCell) 430 { 431 PolygonContainer *polys = new PolygonContainer(); 432 433 // extract polygons that guide the split process 434 mStat.polys += AddMeshToPolygons(viewCell->GetMesh(), *polys, viewCell); 435 mBox.Include(viewCell->GetBox()); // add to BSP aabb 436 437 InsertPolygons(polys); 438 } 439 440 void BspTree::InsertPolygons(PolygonContainer *polys) 441 { 442 std::stack<BspTraversalData> tStack; 443 444 // traverse existing tree or create new tree 445 if (!mRoot) 446 mRoot = new BspLeaf(); 447 448 tStack.push(BspTraversalData(mRoot, polys, 0, mRootCell, new BoundedRayContainer(), 0, 449 mBox.SurfaceArea(), new BspNodeGeometry())); 450 451 while (!tStack.empty()) 452 { 453 // filter polygons donw the tree 454 BspTraversalData tData = tStack.top(); 455 tStack.pop(); 456 457 if (!tData.mNode->IsLeaf()) 458 { 459 BspInterior *interior = dynamic_cast<BspInterior *>(tData.mNode); 460 461 //-- filter view cell polygons down the tree until a leaf is reached 462 if (!tData.mPolygons->empty()) 463 { 464 PolygonContainer *frontPolys = new PolygonContainer(); 465 PolygonContainer *backPolys = new PolygonContainer(); 466 PolygonContainer coincident; 467 468 int splits = 0; 469 470 // split viewcell polygons with respect to split plane 471 splits += interior->SplitPolygons(*tData.mPolygons, 472 *frontPolys, 473 *backPolys, 474 coincident); 475 476 // extract view cells associated with the split polygons 477 ViewCell *frontViewCell = mRootCell; 478 ViewCell *backViewCell = mRootCell; 479 480 BspTraversalData frontData(interior->GetFront(), 481 frontPolys, 482 tData.mDepth + 1, 483 mRootCell, 484 tData.mRays, 485 tData.mPvs, 486 mBox.SurfaceArea(), 487 new BspNodeGeometry()); 488 489 BspTraversalData backData(interior->GetBack(), 490 backPolys, 491 tData.mDepth + 1, 492 mRootCell, 493 tData.mRays, 494 tData.mPvs, 495 mBox.SurfaceArea(), 496 new BspNodeGeometry()); 497 498 if (!mGenerateViewCells) 499 { 500 ExtractViewCells(frontData, 501 backData, 502 coincident, 503 interior->mPlane); 504 } 505 506 // don't need coincident polygons anymore 507 CLEAR_CONTAINER(coincident); 508 509 mStat.splits += splits; 510 511 // push the children on the stack 512 tStack.push(frontData); 513 tStack.push(backData); 514 } 515 516 // cleanup 517 DEL_PTR(tData.mPolygons); 518 } 519 else 520 { 521 // reached leaf => subdivide current viewcell 522 BspNode *subRoot = Subdivide(tStack, tData); 523 } 524 } 525 } 526 527 int BspTree::AddMeshToPolygons(Mesh *mesh, PolygonContainer &polys, MeshInstance *parent) 528 { 529 FaceContainer::const_iterator fi; 530 531 // copy the face data to polygons 532 for (fi = mesh->mFaces.begin(); fi != mesh->mFaces.end(); ++ fi) 533 { 534 Polygon3 *poly = new Polygon3((*fi), mesh); 535 536 if (poly->Valid()) 537 { 538 poly->mParent = parent; // set parent intersectable 539 polys.push_back(poly); 540 } 541 else 542 DEL_PTR(poly); 543 } 544 return (int)mesh->mFaces.size(); 545 } 546 547 int BspTree::AddToPolygonSoup(const ViewCellContainer &viewCells, 548 PolygonContainer &polys, 549 int maxObjects) 550 { 551 int limit = (maxObjects > 0) ? 552 Min((int)viewCells.size(), maxObjects) : (int)viewCells.size(); 553 554 int polysSize = 0; 555 556 for (int i = 0; i < limit; ++ i) 557 { 558 if (viewCells[i]->GetMesh()) // copy the mesh data to polygons 559 { 560 mBox.Include(viewCells[i]->GetBox()); // add to BSP tree aabb 561 polysSize += AddMeshToPolygons(viewCells[i]->GetMesh(), polys, viewCells[i]); 562 } 563 } 564 565 return polysSize; 566 } 567 568 int BspTree::AddToPolygonSoup(const ObjectContainer &objects, PolygonContainer &polys, int maxObjects) 569 { 570 int limit = (maxObjects > 0) ? Min((int)objects.size(), maxObjects) : (int)objects.size(); 571 572 for (int i = 0; i < limit; ++i) 573 { 574 Intersectable *object = objects[i];//*it; 575 Mesh *mesh = NULL; 576 577 switch (object->Type()) // extract the meshes 578 { 579 case Intersectable::MESH_INSTANCE: 580 mesh = dynamic_cast<MeshInstance *>(object)->GetMesh(); 581 break; 582 case Intersectable::VIEW_CELL: 583 mesh = dynamic_cast<ViewCell *>(object)->GetMesh(); 584 break; 585 // TODO: handle transformed mesh instances 586 default: 587 Debug << "intersectable type not supported" << endl; 588 break; 589 } 590 591 if (mesh) // copy the mesh data to polygons 592 { 593 mBox.Include(object->GetBox()); // add to BSP tree aabb 594 AddMeshToPolygons(mesh, polys, mRootCell); 595 } 596 } 597 598 return (int)polys.size(); 599 } 600 601 void BspTree::Construct(const ViewCellContainer &viewCells) 602 { 603 mStat.nodes = 1; 604 mBox.Initialize(); // initialise bsp tree bounding box 605 606 // copy view cell meshes into one big polygon soup 607 PolygonContainer *polys = new PolygonContainer(); 608 mStat.polys = AddToPolygonSoup(viewCells, *polys); 609 610 // construct tree from the view cell polygons 611 Construct(polys, new BoundedRayContainer()); 612 } 613 614 615 void BspTree::Construct(const ObjectContainer &objects) 616 { 617 mStat.nodes = 1; 618 mBox.Initialize(); // initialise bsp tree bounding box 619 620 PolygonContainer *polys = new PolygonContainer(); 621 622 // copy mesh instance polygons into one big polygon soup 623 mStat.polys = AddToPolygonSoup(objects, *polys); 624 625 // construct tree from polygon soup 626 Construct(polys, new BoundedRayContainer()); 627 } 628 629 void BspTree::Construct(const RayContainer &sampleRays) 630 { 631 mStat.nodes = 1; 632 mBox.Initialize(); // initialise BSP tree bounding box 633 634 PolygonContainer *polys = new PolygonContainer(); 635 BoundedRayContainer *rays = new BoundedRayContainer(); 636 637 RayContainer::const_iterator rit, rit_end = sampleRays.end(); 638 639 long startTime = GetTime(); 640 641 Debug << "**** Extracting polygons from rays ****\n"; 642 643 std::map<Face *, Polygon3 *> facePolyMap; 644 645 //-- extract polygons intersected by the rays 646 for (rit = sampleRays.begin(); rit != rit_end; ++ rit) 647 { 648 Ray *ray = *rit; 649 650 // get ray-face intersection. Store polygon representing the rays together 651 // with rays intersecting the face. 652 if (!ray->intersections.empty()) 653 { 654 MeshInstance *obj = dynamic_cast<MeshInstance *>(ray->intersections[0].mObject); 655 Face *face = obj->GetMesh()->mFaces[ray->intersections[0].mFace]; 656 657 std::map<Face *, Polygon3 *>::iterator it = facePolyMap.find(face); 658 659 if (it != facePolyMap.end()) 660 { 661 //store rays if needed for heuristics 662 if (mSplitPlaneStrategy & BLOCKED_RAYS) 663 (*it).second->mPiercingRays.push_back(ray); 664 } 665 else 666 { //store rays if needed for heuristics 667 Polygon3 *poly = new Polygon3(face, obj->GetMesh()); 668 poly->mParent = obj; 669 polys->push_back(poly); 670 671 if (mSplitPlaneStrategy & BLOCKED_RAYS) 672 poly->mPiercingRays.push_back(ray); 673 674 facePolyMap[face] = poly; 675 } 676 } 677 } 678 679 facePolyMap.clear(); 680 681 // compue bounding box 682 Polygon3::IncludeInBox(*polys, mBox); 683 684 //-- store rays 685 for (rit = sampleRays.begin(); rit != rit_end; ++ rit) 686 { 687 Ray *ray = *rit; 688 ray->SetId(-1); // reset id 689 690 float minT, maxT; 691 if (BoundRay(*ray, minT, maxT)) 692 rays->push_back(new BoundedRay(ray, minT, maxT)); 693 } 694 695 mStat.polys = (int)polys->size(); 696 697 Debug << "**** Finished polygon extraction ****" << endl; 698 Debug << (int)polys->size() << " polys extracted from " << (int)sampleRays.size() << " rays" << endl; 699 Debug << "extraction time: " << TimeDiff(startTime, GetTime())*1e-3 << "s" << endl; 700 701 Construct(polys, rays); 702 } 703 704 void BspTree::Construct(PolygonContainer *polys, BoundedRayContainer *rays) 705 { 706 std::stack<BspTraversalData> tStack; 707 708 mRoot = new BspLeaf(); 709 710 BspNodeGeometry *cell = new BspNodeGeometry(); 711 ConstructGeometry(mRoot, *cell); 712 713 BspTraversalData tData(mRoot, polys, 0, mRootCell, rays, 714 ComputePvsSize(*rays), cell->GetArea(), cell); 715 716 tStack.push(tData); 717 718 mStat.Start(); 719 cout << "**** Contructing bsp tree ****\n"; 720 721 while (!tStack.empty()) 722 { 723 tData = tStack.top(); 724 tStack.pop(); 725 726 // subdivide leaf node 727 BspNode *subRoot = Subdivide(tStack, tData); 728 } 729 730 mStat.Stop(); 731 } 732 733 bool BspTree::TerminationCriteriaMet(const BspTraversalData &data) const 734 { 735 return 736 (((int)data.mPolygons->size() <= mTermMaxPolygons) || 737 ((int)data.mRays->size() <= mTermMaxRays) || 738 (data.mPvs <= mTermMinPvs) || 739 (data.mArea <= mTermMinArea) || 740 (data.mDepth >= mTermMaxDepth) || 741 (((float)data.mPvs / ((float)data.mRays->size() + Limits::Small)) < 742 mTermMaxRayContribution)); 743 } 744 745 BspNode *BspTree::Subdivide(BspTraversalStack &tStack, BspTraversalData &tData) 746 { 747 //-- terminate traversal 748 if (TerminationCriteriaMet(tData)) 749 { 750 BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode); 751 752 BspViewCell *viewCell; 753 754 // generate new view cell for each leaf 755 if (mGenerateViewCells) 756 { 757 viewCell = dynamic_cast<BspViewCell *>(ViewCell::Generate()); 758 } 759 else 760 { 761 // add view cell to leaf 762 viewCell = dynamic_cast<BspViewCell *>(tData.mViewCell); 763 } 764 765 leaf->SetViewCell(viewCell); 766 viewCell->mBspLeaves.push_back(leaf); 767 768 //-- add pvs 769 if (viewCell != mRootCell) 770 { 771 int conSamp = 0, sampCon = 0; 772 leaf->AddToPvs(*tData.mRays, conSamp, sampCon); 773 774 mStat.contributingSamples += conSamp; 775 mStat.sampleContributions += sampCon; 776 } 777 778 EvaluateLeafStats(tData); 779 780 //-- clean up 781 782 // discard polygons 783 CLEAR_CONTAINER(*tData.mPolygons); 784 // discard rays 785 CLEAR_CONTAINER(*tData.mRays); 786 787 DEL_PTR(tData.mPolygons); 788 DEL_PTR(tData.mRays); 789 DEL_PTR(tData.mGeometry); 790 791 return leaf; 792 } 793 794 //-- continue subdivision 795 PolygonContainer coincident; 796 797 PolygonContainer *frontPolys = new PolygonContainer(); 798 PolygonContainer *backPolys = new PolygonContainer(); 799 800 BoundedRayContainer *frontRays = new BoundedRayContainer(); 801 BoundedRayContainer *backRays = new BoundedRayContainer(); 802 803 BspTraversalData tFrontData(NULL, new PolygonContainer(), tData.mDepth + 1, mRootCell, 804 new BoundedRayContainer(), 0, 0, new BspNodeGeometry()); 805 BspTraversalData tBackData(NULL, new PolygonContainer(), tData.mDepth + 1, mRootCell, 806 new BoundedRayContainer(), 0, 0, new BspNodeGeometry()); 807 808 // create new interior node and two leaf nodes 809 BspInterior *interior = SubdivideNode(tData, 810 tFrontData, 811 tBackData, 812 coincident); 813 814 #ifdef _DEBUG 815 if (frontPolys->empty() && backPolys->empty() && (coincident.size() > 2)) 816 { for (PolygonContainer::iterator it = coincident.begin(); it != coincident.end(); ++it) 817 Debug << (*it) << " " << (*it)->GetArea() << " " << (*it)->mParent << endl ; 818 Debug << endl;} 819 #endif 820 821 // extract view cells from coincident polygons according to plane normal 822 // only if front or back polygons are empty 823 if (!mGenerateViewCells) 824 { 825 ExtractViewCells(tFrontData, 826 tBackData, 827 coincident, 828 interior->mPlane); 829 830 } 831 832 // don't need coincident polygons anymory 833 CLEAR_CONTAINER(coincident); 834 835 // push the children on the stack 836 tStack.push(tFrontData); 837 tStack.push(tBackData); 838 839 // cleanup 840 DEL_PTR(tData.mNode); 841 DEL_PTR(tData.mPolygons); 842 DEL_PTR(tData.mRays); 843 DEL_PTR(tData.mGeometry); 844 845 return interior; 846 } 847 848 void BspTree::ExtractViewCells(BspTraversalData &frontData, 849 BspTraversalData &backData, 850 const PolygonContainer &coincident, 851 const Plane3 splitPlane) const 852 { 853 // if not empty, tree is further subdivided => don't have to find view cell 854 bool foundFront = !frontData.mPolygons->empty(); 855 bool foundBack = !frontData.mPolygons->empty(); 856 857 PolygonContainer::const_iterator it = 858 coincident.begin(), it_end = coincident.end(); 859 860 //-- find first view cells in front and back leafs 861 for (; !(foundFront && foundBack) && (it != it_end); ++ it) 862 { 863 if (DotProd((*it)->GetNormal(), splitPlane.mNormal) > 0) 864 { 865 backData.mViewCell = dynamic_cast<ViewCell *>((*it)->mParent); 866 foundBack = true; 867 } 868 else 869 { 870 frontData.mViewCell = dynamic_cast<ViewCell *>((*it)->mParent); 871 foundFront = true; 872 } 873 } 874 } 875 876 BspInterior *BspTree::SubdivideNode(BspTraversalData &tData, 877 BspTraversalData &frontData, 878 BspTraversalData &backData, 879 PolygonContainer &coincident) 880 { 881 mStat.nodes += 2; 882 883 BspLeaf *leaf = dynamic_cast<BspLeaf *>(tData.mNode); 884 // select subdivision plane 885 BspInterior *interior = 886 new BspInterior(SelectPlane(leaf, tData)); 887 888 #ifdef _DEBUG 889 Debug << interior << endl; 890 #endif 891 892 // subdivide rays into front and back rays 893 SplitRays(interior->mPlane, *tData.mRays, *frontData.mRays, *backData.mRays); 894 895 // subdivide polygons with plane 896 mStat.splits += interior->SplitPolygons(*tData.mPolygons, 897 *frontData.mPolygons, 898 *backData.mPolygons, 899 coincident); 900 901 // compute pvs 902 frontData.mPvs = ComputePvsSize(*frontData.mRays); 903 backData.mPvs = ComputePvsSize(*backData.mRays); 904 905 // split geometry and compute area 906 if (1) 907 { 908 tData.mGeometry->SplitGeometry(*frontData.mGeometry, 909 *backData.mGeometry, 910 *this, 911 interior->mPlane); 912 913 914 frontData.mArea = frontData.mGeometry->GetArea(); 915 backData.mArea = backData.mGeometry->GetArea(); 916 } 917 918 // compute accumulated ray length 919 //frontData.mAccRayLength = AccumulatedRayLength(*frontData.mRays); 920 //backData.mAccRayLength = AccumulatedRayLength(*backData.mRays); 921 922 //-- create front and back leaf 923 924 BspInterior *parent = leaf->GetParent(); 925 926 // replace a link from node's parent 927 if (!leaf->IsRoot()) 928 { 929 parent->ReplaceChildLink(leaf, interior); 930 interior->SetParent(parent); 931 } 932 else // new root 933 { 934 mRoot = interior; 935 } 936 937 // and setup child links 938 interior->SetupChildLinks(new BspLeaf(interior), new BspLeaf(interior)); 939 940 frontData.mNode = interior->mFront; 941 backData.mNode = interior->mBack; 942 943 //DEL_PTR(leaf); 944 return interior; 945 } 946 947 void BspTree::SortSplitCandidates(const PolygonContainer &polys, 948 const int axis, 949 vector<SortableEntry> &splitCandidates) const 950 { 951 splitCandidates.clear(); 952 953 int requestedSize = 2 * (int)polys.size(); 954 // creates a sorted split candidates array 955 splitCandidates.reserve(requestedSize); 956 957 PolygonContainer::const_iterator it, it_end = polys.end(); 958 959 AxisAlignedBox3 box; 960 961 // insert all queries 962 for(it = polys.begin(); it != it_end; ++ it) 963 { 964 box.Initialize(); 965 box.Include(*(*it)); 966 967 splitCandidates.push_back(SortableEntry(SortableEntry::POLY_MIN, box.Min(axis), *it)); 968 splitCandidates.push_back(SortableEntry(SortableEntry::POLY_MAX, box.Max(axis), *it)); 969 } 970 971 stable_sort(splitCandidates.begin(), splitCandidates.end()); 972 } 973 974 975 float BspTree::BestCostRatio(const PolygonContainer &polys, 976 const AxisAlignedBox3 &box, 977 const int axis, 978 float &position, 979 int &objectsBack, 980 int &objectsFront) const 981 { 982 vector<SortableEntry> splitCandidates; 983 984 SortSplitCandidates(polys, axis, splitCandidates); 985 986 // go through the lists, count the number of objects left and right 987 // and evaluate the following cost funcion: 988 // C = ct_div_ci + (ol + or)/queries 989 990 int objectsLeft = 0, objectsRight = (int)polys.size(); 991 992 float minBox = box.Min(axis); 993 float maxBox = box.Max(axis); 994 float boxArea = box.SurfaceArea(); 995 996 float minBand = minBox + mSplitBorder * (maxBox - minBox); 997 float maxBand = minBox + (1.0f - mSplitBorder) * (maxBox - minBox); 998 999 float minSum = 1e20f; 1000 vector<SortableEntry>::const_iterator ci, ci_end = splitCandidates.end(); 1001 1002 for(ci = splitCandidates.begin(); ci != ci_end; ++ ci) 1003 { 1004 switch ((*ci).type) 1005 { 1006 case SortableEntry::POLY_MIN: 1007 ++ objectsLeft; 1008 break; 1009 case SortableEntry::POLY_MAX: 1010 -- objectsRight; 1011 break; 1012 default: 1013 break; 1014 } 1015 1016 if ((*ci).value > minBand && (*ci).value < maxBand) 1017 { 1018 AxisAlignedBox3 lbox = box; 1019 AxisAlignedBox3 rbox = box; 1020 lbox.SetMax(axis, (*ci).value); 1021 rbox.SetMin(axis, (*ci).value); 1022 1023 float sum = objectsLeft * lbox.SurfaceArea() + 1024 objectsRight * rbox.SurfaceArea(); 1025 1026 if (sum < minSum) 1027 { 1028 minSum = sum; 1029 position = (*ci).value; 1030 1031 objectsBack = objectsLeft; 1032 objectsFront = objectsRight; 1033 } 1034 } 1035 } 1036 1037 float oldCost = (float)polys.size(); 1038 float newCost = mCt_div_ci + minSum / boxArea; 1039 float ratio = newCost / oldCost; 1040 1041 1042 #if 0 1043 Debug << "====================" << endl; 1044 Debug << "costRatio=" << ratio << " pos=" << position<<" t=" << (position - minBox)/(maxBox - minBox) 1045 << "\t o=(" << objectsBack << "," << objectsFront << ")" << endl; 1046 #endif 1047 return ratio; 1048 } 1049 1050 bool BspTree::SelectAxisAlignedPlane(Plane3 &plane, 1051 const PolygonContainer &polys) const 1052 { 1053 AxisAlignedBox3 box; 1054 box.Initialize(); 1055 1056 // create bounding box of region 1057 Polygon3::IncludeInBox(polys, box); 1058 1059 int objectsBack = 0, objectsFront = 0; 1060 int axis = 0; 1061 float costRatio = MAX_FLOAT; 1062 Vector3 position; 1063 1064 //-- area subdivision 1065 for (int i = 0; i < 3; ++ i) 1066 { 1067 float p = 0; 1068 float r = BestCostRatio(polys, box, i, p, objectsBack, objectsFront); 1069 1070 if (r < costRatio) 1071 { 1072 costRatio = r; 1073 axis = i; 1074 position = p; 1075 } 1076 } 1077 1078 if (costRatio >= mMaxCostRatio) 1079 return false; 1080 1081 Vector3 norm(0,0,0); norm[axis] = 1.0f; 1082 plane = Plane3(norm, position); 1083 1084 return true; 1085 } 1086 1087 Plane3 BspTree::SelectPlane(BspLeaf *leaf, BspTraversalData &data) 1088 { 1089 if (data.mPolygons->empty() && data.mRays->empty()) 1090 { 1091 Debug << "Warning: No autopartition polygon candidate available\n"; 1092 1093 // return axis aligned split 1094 AxisAlignedBox3 box; 1095 box.Initialize(); 1096 1097 // create bounding box of region 1098 Polygon3::IncludeInBox(*data.mPolygons, box); 1099 1100 const int axis = box.Size().DrivingAxis(); 1101 const Vector3 position = (box.Min()[axis] + box.Max()[axis])*0.5f; 1102 1103 Vector3 norm(0,0,0); norm[axis] = 1.0f; 1104 return Plane3(norm, position); 1105 } 1106 1107 if ((mSplitPlaneStrategy & AXIS_ALIGNED) && 1108 ((int)data.mPolygons->size() > mTermMaxPolysForAxisAligned) && 1109 ((int)data.mRays->size() > mTermMaxRaysForAxisAligned) && 1110 ((mTermMaxObjectsForAxisAligned < 0) || 1111 (Polygon3::ParentObjectsSize(*data.mPolygons) > mTermMaxObjectsForAxisAligned))) 1112 { 1113 Plane3 plane; 1114 if (SelectAxisAlignedPlane(plane, *data.mPolygons)) 1115 return plane; 1116 } 1117 1118 // simplest strategy: just take next polygon 1119 if (mSplitPlaneStrategy & RANDOM_POLYGON) 1120 { 1121 if (!data.mPolygons->empty()) 1122 { 1123 Polygon3 *nextPoly = (*data.mPolygons)[Random((int)data.mPolygons->size())]; 1124 return nextPoly->GetSupportingPlane(); 1125 } 1126 else 1127 { 1128 const int candidateIdx = Random((int)data.mRays->size()); 1129 BoundedRay *bRay = (*data.mRays)[candidateIdx]; 1130 1131 Ray *ray = bRay->mRay; 1132 1133 const Vector3 minPt = ray->Extrap(bRay->mMinT); 1134 const Vector3 maxPt = ray->Extrap(bRay->mMaxT); 1135 1136 const Vector3 pt = (maxPt + minPt) * 0.5; 1137 1138 const Vector3 normal = ray->GetDir(); 1139 1140 return Plane3(normal, pt); 1141 } 1142 1143 return Plane3(); 1144 } 1145 1146 // use heuristics to find appropriate plane 1147 return SelectPlaneHeuristics(leaf, data); 1148 } 1149 1150 Plane3 BspTree::SelectPlaneHeuristics(BspLeaf *leaf, BspTraversalData &data) 1151 { 1152 float lowestCost = MAX_FLOAT; 1153 Plane3 bestPlane; 1154 Plane3 plane; 1155 1156 int limit = Min((int)data.mPolygons->size(), mMaxPolyCandidates); 1157 1158 int candidateIdx = limit; 1159 1160 for (int i = 0; i < limit; ++ i) 1161 { 1162 candidateIdx = GetNextCandidateIdx(candidateIdx, *data.mPolygons); 1163 1164 Polygon3 *poly = (*data.mPolygons)[candidateIdx]; 1165 // evaluate current candidate 1166 const float candidateCost = 1167 SplitPlaneCost(poly->GetSupportingPlane(), data); 1168 1169 if (candidateCost < lowestCost) 1170 { 1171 bestPlane = poly->GetSupportingPlane(); 1172 lowestCost = candidateCost; 1173 } 1174 } 1175 1176 //Debug << "lowest: " << lowestCost << endl; 1177 1178 //-- choose candidate planes extracted from rays 1179 // we currently use two methods 1180 // 1) take 3 ray endpoints, where two are minimum and one a maximum 1181 // point or the other way round 1182 // 2) take plane normal as plane normal and the midpoint of the ray. 1183 // PROBLEM: does not resemble any point where visibility is likely to change 1184 const BoundedRayContainer *rays = data.mRays; 1185 1186 for (int i = 0; i < mMaxRayCandidates / 2; ++ i) 1187 { 1188 candidateIdx = Random((int)rays->size()); 1189 BoundedRay *bRay = (*rays)[candidateIdx]; 1190 1191 Ray *ray = bRay->mRay; 1192 1193 const Vector3 minPt = ray->Extrap(bRay->mMinT); 1194 const Vector3 maxPt = ray->Extrap(bRay->mMaxT); 1195 1196 const Vector3 pt = (maxPt + minPt) * 0.5; 1197 1198 const Vector3 normal = ray->GetDir(); 1199 1200 plane = Plane3(normal, pt); 1201 1202 const float candidateCost = SplitPlaneCost(plane, data); 1203 1204 if (candidateCost < lowestCost) 1205 { 1206 bestPlane = plane; 1207 1208 lowestCost = candidateCost; 1209 } 1210 } 1211 1212 //Debug << "lowest: " << lowestCost << endl; 1213 for (int i = 0; i < mMaxRayCandidates / 2; ++ i) 1214 { 1215 Vector3 pt[3]; 1216 int idx[3]; 1217 int cmaxT = 0; 1218 int cminT = 0; 1219 bool chooseMin = false; 1220 1221 for (int j = 0; j < 3; j ++) 1222 { 1223 idx[j] = Random((int)rays->size() * 2); 1224 1225 if (idx[j] >= (int)rays->size()) 1226 { 1227 idx[j] -= (int)rays->size(); 1228 1229 chooseMin = (cminT < 2); 1230 } 1231 else 1232 chooseMin = (cmaxT < 2); 1233 1234 BoundedRay *bRay = (*rays)[idx[j]]; 1235 pt[j] = chooseMin ? bRay->mRay->Extrap(bRay->mMinT) : bRay->mRay->Extrap(bRay->mMaxT); 1236 } 1237 1238 plane = Plane3(pt[0], pt[1], pt[2]); 1239 1240 const float candidateCost = SplitPlaneCost(plane, data); 1241 1242 if (candidateCost < lowestCost) 1243 { 1244 //Debug << "choose ray plane 2: " << candidateCost << endl; 1245 bestPlane = plane; 1246 1247 lowestCost = candidateCost; 1248 } 1249 } 1250 1251 #ifdef _DEBUG 1252 Debug << "plane lowest cost: " << lowestCost << endl; 1253 #endif 1254 return bestPlane; 1255 } 1256 1257 int BspTree::GetNextCandidateIdx(int currentIdx, PolygonContainer &polys) 1258 { 1259 const int candidateIdx = Random(currentIdx --); 1260 1261 // swap candidates to avoid testing same plane 2 times 1262 std::swap(polys[currentIdx], polys[candidateIdx]); 1263 1264 return currentIdx; 1265 //return Random((int)polys.size()); 1266 } 1267 1268 float BspTree::SplitPlaneCost(const Plane3 &candidatePlane, 1269 const PolygonContainer &polys) const 1270 { 1271 float val = 0; 1272 1273 float sumBalancedPolys = 0; 1274 float sumSplits = 0; 1275 float sumPolyArea = 0; 1276 float sumBalancedViewCells = 0; 1277 float sumBlockedRays = 0; 1278 float totalBlockedRays = 0; 1279 //float totalArea = 0; 1280 int totalViewCells = 0; 1281 1282 // need three unique ids for each type of view cell 1283 // for balanced view cells criterium 1284 ViewCell::NewMail(); 1285 const int backId = ViewCell::sMailId; 1286 ViewCell::NewMail(); 1287 const int frontId = ViewCell::sMailId; 1288 ViewCell::NewMail(); 1289 const int frontAndBackId = ViewCell::sMailId; 1290 1291 PolygonContainer::const_iterator it, it_end = polys.end(); 1292 1293 for (it = polys.begin(); it != it_end; ++ it) 1294 { 1295 const int classification = (*it)->ClassifyPlane(candidatePlane); 1296 1297 if (mSplitPlaneStrategy & BALANCED_POLYS) 1298 sumBalancedPolys += sBalancedPolysTable[classification]; 1299 1300 if (mSplitPlaneStrategy & LEAST_SPLITS) 1301 sumSplits += sLeastPolySplitsTable[classification]; 1302 1303 if (mSplitPlaneStrategy & LARGEST_POLY_AREA) 1304 { 1305 if (classification == Polygon3::COINCIDENT) 1306 sumPolyArea += (*it)->GetArea(); 1307 //totalArea += area; 1308 } 1309 1310 if (mSplitPlaneStrategy & BLOCKED_RAYS) 1311 { 1312 const float blockedRays = (float)(*it)->mPiercingRays.size(); 1313 1314 if (classification == Polygon3::COINCIDENT) 1315 sumBlockedRays += blockedRays; 1316 1317 totalBlockedRays += blockedRays; 1318 } 1319 1320 // assign view cells to back or front according to classificaion 1321 if (mSplitPlaneStrategy & BALANCED_VIEW_CELLS) 1322 { 1323 MeshInstance *viewCell = (*it)->mParent; 1324 1325 // assure that we only count a view cell 1326 // once for the front and once for the back side of the plane 1327 if (classification == Polygon3::FRONT_SIDE) 1328 { 1329 if ((viewCell->mMailbox != frontId) && 1330 (viewCell->mMailbox != frontAndBackId)) 1331 { 1332 sumBalancedViewCells += 1.0; 1333 1334 if (viewCell->mMailbox != backId) 1335 viewCell->mMailbox = frontId; 1336 else 1337 viewCell->mMailbox = frontAndBackId; 1338 1339 ++ totalViewCells; 1340 } 1341 } 1342 else if (classification == Polygon3::BACK_SIDE) 1343 { 1344 if ((viewCell->mMailbox != backId) && 1345 (viewCell->mMailbox != frontAndBackId)) 1346 { 1347 sumBalancedViewCells -= 1.0; 1348 1349 if (viewCell->mMailbox != frontId) 1350 viewCell->mMailbox = backId; 1351 else 1352 viewCell->mMailbox = frontAndBackId; 1353 1354 ++ totalViewCells; 1355 } 1356 } 1357 } 1358 } 1359 1360 const float polysSize = (float)polys.size() + Limits::Small; 1361 1362 // all values should be approx. between 0 and 1 so they can be combined 1363 // and scaled with the factors according to their importance 1364 if (mSplitPlaneStrategy & BALANCED_POLYS) 1365 val += mBalancedPolysFactor * fabs(sumBalancedPolys) / polysSize; 1366 1367 if (mSplitPlaneStrategy & LEAST_SPLITS) 1368 val += mLeastSplitsFactor * sumSplits / polysSize; 1369 1370 if (mSplitPlaneStrategy & LARGEST_POLY_AREA) 1371 // HACK: polys.size should be total area so scaling is between 0 and 1 1372 val += mLargestPolyAreaFactor * (float)polys.size() / sumPolyArea; 1373 1374 if (mSplitPlaneStrategy & BLOCKED_RAYS) 1375 if (totalBlockedRays != 0) 1376 val += mBlockedRaysFactor * (totalBlockedRays - sumBlockedRays) / totalBlockedRays; 1377 1378 if (mSplitPlaneStrategy & BALANCED_VIEW_CELLS) 1379 val += mBalancedViewCellsFactor * fabs(sumBalancedViewCells) / 1380 ((float)totalViewCells + Limits::Small); 1381 1382 return val; 1383 } 1384 1385 bool BspTree::BoundRay(const Ray &ray, float &minT, float &maxT) const 1386 { 1387 maxT = 1e6; 1388 minT = 0; 1389 1390 // test with tree bounding box 1391 if (!mBox.GetMinMaxT(ray, &minT, &maxT)) 1392 return false; 1393 1394 if (minT < 0) // start ray from origin 1395 minT = 0; 1396 1397 // bound ray or line segment 1398 if ((ray.GetType() == Ray::LOCAL_RAY) && 1399 !ray.intersections.empty() && 1400 (ray.intersections[0].mT <= maxT)) 1401 { 1402 maxT = ray.intersections[0].mT; 1403 } 1404 1405 return true; 1406 } 1407 1408 float BspTree::SplitPlaneCost(const Plane3 &candidatePlane, 1409 const BoundedRayContainer &rays, 1410 const int pvs, 1411 const float area, 1412 const BspNodeGeometry &cell) const 1413 { 1414 float val = 0; 1415 1416 float sumBalancedRays = 0; 1417 float sumRaySplits = 0; 1418 1419 int backId = 0; 1420 int frontId = 0; 1421 int frontAndBackId = 0; 1422 1423 int frontPvs = 0; 1424 int backPvs = 0; 1425 1426 // probability that view point lies in child 1427 float pOverall = 0; 1428 float pFront = 0; 1429 float pBack = 0; 1430 1431 if (mSplitPlaneStrategy & PVS) 1432 { 1433 // create three unique ids for pvs heuristics 1434 Intersectable::NewMail(); backId = ViewCell::sMailId; 1435 Intersectable::NewMail(); frontId = ViewCell::sMailId; 1436 Intersectable::NewMail(); frontAndBackId = ViewCell::sMailId; 1437 1438 if (mPvsUseArea) // use front and back cell areas to approximate volume 1439 { 1440 // construct child geometry with regard to the candidate split plane 1441 BspNodeGeometry frontCell; 1442 BspNodeGeometry backCell; 1443 1444 cell.SplitGeometry(frontCell, backCell, *this, candidatePlane); 1445 1446 pFront = frontCell.GetArea(); 1447 pBack = backCell.GetArea(); 1448 1449 pOverall = area; 1450 } 1451 } 1452 1453 BoundedRayContainer::const_iterator rit, rit_end = rays.end(); 1454 1455 for (rit = rays.begin(); rit != rays.end(); ++ rit) 1456 { 1457 Ray *ray = (*rit)->mRay; 1458 const float minT = (*rit)->mMinT; 1459 const float maxT = (*rit)->mMaxT; 1460 1461 Vector3 entP, extP; 1462 1463 const int cf = 1464 ray->ClassifyPlane(candidatePlane, minT, maxT, entP, extP); 1465 1466 if (mSplitPlaneStrategy & LEAST_RAY_SPLITS) 1467 { 1468 sumBalancedRays += sBalancedRaysTable[cf]; 1469 } 1470 1471 if (mSplitPlaneStrategy & BALANCED_RAYS) 1472 { 1473 sumRaySplits += sLeastRaySplitsTable[cf]; 1474 } 1475 1476 if (mSplitPlaneStrategy & PVS) 1477 { 1478 if (!ray->intersections.empty()) 1479 { 1480 // in case the ray intersects an objcrs 1481 // assure that we only count a object 1482 // once for the front and once for the back side of the plane 1483 IncPvs(*ray->intersections[0].mObject, frontPvs, backPvs, 1484 cf, frontId, backId, frontAndBackId); 1485 } 1486 1487 // the source object in the origin of the ray 1488 if (ray->sourceObject.mObject) 1489 { 1490 IncPvs(*ray->sourceObject.mObject, frontPvs, backPvs, 1491 cf, frontId, backId, frontAndBackId); 1492 } 1493 1494 if (!mPvsUseArea) // use front and back cell areas to approximate volume 1495 { 1496 float len = Distance(entP, extP); 1497 pOverall += len; 1498 1499 // use length of rays to approximate volume 1500 switch (cf) 1501 { 1502 case Ray::COINCIDENT: 1503 pBack += len; 1504 pFront += len; 1505 break; 1506 case Ray::BACK: 1507 pBack += len; 1508 break; 1509 case Ray::FRONT: 1510 pFront += len; 1511 break; 1512 case Ray::FRONT_BACK: 1513 { 1514 // find intersection of ray segment with plane 1515 const Vector3 extp = ray->Extrap(maxT); 1516 const float t = candidatePlane.FindT(ray->GetLoc(), extp); 1517 1518 const float newT = t * maxT; 1519 float newLen = Distance(ray->Extrap(newT), extp); 1520 1521 pFront += len - newLen; 1522 pBack += newLen; 1523 } 1524 break; 1525 case Ray::BACK_FRONT: 1526 { 1527 // find intersection of ray segment with plane 1528 const Vector3 extp = ray->Extrap(maxT); 1529 const float t = candidatePlane.FindT(ray->GetLoc(), extp); 1530 1531 const float newT = t * maxT; 1532 float newLen = Distance(ray->Extrap(newT), extp); 1533 1534 pFront += len; 1535 pBack += len - newLen; 1536 } 1537 break; 1538 default: 1539 Debug << "Should not come here" << endl; 1540 break; 1541 } 1542 } 1543 } 1544 } 1545 1546 const float raysSize = (float)rays.size() + Limits::Small; 1547 if (mSplitPlaneStrategy & LEAST_RAY_SPLITS) 1548 val += mLeastRaySplitsFactor * sumRaySplits / raysSize; 1549 1550 if (mSplitPlaneStrategy & BALANCED_RAYS) 1551 val += mBalancedRaysFactor * fabs(sumBalancedRays) / raysSize; 1552 1553 float denom = pOverall * (float)pvs * 2.0f + Limits::Small; 1554 if ((mSplitPlaneStrategy & PVS) && area && pvs) 1555 { 1556 val += mPvsFactor * (frontPvs * pFront + (backPvs * pBack)) / denom; 1557 1558 // give penalty to unbalanced split 1559 if (0) 1560 if (((pFront * 0.2 + Limits::Small) > pBack) || (pFront < (pBack * 0.2 + Limits::Small))) 1561 val += 0.5; 1562 } 1563 1564 #ifdef _DEBUG 1565 Debug << "totalpvs: " << pvs << " ptotal: " << pOverall 1566 << " frontpvs: " << frontPvs << " pFront: " << pFront 1567 << " backpvs: " << backPvs << " pBack: " << pBack << endl << endl; 1568 #endif 1569 return val; 1570 } 1571 1572 void BspTree::IncPvs(Intersectable &obj, 1573 int &frontPvs, 1574 int &backPvs, 1575 const int cf, 1576 const int frontId, 1577 const int backId, 1578 const int frontAndBackId) const 1579 { 1580 // TODO: does this really belong to no pvs? 1581 //if (cf == Ray::COINCIDENT) return; 1582 1583 if (cf == Ray::FRONT) 1584 { 1585 if ((obj.mMailbox != frontId) && 1586 (obj.mMailbox != frontAndBackId)) 1587 { 1588 ++ frontPvs; 1589 1590 if (obj.mMailbox != backId) 1591 obj.mMailbox = frontId; 1592 else 1593 obj.mMailbox = frontAndBackId; 1594 } 1595 } 1596 else if (cf == Ray::BACK) 1597 { 1598 if ((obj.mMailbox != backId) && 1599 (obj.mMailbox != frontAndBackId)) 1600 { 1601 ++ backPvs; 1602 1603 if (obj.mMailbox != frontId) 1604 obj.mMailbox = backId; 1605 else 1606 obj.mMailbox = frontAndBackId; 1607 } 1608 } 1609 // object belongs to both PVS 1610 else if ((cf == Ray::FRONT_BACK) || (cf == Ray::BACK_FRONT) ||(cf == Ray::COINCIDENT)) 1611 { 1612 if (obj.mMailbox != frontAndBackId) 1613 { 1614 if (obj.mMailbox != frontId) 1615 ++ frontPvs; 1616 if (obj.mMailbox != backId) 1617 ++ backPvs; 1618 1619 obj.mMailbox = frontAndBackId; 1620 } 1621 } 1622 } 1623 1624 float BspTree::SplitPlaneCost(const Plane3 &candidatePlane, 1625 BspTraversalData &data) const 1626 { 1627 float val = 0; 1628 1629 if (mSplitPlaneStrategy & VERTICAL_AXIS) 1630 { 1631 Vector3 tinyAxis(0,0,0); tinyAxis[mBox.Size().TinyAxis()] = 1.0f; 1632 // we put a penalty on the dot product between the "tiny" vertical axis 1633 // and the split plane axis 1634 val += mVerticalSplitsFactor * 1635 fabs(DotProd(candidatePlane.mNormal, tinyAxis)); 1636 } 1637 1638 // the following criteria loop over all polygons to find the cost value 1639 if ((mSplitPlaneStrategy & BALANCED_POLYS) || 1640 (mSplitPlaneStrategy & LEAST_SPLITS) || 1641 (mSplitPlaneStrategy & LARGEST_POLY_AREA) || 1642 (mSplitPlaneStrategy & BALANCED_VIEW_CELLS) || 1643 (mSplitPlaneStrategy & BLOCKED_RAYS)) 1644 { 1645 val += SplitPlaneCost(candidatePlane, *data.mPolygons); 1646 } 1647 1648 // the following criteria loop over all rays to find the cost value 1649 if ((mSplitPlaneStrategy & BALANCED_RAYS) || 1650 (mSplitPlaneStrategy & LEAST_RAY_SPLITS) || 1651 (mSplitPlaneStrategy & PVS)) 1652 { 1653 val += SplitPlaneCost(candidatePlane, *data.mRays, data.mPvs, 1654 data.mArea, *data.mGeometry); 1655 } 1656 1657 // return linear combination of the sums 1658 return val; 1654 1659 } 1655 1660 -
trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellBsp.h
r420 r421 222 222 223 223 224 static int mailID;225 int m ailbox;224 static int sMailId; 225 int mMailbox; 226 226 227 void Mail() { m ailbox = mailID; }228 static void NewMail() { mailID++; }229 bool Mailed() const { return m ailbox == mailID; }227 void Mail() { mMailbox = sMailId; } 228 static void NewMail() { ++ sMailId; } 229 bool Mailed() const { return mMailbox == sMailId; } 230 230 231 231 protected: … … 495 495 void EvaluateViewCellsStats(BspViewCellsStatistics &stat) const; 496 496 497 /** Parses the environment and stores the global BSP tree parameters 498 */ 499 static void ParseEnvironment(); 500 497 501 /// BSP tree construction method 498 int mConstructionMethod; 499 502 static int sConstructionMethod; 500 503 protected: 501 504 … … 768 771 /// should view cells be stored or generated in the leaves? 769 772 bool mGenerateViewCells; 770 771 /** Parses the environment and stores the global BSP tree parameters772 */773 void ParseEnvironment();774 773 775 774 /// maximal number of polygons before subdivision termination … … 809 808 810 809 // factors guiding the split plane heuristics 811 float sLeastSplitsFactor;812 float sBalancedPolysFactor;813 float sBalancedViewCellsFactor;814 float sVerticalSplitsFactor;815 float sLargestPolyAreaFactor;816 float sBlockedRaysFactor;817 float sLeastRaySplitsFactor;818 float sBalancedRaysFactor;819 float sPvsFactor;810 float mLeastSplitsFactor; 811 float mBalancedPolysFactor; 812 float mBalancedViewCellsFactor; 813 float mVerticalSplitsFactor; 814 float mLargestPolyAreaFactor; 815 float mBlockedRaysFactor; 816 float mLeastRaySplitsFactor; 817 float mBalancedRaysFactor; 818 float mPvsFactor; 820 819 821 820 //-- thresholds used for view cells merge … … 830 829 contribution for a balanced tree. 831 830 */ 832 static float sLeastPolySplitsTable[4];831 static const float sLeastPolySplitsTable[4]; 833 832 /** Evaluates split plane classification with respect to the plane's 834 833 contribution for a minimum number splits in the tree. 835 834 */ 836 static float sBalancedPolysTable[4];835 static const float sBalancedPolysTable[4]; 837 836 /** Evaluates split plane classification with respect to the plane's 838 837 contribution for a minimum number of ray splits. 839 838 */ 840 static float sLeastRaySplitsTable[5];839 static const float sLeastRaySplitsTable[5]; 841 840 /** Evaluates split plane classification with respect to the plane's 842 841 contribution for balanced rays. 843 842 */ 844 static float sBalancedRaysTable[5];843 static const float sBalancedRaysTable[5]; 845 844 846 845 }; -
trunk/VUT/GtpVisibilityPreprocessor/src/VspKdTree.cpp
r420 r421 28 28 // Static variables 29 29 int VspKdTreeLeaf::mailID = 0; 30 int VspKdTree::sTermMaxDepth = 10;31 float VspKdTree::sTermMinSize = 0.1f;32 int VspKdTree::sTermMinPvs = 10;33 int VspKdTree::sTermMinRays = 20;34 float VspKdTree::sTermMaxCostRatio = 0.1f;35 float VspKdTree::sTermMaxRayContribution = 0.1f;36 30 37 31 /// Adds object to the pvs of the front and back node … … 248 242 249 243 250 void VspKdTree::ParseEnvironment()251 {252 environment->GetIntValue("VspKdTree.Termination.maxDepth", sTermMaxDepth);253 environment->GetIntValue("VspKdTree.Termination.minPvs", sTermMinPvs);254 environment->GetIntValue("VspKdTree.Termination.minRays", sTermMinRays);255 environment->GetFloatValue("VspKdTree.Termination.maxRayContribution", sTermMaxRayContribution);256 environment->GetFloatValue("VspKdTree.Termination.maxCostRatio", sTermMaxCostRatio);257 258 environment->GetFloatValue("VspKdTree.Termination.minSize", sTermMinSize);259 sTermMinSize = sqr(sTermMinSize);260 }261 262 244 // Constructor 263 245 VspKdTree::VspKdTree() 264 246 { 247 environment->GetIntValue("VspKdTree.Termination.maxDepth", mTermMaxDepth); 248 environment->GetIntValue("VspKdTree.Termination.minPvs", mTermMinPvs); 249 environment->GetIntValue("VspKdTree.Termination.minRays", mTermMinRays); 250 environment->GetFloatValue("VspKdTree.Termination.maxRayContribution", mTermMaxRayContribution); 251 environment->GetFloatValue("VspKdTree.Termination.maxCostRatio", mTermMaxCostRatio); 252 253 environment->GetFloatValue("VspKdTree.Termination.minSize", mTermMinSize); 254 mTermMinSize = sqr(mTermMinSize); 255 265 256 environment->GetFloatValue("VspKdTree.epsilon", epsilon); 266 257 environment->GetFloatValue("VspKdTree.ct_div_ci", ct_div_ci); … … 563 554 } 564 555 565 if (costRatio > sTermMaxCostRatio)556 if (costRatio > mTermMaxCostRatio) 566 557 { 567 558 // cout<<"Too big cost ratio "<<costRatio<<endl; … … 861 852 VspKdTreeLeaf *leaf = dynamic_cast<VspKdTreeLeaf *>(data.mNode); 862 853 863 if (data.mDepth >= sTermMaxDepth)854 if (data.mDepth >= mTermMaxDepth) 864 855 ++ mStat.maxDepthNodes; 865 856 866 857 // if ( (int)(leaf->mRays.size()) < termMinCost) 867 858 // stat.minCostNodes++; 868 if (leaf->GetPvsSize() < sTermMinPvs)859 if (leaf->GetPvsSize() < mTermMinPvs) 869 860 ++ mStat.minPvsNodes; 870 861 871 if (leaf->GetPvsSize() < sTermMinRays)862 if (leaf->GetPvsSize() < mTermMinRays) 872 863 ++ mStat.minRaysNodes; 873 864 874 if (0 && leaf->GetAvgRayContribution() > sTermMaxRayContribution)865 if (0 && leaf->GetAvgRayContribution() > mTermMaxRayContribution) 875 866 ++ mStat.maxRayContribNodes; 876 867 877 if (SqrMagnitude(data.mBox.Size()) <= sTermMinSize)868 if (SqrMagnitude(data.mBox.Size()) <= mTermMinSize) 878 869 ++ mStat.minSizeNodes; 879 870 … … 882 873 } 883 874 875 876 inline bool VspKdTree::TerminationCriteriaMet(const VspKdTreeLeaf *leaf, 877 const AxisAlignedBox3 &box) const 878 { 879 return ((leaf->GetPvsSize() < mTermMinPvs) || (leaf->mRays.size() < mTermMinRays) || 880 // (leaf->GetAvgRayContribution() > termMaxRayContribution ) || 881 (leaf->mDepth >= mTermMaxDepth) || SqrMagnitude(box.Size()) <= mTermMinSize); 882 } 884 883 885 884 … … 889 888 AxisAlignedBox3 &frontBBox) 890 889 { 891 if ( (leaf->GetPvsSize() < sTermMinPvs) || (leaf->mRays.size() < sTermMinRays) || 892 // (leaf->GetAvgRayContribution() > termMaxRayContribution ) || 893 (leaf->mDepth >= sTermMaxDepth) || SqrMagnitude(box.Size()) <= sTermMinSize ) 890 if (TerminationCriteriaMet(leaf, box)) 894 891 { 895 892 … … 1091 1088 // check if we should perform a dynamic subdivision of the leaf 1092 1089 if (// leaf->mRays.size() > (unsigned)termMinCost && 1093 (leaf->GetPvsSize() >= sTermMinPvs) &&1090 (leaf->GetPvsSize() >= mTermMinPvs) && 1094 1091 (SqrMagnitude(leafBBox.Size()) > sizeThreshold) ) 1095 1092 { -
trunk/VUT/GtpVisibilityPreprocessor/src/VspKdTree.h
r420 r421 421 421 float GetAvgPvsSize(); 422 422 423 /** Parses the environment and stores the global VspKd tree parameters424 */425 static void ParseEnvironment();426 427 /////////////////////////////428 // Construction parameters429 430 /// max depth of the tree431 static int sTermMaxDepth;432 433 /// minimal ratio of the volume of the cell and the query volume434 static float sTermMinSize;435 436 /// minimal pvs per node to still get subdivided437 static int sTermMinPvs;438 439 /// minimal ray number per node to still get subdivided440 static int sTermMinRays;441 442 /// maximal cost ration to subdivide a node443 static float sTermMaxCostRatio;444 445 /// maximal contribution per ray to subdivide the node446 static float sTermMaxRayContribution;447 448 423 /** Returns memory usage in MB. 449 424 */ … … 533 508 int ReleaseMemory(const int time); 534 509 510 bool TerminationCriteriaMet(const VspKdTreeLeaf *leaf, 511 const AxisAlignedBox3 &box) const; 512 535 513 protected: 536 514 ///////////////////////////// … … 575 553 // reusable array of split candidates 576 554 vector<SortableEntry> *splitCandidates; 577 555 556 557 ///////////////////////////// 558 // Construction parameters 559 560 /// max depth of the tree 561 int mTermMaxDepth; 562 563 /// minimal ratio of the volume of the cell and the query volume 564 float mTermMinSize; 565 566 /// minimal pvs per node to still get subdivided 567 int mTermMinPvs; 568 569 /// minimal ray number per node to still get subdivided 570 int mTermMinRays; 571 572 /// maximal cost ration to subdivide a node 573 float mTermMaxCostRatio; 574 575 /// maximal contribution per ray to subdivide the node 576 float mTermMaxRayContribution; 577 578 578 579 ///////////////////////////// 579 580 VspKdStatistics mStat; -
trunk/VUT/GtpVisibilityPreprocessor/src/main.cpp
r420 r421 23 23 environment->Parse(argc, argv, USE_EXE_PATH); 24 24 MeshKdTree::ParseEnvironment(); 25 26 VspKdTree::ParseEnvironment(); 27 25 BspTree::ParseEnvironment(); 26 28 27 char buff[128]; 29 28 … … 63 62 // a certain number of rays collected 64 63 if (ViewCell::sHierarchy == ViewCell::BSP && 65 !(BspTree:: mConstructionMethod == BspTree::FROM_RAYS))64 !(BspTree::sConstructionMethod == BspTree::FROM_RAYS)) 66 65 { 67 if (BspTree:: mConstructionMethod == BspTree::FROM_INPUT_VIEW_CELLS)66 if (BspTree::sConstructionMethod == BspTree::FROM_INPUT_VIEW_CELLS) 68 67 { 69 68 // view cells input file name -
trunk/VUT/work/TestCullingTerrain/TerrainFrameListener.cpp
r418 r421 646 646 { 647 647 // move node rather than camera so orientation is right in the visualization 648 mCamNode->yaw(mRotX); 648 mCamNode->yaw(mRotX, Ogre::Node::TS_WORLD); 649 //mCamNode->rotate(Vector3(0,1,0), mRotX, Ogre::Node::TS_WORLD); 649 650 mCamNode->pitch(mRotY); 651 650 652 mCamNode->translate(mCamNode->getLocalAxes(), mTranslateVector); 651 653 } … … 1131 1133 toggleUseDepthPass(); 1132 1134 break; 1133 case KC_ S:1135 case KC_H: 1134 1136 toggleShowShadows(); 1135 1137 break; … … 1218 1220 mUseDemoFps = !mUseDemoFps; 1219 1221 break; 1220 case KC_ A:1222 case KC_Q: 1221 1223 toggleUseArbQueries(); 1222 1224 break; … … 1312 1314 1313 1315 /* Move camera forward by keypress. */ 1314 if (mInputDevice->isKeyDown(KC_UP) )1316 if (mInputDevice->isKeyDown(KC_UP) || mInputDevice->isKeyDown(KC_W)) 1315 1317 { 1316 1318 mTranslateVector.z = -mMoveScale; … … 1318 1320 } 1319 1321 /* Move camera backward by keypress. */ 1320 if (mInputDevice->isKeyDown(KC_DOWN) )1322 if (mInputDevice->isKeyDown(KC_DOWN) || mInputDevice->isKeyDown(KC_S)) 1321 1323 { 1322 1324 mTranslateVector.z = mMoveScale; 1323 1325 cursorPressed = true; 1324 1326 } 1327 1328 if (mInputDevice->isKeyDown(KC_A)) 1329 { 1330 mTranslateVector.x -= mMoveScale; 1331 mTranslateVector.y += mMoveScale; 1332 1333 cursorPressed = true; 1334 } 1335 1336 if (mInputDevice->isKeyDown(KC_D)) 1337 { 1338 mTranslateVector.x += mMoveScale; 1339 mTranslateVector.y -= mMoveScale; 1340 1341 cursorPressed = true; 1342 } 1325 1343 1326 1344 if (mInputDevice->isKeyDown(KC_RIGHT)) … … 1329 1347 cursorPressed = true; 1330 1348 } 1331 1349 1332 1350 if (mInputDevice->isKeyDown(KC_LEFT)) 1333 1351 { -
trunk/VUT/work/TestCullingTerrain/TerrainFrameListener.h
r418 r421 405 405 406 406 bool mUseBufferedInputMouse; 407 Matrix4 rotMatrix; 407 408 }; 408 409
Note: See TracChangeset
for help on using the changeset viewer.