Ignore:
Timestamp:
11/18/05 14:02:49 (19 years ago)
Author:
mattausch
Message:

fixed controls for terrain demo
fixed member names in vspkdtree

Location:
trunk/VUT/GtpVisibilityPreprocessor/src
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • trunk/VUT/GtpVisibilityPreprocessor/src/Environment.cpp

    r419 r421  
    11751175                 "bspTree"); 
    11761176 
     1177  RegisterOption("ViewCells.maxViewCells", 
     1178                 optInt, 
     1179                 "-view_cells_max_view_cells", 
     1180                 "0"); 
     1181 
    11771182  RegisterOption("ViewCells.PostProcessing.minPvsDif", 
    11781183                 optInt, 
  • trunk/VUT/GtpVisibilityPreprocessor/src/SamplingPreprocessor.cpp

    r420 r421  
    6161        ObjectContainer objects; 
    6262         
    63         switch (mBspTree->mConstructionMethod) 
     63        switch (BspTree::sConstructionMethod) 
    6464        { 
    6565        case BspTree::FROM_INPUT_VIEW_CELLS: 
     
    779779        if (!mBspTree) 
    780780        { 
    781                 if ((BspTree::mConstructionMethod == BspTree::FROM_RAYS) && 
     781                if ((BspTree::sConstructionMethod == BspTree::FROM_RAYS) && 
    782782                        ((int)mSampleRays.size() < mBspConstructionSamples)) 
    783783                { 
     
    889889                                        outRays.push_back(mSampleRays[i]); 
    890890                        } 
    891                         if (BspTree::mConstructionMethod == BspTree::FROM_RAYS) 
     891                        if (BspTree::sConstructionMethod == BspTree::FROM_RAYS) 
    892892                        { 
    893893                                // export rays  
  • trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellBsp.cpp

    r420 r421  
    1414#include "Plane3.h" 
    1515 
    16 int BspNode::mailID = 1; 
     16//-- static members 
     17 
     18int BspNode::sMailId = 1; 
    1719 
    1820/** Evaluates split plane classification with respect to the plane's  
    1921        contribution for a minimum number splits in the tree. 
    2022*/ 
    21 float BspTree::sLeastPolySplitsTable[] = {0, 0, 1, 0}; 
     23const float BspTree::sLeastPolySplitsTable[] = {0, 0, 1, 0}; 
    2224/** Evaluates split plane classification with respect to the plane's  
    2325        contribution for a balanced tree. 
    2426*/ 
    25 float BspTree::sBalancedPolysTable[] = {1, -1, 0, 0}; 
     27const float BspTree::sBalancedPolysTable[] = {1, -1, 0, 0}; 
    2628 
    2729/** Evaluates split plane classification with respect to the plane's  
    2830        contribution for a minimum number of ray splits. 
    2931*/ 
    30 float BspTree::sLeastRaySplitsTable[] = {0, 0, 1, 1, 0}; 
     32const float BspTree::sLeastRaySplitsTable[] = {0, 0, 1, 1, 0}; 
    3133/** Evaluates split plane classification with respect to the plane's  
    3234        contribution for balanced rays. 
    3335*/ 
    34 float BspTree::sBalancedRaysTable[] = {1, -1, 0, 0, 0}; 
     36const float BspTree::sBalancedRaysTable[] = {1, -1, 0, 0, 0}; 
     37 
     38int BspTree::sConstructionMethod = FROM_INPUT_VIEW_CELLS; 
     39 
    3540 
    3641/****************************************************************/ 
     
    283288mPvsUseArea(true) 
    284289{ 
    285         ParseEnvironment(); 
    286290        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 
    1590292        //-- termination criteria for autopartition 
    1591293        environment->GetIntValue("BspTree.Termination.maxDepth", mTermMaxDepth); 
     
    1651353        if (mSplitPlaneStrategy & PVS) 
    1652354                Debug << "pvs"; 
     355 
    1653356        Debug << endl; 
     357} 
     358 
     359void 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 
     383const BspTreeStatistics &BspTree::GetStatistics() const  
     384{ 
     385        return mStat; 
     386} 
     387 
     388void 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 
     424BspTree::~BspTree() 
     425{ 
     426        DEL_PTR(mRoot); 
     427} 
     428 
     429void 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 
     440void 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 
     527int 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 
     547int 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 
     568int 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 
     601void 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 
     615void 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 
     629void 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 
     704void 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 
     733bool 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 
     745BspNode *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 
     848void 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 
     876BspInterior *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 
     947void 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 
     975float 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 
     1050bool 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 
     1087Plane3 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 
     1150Plane3 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 
     1257int 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 
     1268float 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 
     1385bool 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 
     1408float 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 
     1572void 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 
     1624float 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; 
    16541659} 
    16551660 
  • trunk/VUT/GtpVisibilityPreprocessor/src/ViewCellBsp.h

    r420 r421  
    222222 
    223223         
    224         static int mailID; 
    225         int mailbox; 
     224        static int sMailId; 
     225        int mMailbox; 
    226226   
    227         void Mail() { mailbox = mailID; } 
    228         static void NewMail() { mailID++; } 
    229         bool Mailed() const { return mailbox == mailID; } 
     227        void Mail() { mMailbox = sMailId; } 
     228        static void NewMail() { ++ sMailId; } 
     229        bool Mailed() const { return mMailbox == sMailId; } 
    230230 
    231231protected: 
     
    495495        void EvaluateViewCellsStats(BspViewCellsStatistics &stat) const; 
    496496 
     497        /** Parses the environment and stores the global BSP tree parameters 
     498        */ 
     499        static void ParseEnvironment(); 
     500 
    497501        /// BSP tree construction method 
    498         int mConstructionMethod; 
    499  
     502        static int sConstructionMethod; 
    500503protected: 
    501504 
     
    768771        /// should view cells be stored or generated in the leaves? 
    769772        bool mGenerateViewCells; 
    770  
    771                 /** Parses the environment and stores the global BSP tree parameters 
    772         */ 
    773         void ParseEnvironment(); 
    774773 
    775774        /// maximal number of polygons before subdivision termination 
     
    809808 
    810809        // 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; 
    820819 
    821820        //-- thresholds used for view cells merge 
     
    830829                contribution for a balanced tree. 
    831830        */ 
    832         static float sLeastPolySplitsTable[4]; 
     831        static const float sLeastPolySplitsTable[4]; 
    833832        /** Evaluates split plane classification with respect to the plane's  
    834833                contribution for a minimum number splits in the tree. 
    835834        */ 
    836         static float sBalancedPolysTable[4]; 
     835        static const float sBalancedPolysTable[4]; 
    837836        /** Evaluates split plane classification with respect to the plane's  
    838837                contribution for a minimum number of ray splits. 
    839838        */ 
    840         static float sLeastRaySplitsTable[5]; 
     839        static const float sLeastRaySplitsTable[5]; 
    841840        /** Evaluates split plane classification with respect to the plane's  
    842841                contribution for balanced rays. 
    843842        */ 
    844         static float sBalancedRaysTable[5]; 
     843        static const float sBalancedRaysTable[5]; 
    845844 
    846845}; 
  • trunk/VUT/GtpVisibilityPreprocessor/src/VspKdTree.cpp

    r420 r421  
    2828// Static variables 
    2929int 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; 
    3630 
    3731/// Adds object to the pvs of the front and back node 
     
    248242 
    249243 
    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  
    262244// Constructor 
    263245VspKdTree::VspKdTree() 
    264246{          
     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 
    265256        environment->GetFloatValue("VspKdTree.epsilon", epsilon); 
    266257        environment->GetFloatValue("VspKdTree.ct_div_ci", ct_div_ci); 
     
    563554  } 
    564555 
    565         if (costRatio > sTermMaxCostRatio)  
     556        if (costRatio > mTermMaxCostRatio)  
    566557        { 
    567558                //              cout<<"Too big cost ratio "<<costRatio<<endl; 
     
    861852        VspKdTreeLeaf *leaf = dynamic_cast<VspKdTreeLeaf *>(data.mNode); 
    862853 
    863         if (data.mDepth >= sTermMaxDepth) 
     854        if (data.mDepth >= mTermMaxDepth) 
    864855                ++ mStat.maxDepthNodes; 
    865856   
    866857        //  if ( (int)(leaf->mRays.size()) < termMinCost) 
    867858        //    stat.minCostNodes++; 
    868         if (leaf->GetPvsSize() < sTermMinPvs) 
     859        if (leaf->GetPvsSize() < mTermMinPvs) 
    869860                ++ mStat.minPvsNodes; 
    870861 
    871         if (leaf->GetPvsSize() < sTermMinRays) 
     862        if (leaf->GetPvsSize() < mTermMinRays) 
    872863                ++ mStat.minRaysNodes; 
    873864 
    874         if (0 && leaf->GetAvgRayContribution() > sTermMaxRayContribution) 
     865        if (0 && leaf->GetAvgRayContribution() > mTermMaxRayContribution) 
    875866                ++ mStat.maxRayContribNodes; 
    876867         
    877         if (SqrMagnitude(data.mBox.Size()) <= sTermMinSize)  
     868        if (SqrMagnitude(data.mBox.Size()) <= mTermMinSize)  
    878869                ++ mStat.minSizeNodes; 
    879870 
     
    882873} 
    883874 
     875 
     876inline 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} 
    884883 
    885884 
     
    889888                                                                                AxisAlignedBox3 &frontBBox) 
    890889{ 
    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)) 
    894891        { 
    895892 
     
    10911088        // check if we should perform a dynamic subdivision of the leaf 
    10921089        if (// leaf->mRays.size() > (unsigned)termMinCost && 
    1093                 (leaf->GetPvsSize() >= sTermMinPvs) &&  
     1090                (leaf->GetPvsSize() >= mTermMinPvs) &&  
    10941091                (SqrMagnitude(leafBBox.Size()) > sizeThreshold) ) 
    10951092        { 
  • trunk/VUT/GtpVisibilityPreprocessor/src/VspKdTree.h

    r420 r421  
    421421        float GetAvgPvsSize(); 
    422422 
    423         /** Parses the environment and stores the global VspKd tree parameters 
    424         */ 
    425         static void ParseEnvironment(); 
    426  
    427         ///////////////////////////// 
    428         // Construction parameters 
    429  
    430         /// max depth of the tree 
    431         static int sTermMaxDepth; 
    432  
    433         /// minimal ratio of the volume of the cell and the query volume 
    434         static float sTermMinSize; 
    435  
    436         /// minimal pvs per node to still get subdivided 
    437         static int sTermMinPvs; 
    438  
    439         /// minimal ray number per node to still get subdivided 
    440         static int sTermMinRays; 
    441          
    442         /// maximal cost ration to subdivide a node 
    443         static float sTermMaxCostRatio; 
    444          
    445         /// maximal contribution per ray to subdivide the node 
    446         static float sTermMaxRayContribution; 
    447  
    448423        /** Returns memory usage in MB. 
    449424        */ 
     
    533508        int ReleaseMemory(const int time); 
    534509 
     510        bool TerminationCriteriaMet(const VspKdTreeLeaf *leaf,  
     511                                                                const AxisAlignedBox3 &box) const; 
     512 
    535513protected: 
    536514        ///////////////////////////// 
     
    575553        // reusable array of split candidates 
    576554        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 
    578579        ///////////////////////////// 
    579580        VspKdStatistics mStat;   
  • trunk/VUT/GtpVisibilityPreprocessor/src/main.cpp

    r420 r421  
    2323  environment->Parse(argc, argv, USE_EXE_PATH); 
    2424  MeshKdTree::ParseEnvironment(); 
    25    
    26   VspKdTree::ParseEnvironment(); 
    27  
     25  BspTree::ParseEnvironment(); 
     26  
    2827  char buff[128]; 
    2928   
     
    6362  // a certain number of rays collected 
    6463  if (ViewCell::sHierarchy == ViewCell::BSP && 
    65           !(BspTree::mConstructionMethod == BspTree::FROM_RAYS))  
     64          !(BspTree::sConstructionMethod == BspTree::FROM_RAYS))  
    6665  { 
    67           if (BspTree::mConstructionMethod == BspTree::FROM_INPUT_VIEW_CELLS) 
     66          if (BspTree::sConstructionMethod == BspTree::FROM_INPUT_VIEW_CELLS) 
    6867          { 
    6968                  // view cells input file name 
Note: See TracChangeset for help on using the changeset viewer.