Changeset 580 for trunk/VUT/GtpVisibilityPreprocessor/src/VspBspTree.cpp
- Timestamp:
- 02/01/06 19:29:59 (18 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/VUT/GtpVisibilityPreprocessor/src/VspBspTree.cpp
r579 r580 25 25 const float VspBspTree::sLeastRaySplitsTable[] = {0, 0, 1, 1, 0}; 26 26 /** Evaluates split plane classification with respect to the plane's 27 contribution for balanced rays.27 contribution for balanced rays. 28 28 */ 29 29 const float VspBspTree::sBalancedRaysTable[] = {1, -1, 0, 0, 0}; 30 30 31 ViewCellsManager *BspMergeCandidate::sViewCellsManager = NULL;32 //int BspMergeCandidate::sMaxPvsSize = 0;33 //int BspMergeCandidate::sMinPvsSize = 0;34 31 35 32 int VspBspTree::sFrontId = 0; … … 37 34 int VspBspTree::sFrontAndBackId = 0; 38 35 39 float BspMergeCandidate::sOverallCost = 0;40 float BspMergeCandidate::sExpectedCost = 0;41 float BspMergeCandidate::sVariance = 0;42 float BspMergeCandidate::sRenderCostWeight = 0.5f;43 bool BspMergeCandidate::sUseArea = false;44 int BspMergeCandidate::sNumViewCells = 0;45 46 //int upperPvsLimit = 120;47 //int lowerPvsLimit = 5;48 36 49 37 … … 64 52 65 53 66 // penalty for pvs durint merge67 inline float EvalPvsPenaltyForMerge(const int pvs,68 const int lower,69 const int upper)70 {71 // clamp to minmax values72 if (pvs < lower)73 return (float)lower;74 if (pvs > upper)75 return (float)upper;76 77 return (float)pvs;78 }79 54 80 55 … … 90 65 mViewCellsManager(NULL), 91 66 mOutOfBoundsCell(NULL), 92 mStoreRays(false) 67 mStoreRays(false), 68 mRenderCostWeight(0.5) 93 69 { 94 70 bool randomize = false; … … 126 102 // if only the driving axis is used for axis aligned split 127 103 environment->GetBoolValue("VspBspTree.splitUseOnlyDrivingAxis", mOnlyDrivingAxis); 128 129 //-- merge options 130 environment->GetIntValue("VspBspTree.PostProcess.minViewCells", mMergeMinViewCells); 131 environment->GetFloatValue("VspBspTree.PostProcess.maxCostRatio", mMergeMaxCostRatio); 132 environment->GetBoolValue("VspBspTree.PostProcess.useRaysForMerge", mUseRaysForMerge); 133 134 104 135 105 //-- termination criteria for axis aligned split 136 106 environment->GetFloatValue("VspBspTree.Termination.AxisAligned.maxRayContribution", … … 142 112 environment->GetFloatValue("VspBspTree.maxStaticMemory", mMaxMemory); 143 113 144 environment->GetBoolValue("VspBspTree.Visualization.exportMergedViewCells", mExportMergedViewCells); 145 environment->GetBoolValue("VspBspTree.PostProcess.exportMergeStats", mExportMergeStats); 146 147 148 mStats.open("bspStats.log"); 114 environment->GetFloatValue("VspBspTree.Construction.renderCostWeight", mRenderCostWeight); 115 116 117 149 118 150 119 //-- debug output 120 151 121 Debug << "******* VSP BSP options ******** " << endl; 152 122 Debug << "max depth: " << mTermMaxDepth << endl; … … 162 132 Debug << "max plane candidates: " << mMaxRayCandidates << endl; 163 133 Debug << "randomize: " << randomize << endl; 164 Debug << "minimum view cells: " << mMergeMinViewCells << endl;134 // Debug << "minimum view cells: " << mMergeMinViewCells << endl; 165 135 Debug << "using area for pvs: " << mUseAreaForPvs << endl; 136 Debug << "render cost weight: " << mRenderCostWeight << endl; 166 137 Debug << "Split plane strategy: "; 167 138 … … 195 166 Debug << endl; 196 167 } 168 197 169 198 170 BspViewCell *VspBspTree::GetOutOfBoundsCell() … … 249 221 return (int)mesh->mFaces.size(); 250 222 } 223 251 224 252 225 int VspBspTree::AddToPolygonSoup(const ViewCellContainer &viewCells, … … 273 246 return polysSize; 274 247 } 248 275 249 276 250 int VspBspTree::AddToPolygonSoup(const ObjectContainer &objects, … … 310 284 } 311 285 286 312 287 void VspBspTree::Construct(const VssRayContainer &sampleRays, 313 288 AxisAlignedBox3 *forcedBoundingBox) … … 366 341 367 342 Debug << "maximal pvs (i.e., pvs still considered as valid) : " << mViewCellsManager->GetMaxPvsSize() << endl; 343 368 344 //-- store rays 369 345 for (rit = sampleRays.begin(); rit != rit_end; ++ rit) … … 572 548 } 573 549 574 viewCell->mLea ves.push_back(leaf);550 viewCell->mLeaf = leaf; 575 551 576 552 if (mUseAreaForPvs) … … 589 565 return newNode; 590 566 } 591 592 593 567 594 568 … … 752 726 } 753 727 728 754 729 void VspBspTree::SortSplitCandidates(const RayInfoContainer &rays, const int axis) 755 730 { … … 780 755 stable_sort(mSplitCandidates->begin(), mSplitCandidates->end()); 781 756 } 757 782 758 783 759 float VspBspTree::BestCostRatioHeuristics(const RayInfoContainer &rays, … … 1035 1011 1036 1012 1013 bool VspBspTree::SelectPlane(Plane3 &bestPlane, 1014 BspLeaf *leaf, 1015 VspBspTraversalData &data, 1016 VspBspTraversalData &frontData, 1017 VspBspTraversalData &backData) 1018 { 1019 // simplest strategy: just take next polygon 1020 if (mSplitPlaneStrategy & RANDOM_POLYGON) 1021 { 1022 if (!data.mPolygons->empty()) 1023 { 1024 const int randIdx = 1025 (int)RandomValue(0, (Real)((int)data.mPolygons->size() - 1)); 1026 Polygon3 *nextPoly = (*data.mPolygons)[randIdx]; 1027 1028 bestPlane = nextPoly->GetSupportingPlane(); 1029 return true; 1030 } 1031 } 1032 1033 //-- use heuristics to find appropriate plane 1034 1035 // intermediate plane 1036 Plane3 plane; 1037 float lowestCost = MAX_FLOAT; 1038 1039 // decides if the first few splits should be only axisAligned 1040 const bool onlyAxisAligned = 1041 (mSplitPlaneStrategy & AXIS_ALIGNED) && 1042 ((int)data.mRays->size() > mTermMinRaysForAxisAligned) && 1043 ((int)data.GetAvgRayContribution() < mTermMaxRayContriForAxisAligned); 1044 1045 const int limit = onlyAxisAligned ? 0 : 1046 Min((int)data.mPolygons->size(), mMaxPolyCandidates); 1047 1048 float candidateCost; 1049 1050 int maxIdx = (int)data.mPolygons->size(); 1051 1052 for (int i = 0; i < limit; ++ i) 1053 { 1054 // the already taken candidates are stored behind maxIdx 1055 // => assure that no index is taken twice 1056 const int candidateIdx = (int)RandomValue(0, (Real)(-- maxIdx)); 1057 Polygon3 *poly = (*data.mPolygons)[candidateIdx]; 1058 1059 // swap candidate to the end to avoid testing same plane 1060 std::swap((*data.mPolygons)[maxIdx], (*data.mPolygons)[candidateIdx]); 1061 //Polygon3 *poly = (*data.mPolygons)[(int)RandomValue(0, (int)polys.size() - 1)]; 1062 1063 // evaluate current candidate 1064 BspNodeGeometry fGeom, bGeom; 1065 float fArea, bArea; 1066 plane = poly->GetSupportingPlane(); 1067 candidateCost = EvalSplitPlaneCost(plane, data, fGeom, bGeom, fArea, bArea); 1068 1069 if (candidateCost < lowestCost) 1070 { 1071 bestPlane = plane; 1072 lowestCost = candidateCost; 1073 } 1074 } 1075 1076 //-- evaluate axis aligned splits 1077 int axis; 1078 BspNodeGeometry *fGeom, *bGeom; 1079 float pFront, pBack; 1080 1081 candidateCost = SelectAxisAlignedPlane(plane, data, axis, 1082 &fGeom, &bGeom, 1083 pFront, pBack, 1084 data.mIsKdNode); 1085 1086 bool isAxisAlignedSplit = false; 1087 1088 if (candidateCost < lowestCost) 1089 { 1090 bestPlane = plane; 1091 lowestCost = candidateCost; 1092 1093 // assign already computed values 1094 // we can do this because we always save the 1095 // computed values from the axis aligned splits 1096 frontData.mGeometry = fGeom; 1097 backData.mGeometry = bGeom; 1098 1099 frontData.mProbability = pFront; 1100 backData.mProbability = pBack; 1101 1102 //! error also computed if cost ratio is missed 1103 ++ mBspStats.splits[axis]; 1104 isAxisAlignedSplit = true; 1105 } 1106 else 1107 { 1108 DEL_PTR(fGeom); 1109 DEL_PTR(bGeom); 1110 } 1111 1112 frontData.mIsKdNode = backData.mIsKdNode = (data.mIsKdNode && isAxisAlignedSplit); 1113 1114 #ifdef _DEBUG 1115 Debug << "plane lowest cost: " << lowestCost << endl; 1116 #endif 1117 1118 // cost ratio miss 1119 if (lowestCost > mTermMaxCostRatio) 1120 return false; 1121 1122 return true; 1123 } 1124 1125 1126 Plane3 VspBspTree::ChooseCandidatePlane(const RayInfoContainer &rays) const 1127 { 1128 const int candidateIdx = (int)RandomValue(0, (Real)((int)rays.size() - 1)); 1129 1130 const Vector3 minPt = rays[candidateIdx].ExtrapOrigin(); 1131 const Vector3 maxPt = rays[candidateIdx].ExtrapTermination(); 1132 1133 const Vector3 pt = (maxPt + minPt) * 0.5; 1134 const Vector3 normal = Normalize(rays[candidateIdx].mRay->GetDir()); 1135 1136 return Plane3(normal, pt); 1137 } 1138 1139 1140 Plane3 VspBspTree::ChooseCandidatePlane2(const RayInfoContainer &rays) const 1141 { 1142 Vector3 pt[3]; 1143 1144 int idx[3]; 1145 int cmaxT = 0; 1146 int cminT = 0; 1147 bool chooseMin = false; 1148 1149 for (int j = 0; j < 3; ++ j) 1150 { 1151 idx[j] = (int)RandomValue(0, (Real)((int)rays.size() * 2 - 1)); 1152 1153 if (idx[j] >= (int)rays.size()) 1154 { 1155 idx[j] -= (int)rays.size(); 1156 1157 chooseMin = (cminT < 2); 1158 } 1159 else 1160 chooseMin = (cmaxT < 2); 1161 1162 RayInfo rayInf = rays[idx[j]]; 1163 pt[j] = chooseMin ? rayInf.ExtrapOrigin() : rayInf.ExtrapTermination(); 1164 } 1165 1166 return Plane3(pt[0], pt[1], pt[2]); 1167 } 1168 1169 1170 Plane3 VspBspTree::ChooseCandidatePlane3(const RayInfoContainer &rays) const 1171 { 1172 Vector3 pt[3]; 1173 1174 int idx1 = (int)RandomValue(0, (Real)((int)rays.size() - 1)); 1175 int idx2 = (int)RandomValue(0, (Real)((int)rays.size() - 1)); 1176 1177 // check if rays different 1178 if (idx1 == idx2) 1179 idx2 = (idx2 + 1) % (int)rays.size(); 1180 1181 const RayInfo ray1 = rays[idx1]; 1182 const RayInfo ray2 = rays[idx2]; 1183 1184 // normal vector of the plane parallel to both lines 1185 const Vector3 norm = Normalize(CrossProd(ray1.mRay->GetDir(), ray2.mRay->GetDir())); 1186 1187 // vector from line 1 to line 2 1188 const Vector3 vd = ray2.ExtrapOrigin() - ray1.ExtrapOrigin(); 1189 1190 // project vector on normal to get distance 1191 const float dist = DotProd(vd, norm); 1192 1193 // point on plane lies halfway between the two planes 1194 const Vector3 planePt = ray1.ExtrapOrigin() + norm * dist * 0.5; 1195 1196 return Plane3(norm, planePt); 1197 } 1198 1199 1200 inline void VspBspTree::GenerateUniqueIdsForPvs() 1201 { 1202 Intersectable::NewMail(); sBackId = Intersectable::sMailId; 1203 Intersectable::NewMail(); sFrontId = Intersectable::sMailId; 1204 Intersectable::NewMail(); sFrontAndBackId = Intersectable::sMailId; 1205 } 1206 1207 1208 float VspBspTree::EvalSplitPlaneCost(const Plane3 &candidatePlane, 1209 const VspBspTraversalData &data, 1210 BspNodeGeometry &geomFront, 1211 BspNodeGeometry &geomBack, 1212 float &pFront, 1213 float &pBack) const 1214 { 1215 float cost = 0; 1216 1217 float sumBalancedRays = 0; 1218 float sumRaySplits = 0; 1219 1220 int pvsFront = 0; 1221 int pvsBack = 0; 1222 1223 // probability that view point lies in back / front node 1224 float pOverall = 0; 1225 pFront = 0; 1226 pBack = 0; 1227 1228 int raysFront = 0; 1229 int raysBack = 0; 1230 int totalPvs = 0; 1231 1232 int limit; 1233 bool useRand; 1234 1235 // choose test rays randomly if too much 1236 if ((int)data.mRays->size() > mMaxTests) 1237 { 1238 useRand = true; 1239 limit = mMaxTests; 1240 } 1241 else 1242 { 1243 useRand = false; 1244 limit = (int)data.mRays->size(); 1245 } 1246 1247 for (int i = 0; i < limit; ++ i) 1248 { 1249 const int testIdx = useRand ? 1250 (int)RandomValue(0, (Real)((int)data.mRays->size() - 1)) : i; 1251 RayInfo rayInf = (*data.mRays)[testIdx]; 1252 1253 float t; 1254 VssRay *ray = rayInf.mRay; 1255 const int cf = rayInf.ComputeRayIntersection(candidatePlane, t); 1256 1257 if (0) 1258 { 1259 if (cf >= 0) 1260 ++ raysFront; 1261 if (cf <= 0) 1262 ++ raysBack; 1263 } 1264 1265 if (mSplitPlaneStrategy & LEAST_RAY_SPLITS) 1266 { 1267 sumBalancedRays += cf; 1268 } 1269 1270 if (mSplitPlaneStrategy & BALANCED_RAYS) 1271 { 1272 if (cf == 0) 1273 ++ sumRaySplits; 1274 } 1275 1276 if (mSplitPlaneStrategy & PVS) 1277 { 1278 // find front and back pvs for origing and termination object 1279 AddObjToPvs(ray->mTerminationObject, cf, pvsFront, pvsBack, totalPvs); 1280 AddObjToPvs(ray->mOriginObject, cf, pvsFront, pvsBack, totalPvs); 1281 } 1282 } 1283 1284 const float raysSize = (float)data.mRays->size() + Limits::Small; 1285 1286 if (mSplitPlaneStrategy & PVS) 1287 { 1288 // create unique ids for pvs heuristics 1289 GenerateUniqueIdsForPvs(); 1290 1291 // construct child geometry with regard to the candidate split plane 1292 data.mGeometry->SplitGeometry(geomFront, 1293 geomBack, 1294 candidatePlane, 1295 mBox, 1296 mEpsilon); 1297 1298 pOverall = data.mProbability; 1299 1300 if (!mUseAreaForPvs) // use front and back cell areas to approximate volume 1301 { 1302 pFront = geomFront.GetVolume(); 1303 pBack = pOverall - geomFront.GetVolume(); 1304 } 1305 else 1306 { 1307 pFront = geomFront.GetArea(); 1308 pBack = geomBack.GetArea(); 1309 } 1310 } 1311 1312 1313 if (mSplitPlaneStrategy & LEAST_RAY_SPLITS) 1314 cost += mLeastRaySplitsFactor * sumRaySplits / raysSize; 1315 1316 if (mSplitPlaneStrategy & BALANCED_RAYS) 1317 cost += mBalancedRaysFactor * fabs(sumBalancedRays) / raysSize; 1318 1319 // -- pvs rendering heuristics 1320 if (mSplitPlaneStrategy & PVS) 1321 { 1322 const int lowerPvsLimit = mViewCellsManager->GetMinPvsSize(); 1323 const int upperPvsLimit = mViewCellsManager->GetMaxPvsSize(); 1324 1325 // only render cost heuristics or combined with standard deviation 1326 if (1) 1327 { 1328 const float penaltyOld = EvalPvsPenalty(totalPvs, lowerPvsLimit, upperPvsLimit); 1329 const float penaltyFront = EvalPvsPenalty(pvsFront, lowerPvsLimit, upperPvsLimit); 1330 const float penaltyBack = EvalPvsPenalty(pvsBack, lowerPvsLimit, upperPvsLimit); 1331 1332 const float oldRenderCost = pOverall * (float)penaltyOld + Limits::Small; 1333 const float newRenderCost = penaltyFront * pFront + penaltyBack * pBack; 1334 1335 float oldCost, newCost; 1336 1337 if (1) 1338 { 1339 oldCost = oldRenderCost; 1340 newCost = newRenderCost; 1341 } 1342 else 1343 { 1344 // standard deviation is difference of back and front pvs 1345 const float expectedCost = 0.5f * (penaltyFront + penaltyBack); 1346 1347 const float newDeviation = 0.5f * 1348 fabs(penaltyFront - expectedCost) + fabs(penaltyBack - expectedCost); 1349 1350 const float oldDeviation = penaltyOld + Limits::Small; 1351 1352 newCost = mRenderCostWeight * newRenderCost + (1.0f - mRenderCostWeight) * newDeviation; 1353 oldCost = mRenderCostWeight * oldRenderCost + (1.0f - mRenderCostWeight) * oldDeviation; 1354 } 1355 1356 cost += mPvsFactor * newCost / oldCost; 1357 } 1358 else 1359 { 1360 //-- compute weighted sum of expected render cost and standard deviation 1361 1362 //-- first compute expected render cost 1363 const float penaltyOld = EvalPvsPenalty(totalPvs, lowerPvsLimit, upperPvsLimit); 1364 const float penaltyFront = EvalPvsPenalty(pvsFront, lowerPvsLimit, upperPvsLimit); 1365 const float penaltyBack = EvalPvsPenalty(pvsBack, lowerPvsLimit, upperPvsLimit); 1366 1367 const float renderCostFront = penaltyFront * pFront; 1368 const float renderCostBack = penaltyBack * pBack; 1369 1370 const float oldRenderCost = pOverall * (float)penaltyOld + Limits::Small; 1371 const float newRenderCost = renderCostFront + renderCostBack; 1372 1373 1374 //-- compute standard deviation 1375 const float expectedCost = 0.5f * (renderCostBack + renderCostFront); 1376 1377 const float devFront = fabs(renderCostFront - expectedCost); 1378 1379 const float devBack = fabs(renderCostBack - expectedCost); 1380 1381 const float newDev = 0.5f * (devFront + devBack); 1382 const float oldDev = oldRenderCost * oldRenderCost; 1383 1384 const float newCost = newRenderCost * mRenderCostWeight + newDev * (1.0f - mRenderCostWeight); 1385 const float oldCost = oldRenderCost * mRenderCostWeight + oldDev * (1.0f - mRenderCostWeight); 1386 1387 cost += mPvsFactor * newCost / oldCost; 1388 1389 // also try to equalize render differences between front and back pvs 1390 //const float oldCost = pOverall + Limits::Small; 1391 //float newCost = (float)abs(pvsFront - pvsBack); 1392 1393 } 1394 } 1395 1396 #ifdef _DEBUG 1397 Debug << "totalpvs: " << data.mPvs << " ptotal: " << pOverall 1398 << " frontpvs: " << pvsFront << " pFront: " << pFront 1399 << " backpvs: " << pvsBack << " pBack: " << pBack << endl << endl; 1400 #endif 1401 1402 // normalize cost by sum of linear factors 1403 if(0) 1404 return cost / (float)mCostNormalizer; 1405 else 1406 return cost; 1407 } 1408 1409 1037 1410 float VspBspTree::EvalAxisAlignedSplitCost(const VspBspTraversalData &data, 1038 1411 const AxisAlignedBox3 &box, … … 1110 1483 1111 1484 return (mCtDivCi + newCost) / oldCost; 1112 }1113 1114 1115 1116 bool VspBspTree::SelectPlane(Plane3 &bestPlane,1117 BspLeaf *leaf,1118 VspBspTraversalData &data,1119 VspBspTraversalData &frontData,1120 VspBspTraversalData &backData)1121 {1122 // simplest strategy: just take next polygon1123 if (mSplitPlaneStrategy & RANDOM_POLYGON)1124 {1125 if (!data.mPolygons->empty())1126 {1127 const int randIdx =1128 (int)RandomValue(0, (Real)((int)data.mPolygons->size() - 1));1129 Polygon3 *nextPoly = (*data.mPolygons)[randIdx];1130 1131 bestPlane = nextPoly->GetSupportingPlane();1132 return true;1133 }1134 }1135 1136 //-- use heuristics to find appropriate plane1137 1138 // intermediate plane1139 Plane3 plane;1140 float lowestCost = MAX_FLOAT;1141 1142 // decides if the first few splits should be only axisAligned1143 const bool onlyAxisAligned =1144 (mSplitPlaneStrategy & AXIS_ALIGNED) &&1145 ((int)data.mRays->size() > mTermMinRaysForAxisAligned) &&1146 ((int)data.GetAvgRayContribution() < mTermMaxRayContriForAxisAligned);1147 1148 const int limit = onlyAxisAligned ? 0 :1149 Min((int)data.mPolygons->size(), mMaxPolyCandidates);1150 1151 float candidateCost;1152 1153 int maxIdx = (int)data.mPolygons->size();1154 1155 for (int i = 0; i < limit; ++ i)1156 {1157 // the already taken candidates are stored behind maxIdx1158 // => assure that no index is taken twice1159 const int candidateIdx = (int)RandomValue(0, (Real)(-- maxIdx));1160 Polygon3 *poly = (*data.mPolygons)[candidateIdx];1161 1162 // swap candidate to the end to avoid testing same plane1163 std::swap((*data.mPolygons)[maxIdx], (*data.mPolygons)[candidateIdx]);1164 //Polygon3 *poly = (*data.mPolygons)[(int)RandomValue(0, (int)polys.size() - 1)];1165 1166 // evaluate current candidate1167 BspNodeGeometry fGeom, bGeom;1168 float fArea, bArea;1169 plane = poly->GetSupportingPlane();1170 candidateCost = EvalSplitPlaneCost(plane, data, fGeom, bGeom, fArea, bArea);1171 1172 if (candidateCost < lowestCost)1173 {1174 bestPlane = plane;1175 lowestCost = candidateCost;1176 }1177 }1178 1179 //-- evaluate axis aligned splits1180 int axis;1181 BspNodeGeometry *fGeom, *bGeom;1182 float pFront, pBack;1183 1184 candidateCost = SelectAxisAlignedPlane(plane, data, axis,1185 &fGeom, &bGeom,1186 pFront, pBack,1187 data.mIsKdNode);1188 1189 bool isAxisAlignedSplit = false;1190 1191 if (candidateCost < lowestCost)1192 {1193 bestPlane = plane;1194 lowestCost = candidateCost;1195 1196 // assign already computed values1197 // we can do this because we always save the1198 // computed values from the axis aligned splits1199 frontData.mGeometry = fGeom;1200 backData.mGeometry = bGeom;1201 1202 frontData.mProbability = pFront;1203 backData.mProbability = pBack;1204 1205 //! error also computed if cost ratio is missed1206 ++ mBspStats.splits[axis];1207 isAxisAlignedSplit = true;1208 }1209 else1210 {1211 DEL_PTR(fGeom);1212 DEL_PTR(bGeom);1213 }1214 1215 frontData.mIsKdNode = backData.mIsKdNode = (data.mIsKdNode && isAxisAlignedSplit);1216 1217 #ifdef _DEBUG1218 Debug << "plane lowest cost: " << lowestCost << endl;1219 #endif1220 1221 // cost ratio miss1222 if (lowestCost > mTermMaxCostRatio)1223 return false;1224 1225 return true;1226 }1227 1228 1229 Plane3 VspBspTree::ChooseCandidatePlane(const RayInfoContainer &rays) const1230 {1231 const int candidateIdx = (int)RandomValue(0, (Real)((int)rays.size() - 1));1232 1233 const Vector3 minPt = rays[candidateIdx].ExtrapOrigin();1234 const Vector3 maxPt = rays[candidateIdx].ExtrapTermination();1235 1236 const Vector3 pt = (maxPt + minPt) * 0.5;1237 const Vector3 normal = Normalize(rays[candidateIdx].mRay->GetDir());1238 1239 return Plane3(normal, pt);1240 }1241 1242 1243 Plane3 VspBspTree::ChooseCandidatePlane2(const RayInfoContainer &rays) const1244 {1245 Vector3 pt[3];1246 1247 int idx[3];1248 int cmaxT = 0;1249 int cminT = 0;1250 bool chooseMin = false;1251 1252 for (int j = 0; j < 3; ++ j)1253 {1254 idx[j] = (int)RandomValue(0, (Real)((int)rays.size() * 2 - 1));1255 1256 if (idx[j] >= (int)rays.size())1257 {1258 idx[j] -= (int)rays.size();1259 1260 chooseMin = (cminT < 2);1261 }1262 else1263 chooseMin = (cmaxT < 2);1264 1265 RayInfo rayInf = rays[idx[j]];1266 pt[j] = chooseMin ? rayInf.ExtrapOrigin() : rayInf.ExtrapTermination();1267 }1268 1269 return Plane3(pt[0], pt[1], pt[2]);1270 }1271 1272 Plane3 VspBspTree::ChooseCandidatePlane3(const RayInfoContainer &rays) const1273 {1274 Vector3 pt[3];1275 1276 int idx1 = (int)RandomValue(0, (Real)((int)rays.size() - 1));1277 int idx2 = (int)RandomValue(0, (Real)((int)rays.size() - 1));1278 1279 // check if rays different1280 if (idx1 == idx2)1281 idx2 = (idx2 + 1) % (int)rays.size();1282 1283 const RayInfo ray1 = rays[idx1];1284 const RayInfo ray2 = rays[idx2];1285 1286 // normal vector of the plane parallel to both lines1287 const Vector3 norm = Normalize(CrossProd(ray1.mRay->GetDir(), ray2.mRay->GetDir()));1288 1289 // vector from line 1 to line 21290 const Vector3 vd = ray2.ExtrapOrigin() - ray1.ExtrapOrigin();1291 1292 // project vector on normal to get distance1293 const float dist = DotProd(vd, norm);1294 1295 // point on plane lies halfway between the two planes1296 const Vector3 planePt = ray1.ExtrapOrigin() + norm * dist * 0.5;1297 1298 return Plane3(norm, planePt);1299 }1300 1301 1302 inline void VspBspTree::GenerateUniqueIdsForPvs()1303 {1304 Intersectable::NewMail(); sBackId = ViewCell::sMailId;1305 Intersectable::NewMail(); sFrontId = ViewCell::sMailId;1306 Intersectable::NewMail(); sFrontAndBackId = ViewCell::sMailId;1307 }1308 1309 1310 float VspBspTree::EvalSplitPlaneCost(const Plane3 &candidatePlane,1311 const VspBspTraversalData &data,1312 BspNodeGeometry &geomFront,1313 BspNodeGeometry &geomBack,1314 float &pFront,1315 float &pBack) const1316 {1317 float cost = 0;1318 1319 float sumBalancedRays = 0;1320 float sumRaySplits = 0;1321 1322 int pvsFront = 0;1323 int pvsBack = 0;1324 1325 // probability that view point lies in back / front node1326 float pOverall = 0;1327 pFront = 0;1328 pBack = 0;1329 1330 int raysFront = 0;1331 int raysBack = 0;1332 int totalPvs = 0;1333 1334 int limit;1335 bool useRand;1336 1337 // choose test rays randomly if too much1338 if ((int)data.mRays->size() > mMaxTests)1339 {1340 useRand = true;1341 limit = mMaxTests;1342 }1343 else1344 {1345 useRand = false;1346 limit = (int)data.mRays->size();1347 }1348 1349 for (int i = 0; i < limit; ++ i)1350 {1351 const int testIdx = useRand ?1352 (int)RandomValue(0, (Real)((int)data.mRays->size() - 1)) : i;1353 RayInfo rayInf = (*data.mRays)[testIdx];1354 1355 float t;1356 VssRay *ray = rayInf.mRay;1357 const int cf = rayInf.ComputeRayIntersection(candidatePlane, t);1358 1359 if (0)1360 {1361 if (cf >= 0)1362 ++ raysFront;1363 if (cf <= 0)1364 ++ raysBack;1365 }1366 1367 if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)1368 {1369 sumBalancedRays += cf;1370 }1371 1372 if (mSplitPlaneStrategy & BALANCED_RAYS)1373 {1374 if (cf == 0)1375 ++ sumRaySplits;1376 }1377 1378 if (mSplitPlaneStrategy & PVS)1379 {1380 // find front and back pvs for origing and termination object1381 AddObjToPvs(ray->mTerminationObject, cf, pvsFront, pvsBack, totalPvs);1382 AddObjToPvs(ray->mOriginObject, cf, pvsFront, pvsBack, totalPvs);1383 }1384 }1385 1386 const float raysSize = (float)data.mRays->size() + Limits::Small;1387 1388 if (mSplitPlaneStrategy & PVS)1389 {1390 // create unique ids for pvs heuristics1391 GenerateUniqueIdsForPvs();1392 1393 // construct child geometry with regard to the candidate split plane1394 data.mGeometry->SplitGeometry(geomFront,1395 geomBack,1396 candidatePlane,1397 mBox,1398 mEpsilon);1399 1400 pOverall = data.mProbability;1401 1402 if (!mUseAreaForPvs) // use front and back cell areas to approximate volume1403 {1404 pFront = geomFront.GetVolume();1405 pBack = pOverall - geomFront.GetVolume();1406 }1407 else1408 {1409 pFront = geomFront.GetArea();1410 pBack = geomBack.GetArea();1411 }1412 }1413 1414 1415 if (mSplitPlaneStrategy & LEAST_RAY_SPLITS)1416 cost += mLeastRaySplitsFactor * sumRaySplits / raysSize;1417 1418 if (mSplitPlaneStrategy & BALANCED_RAYS)1419 cost += mBalancedRaysFactor * fabs(sumBalancedRays) / raysSize;1420 1421 // pvs criterium1422 if (mSplitPlaneStrategy & PVS)1423 {1424 if (1)1425 {1426 const int lowerPvsLimit = mViewCellsManager->GetMinPvsSize();1427 const int upperPvsLimit = mViewCellsManager->GetMaxPvsSize();1428 1429 const float penaltyOld = EvalPvsPenalty(totalPvs, lowerPvsLimit, upperPvsLimit);1430 1431 const float penaltyFront = EvalPvsPenalty(pvsFront, lowerPvsLimit, upperPvsLimit);1432 const float penaltyBack = EvalPvsPenalty(pvsBack, lowerPvsLimit, upperPvsLimit);1433 1434 const float oldCost = pOverall * (float)penaltyOld + Limits::Small;1435 cost += mPvsFactor * (penaltyFront * pFront + penaltyBack * pBack) / oldCost;1436 1437 }1438 else1439 {1440 // try to equalize render differences1441 //const float oldCost = pOverall * (float)totalPvs + Limits::Small;1442 //float newCost = fabs(pvsFront * pFront - pvsBack * pBack);1443 const float oldCost = pOverall + Limits::Small;1444 float newCost = (float)abs(pvsFront - pvsBack);1445 1446 cost += mPvsFactor * newCost / oldCost;1447 }1448 }1449 1450 #ifdef _DEBUG1451 Debug << "totalpvs: " << data.mPvs << " ptotal: " << pOverall1452 << " frontpvs: " << pvsFront << " pFront: " << pFront1453 << " backpvs: " << pvsBack << " pBack: " << pBack << endl << endl;1454 #endif1455 1456 // normalize cost by sum of linear factors1457 if(0)1458 return cost / (float)mCostNormalizer;1459 else1460 return cost;1461 1485 } 1462 1486 … … 1731 1755 { 1732 1756 BspViewCell *viewCell = dynamic_cast<BspLeaf *>(node)->GetViewCell(); 1733 1734 vector<BspLeaf *>::const_iterator it, it_end = viewCell->mLeaves.end(); 1735 for (it = viewCell->mLeaves.begin();it != it_end; ++ it) 1757 1758 ViewCellContainer leaves; 1759 mViewCellsManager->GetViewCellsTree()->CollectLeaves(viewCell, leaves); 1760 1761 ViewCellContainer::const_iterator it, it_end = leaves.end(); 1762 1763 for (it = leaves.begin(); it != it_end; ++ it) 1736 1764 { 1737 BspLeaf *l = *it;1765 BspLeaf *l = dynamic_cast<BspViewCell *>(*it)->mLeaf; 1738 1766 l->SetViewCell(GetOrCreateOutOfBoundsCell()); 1739 1767 ++ mBspStats.invalidLeaves; … … 2024 2052 BspNodeGeometry &vcGeom) const 2025 2053 { 2026 vector<BspLeaf *> leaves = vc->mLeaves; 2027 vector<BspLeaf *>::const_iterator it, it_end = leaves.end(); 2054 ViewCellContainer leaves; 2055 mViewCellsManager->GetViewCellsTree()->CollectLeaves(vc, leaves); 2056 2057 ViewCellContainer::const_iterator it, it_end = leaves.end(); 2028 2058 2029 2059 for (it = leaves.begin(); it != it_end; ++ it) 2030 ConstructGeometry(*it, vcGeom); 2060 { 2061 BspLeaf *l = dynamic_cast<BspViewCell *>(*it)->mLeaf; 2062 ConstructGeometry(l, vcGeom); 2063 } 2031 2064 } 2032 2065 … … 2456 2489 } 2457 2490 2491 2458 2492 BspNode *VspBspTree::CollapseTree(BspNode *node, int &collapsed) 2459 2493 { … … 2499 2533 { 2500 2534 int collapsed = 0; 2501 2535 //TODO 2536 #if VC_HISTORY 2502 2537 (void)CollapseTree(mRoot, collapsed); 2503 2538 2504 2539 // revalidate leaves 2505 2540 RepairViewCellsLeafLists(); 2506 2541 #endif 2507 2542 return collapsed; 2508 2543 } … … 2527 2562 2528 2563 BspViewCell *viewCell = leaf->GetViewCell(); 2529 2564 // TODO 2565 #if VC_HISTORY 2530 2566 if (!viewCell->Mailed()) 2531 2567 { … … 2533 2569 viewCell->Mail(); 2534 2570 } 2535 2571 2536 2572 viewCell->mLeaves.push_back(leaf); 2573 // TODO 2574 #endif 2537 2575 } 2538 2576 else … … 2631 2669 2632 2670 2633 bool VspBspTree::MergeViewCells(BspLeaf *l1, BspLeaf *l2) //const2634 {2635 //-- change pointer to view cells of all leaves associated2636 //-- with the previous view cells2637 BspViewCell *fVc = l1->GetViewCell();2638 BspViewCell *bVc = l2->GetViewCell();2639 2640 BspViewCell *vc = dynamic_cast<BspViewCell *>(2641 mViewCellsManager->MergeViewCells(*fVc, *bVc));2642 2643 // if merge was unsuccessful2644 if (!vc) return false;2645 2646 // set new size of view cell2647 if (mUseAreaForPvs)2648 vc->SetArea(fVc->GetArea() + bVc->GetArea());2649 else2650 vc->SetVolume(fVc->GetVolume() + bVc->GetVolume());2651 2652 vector<BspLeaf *> fLeaves = fVc->mLeaves;2653 vector<BspLeaf *> bLeaves = bVc->mLeaves;2654 2655 vector<BspLeaf *>::const_iterator it;2656 2657 //-- change view cells of all the other leaves the view cell belongs to2658 for (it = fLeaves.begin(); it != fLeaves.end(); ++ it)2659 {2660 (*it)->SetViewCell(vc);2661 vc->mLeaves.push_back(*it);2662 }2663 2664 for (it = bLeaves.begin(); it != bLeaves.end(); ++ it)2665 {2666 (*it)->SetViewCell(vc);2667 vc->mLeaves.push_back(*it);2668 }2669 2670 // important so other merge candidates sharing this view cell2671 // are notified that the merge cost must be updated!!2672 vc->Mail();2673 2674 //-- clean up old view cells2675 if (mExportMergedViewCells)2676 {2677 DEL_PTR(fVc);2678 DEL_PTR(bVc);2679 }2680 else2681 {2682 // old view cells container needed for visualization2683 //fVc->mMailbox = -1;2684 //bVc->mMailbox = -1;2685 fVc->SetId(-2);2686 bVc->SetId(-2);2687 2688 mOldViewCells.push_back(fVc);2689 mOldViewCells.push_back(bVc);2690 2691 mNewViewCells.push_back(vc);2692 }2693 2694 return true;2695 }2696 2697 2698 2671 void VspBspTree::SetViewCellsManager(ViewCellsManager *vcm) 2699 2672 { … … 2702 2675 2703 2676 2704 int VspBspTree::CollectMergeCandidates(const vector<BspLeaf *> leaves) 2677 int VspBspTree::CollectMergeCandidates(const vector<BspLeaf *> leaves, 2678 vector<MergeCandidate> &candidates) 2705 2679 { 2706 2680 BspLeaf::NewMail(); … … 2708 2682 vector<BspLeaf *>::const_iterator it, it_end = leaves.end(); 2709 2683 2710 int candidates = 0;2684 int numCandidates = 0; 2711 2685 2712 2686 // find merge candidates and push them into queue … … 2714 2688 { 2715 2689 BspLeaf *leaf = *it; 2716 2717 /// create leaf pvs (needed for post processing)2718 leaf->mPvs = new ObjectPvs(leaf->GetViewCell()->GetPvs());2719 2720 //const float rc = leaf->mProbability * (float)leaf->mPvs->GetSize();2721 //BspMergeCandidate::sOverallCost += rc;2722 2690 2723 2691 // the same leaves must not be part of two merge candidates … … 2733 2701 if ((*nit)->GetViewCell() != leaf->GetViewCell()) 2734 2702 { 2735 BspMergeCandidate mc(leaf, *nit); 2736 mc.EvalMergeCost(); 2737 2738 mMergeQueue.push(mc); 2739 ++ candidates; 2740 if ((candidates % 1000) == 0) 2703 MergeCandidate mc(leaf->GetViewCell(), (*nit)->GetViewCell()); 2704 candidates.push_back(mc); 2705 2706 ++ numCandidates; 2707 if ((numCandidates % 1000) == 0) 2741 2708 { 2742 cout << "collected " << candidates << " merge candidates" << endl;2709 cout << "collected " << numCandidates << " merge candidates" << endl; 2743 2710 } 2744 2711 } … … 2746 2713 } 2747 2714 2748 Debug << "mergequeue: " << (int)mMergeQueue.size() << endl; 2749 Debug << "leaves in queue: " << candidates << endl; 2750 Debug << "overall cost: " << BspMergeCandidate::sOverallCost << endl; 2751 2715 Debug << "merge queue: " << (int)candidates.size() << endl; 2716 Debug << "leaves in queue: " << numCandidates << endl; 2717 2752 2718 2753 2719 return (int)leaves.size(); … … 2755 2721 2756 2722 2757 int VspBspTree::CollectMergeCandidates(const VssRayContainer &rays) 2723 int VspBspTree::CollectMergeCandidates(const VssRayContainer &rays, 2724 vector<MergeCandidate> &candidates) 2758 2725 { 2759 2726 ViewCell::NewMail(); … … 2775 2742 if (ray->mViewCells.size() < 2) 2776 2743 continue; 2777 2744 //TODO viewcellhierarchy 2778 2745 iit = ray->mViewCells.begin(); 2779 2746 BspViewCell *bspVc = dynamic_cast<BspViewCell *>(*(iit ++)); 2780 BspLeaf *leaf = bspVc->mLeaves[0]; 2781 2782 // create leaf pvs (needed for post processing) 2783 if (!leaf->mPvs) 2784 { 2785 leaf->mPvs = 2786 new ObjectPvs(leaf->GetViewCell()->GetPvs()); 2787 2788 //BspMergeCandidate::sOverallCost += 2789 // leaf->mProbability * leaf->mPvs->GetSize(); 2790 2791 ++ numLeaves; 2792 } 2747 BspLeaf *leaf = bspVc->mLeaf; 2793 2748 2794 2749 // traverse intersections … … 2799 2754 BspLeaf *prevLeaf = leaf; 2800 2755 bspVc = dynamic_cast<BspViewCell *>(*iit); 2801 leaf = bspVc->mLea ves[0];2756 leaf = bspVc->mLeaf; 2802 2757 2803 2758 // view space not valid or same view cell … … 2806 2761 continue; 2807 2762 2808 // create leaf pvs (needed for post processing) 2809 if (!leaf->mPvs) 2810 { 2811 leaf->mPvs = 2812 new ObjectPvs(leaf->GetViewCell()->GetPvs()); 2813 2814 //BspMergeCandidate::sOverallCost += 2815 // leaf->mProbability * leaf->mPvs->GetSize(); 2816 2817 ++ numLeaves; 2818 } 2819 2820 vector<BspLeaf *> &neighbors = neighborMap[leaf]; 2763 vector<BspLeaf *> &neighbors = neighborMap[leaf]; 2821 2764 2822 2765 bool found = false; … … 2843 2786 prevLeaf->Mail(); 2844 2787 2845 BspMergeCandidate mc(leaf, prevLeaf); 2846 mc.EvalMergeCost(); 2847 2848 mMergeQueue.push(mc); 2849 2850 if (((int)mMergeQueue.size() % 1000) == 0) 2788 MergeCandidate mc(leaf->GetViewCell(), prevLeaf->GetViewCell()); 2789 2790 candidates.push_back(mc); 2791 2792 if (((int)candidates.size() % 1000) == 0) 2851 2793 { 2852 cout << "collected " << (int) mMergeQueue.size() << " merge candidates" << endl;2794 cout << "collected " << (int)candidates.size() << " merge candidates" << endl; 2853 2795 } 2854 2796 } … … 2857 2799 2858 2800 Debug << "neighbormap size: " << (int)neighborMap.size() << endl; 2859 Debug << "merge queue: " << (int)mMergeQueue.size() << endl;2801 Debug << "merge queue: " << (int)candidates.size() << endl; 2860 2802 Debug << "leaves in queue: " << numLeaves << endl; 2861 Debug << "overall cost: " << BspMergeCandidate::sOverallCost << endl; 2803 2862 2804 2863 2805 //-- collect the leaves which haven't been found by ray casting … … 2868 2810 CollectLeaves(leaves, true); 2869 2811 Debug << "found " << (int)leaves.size() << " new leaves" << endl << endl; 2870 CollectMergeCandidates(leaves );2812 CollectMergeCandidates(leaves, candidates); 2871 2813 } 2872 2814 … … 2875 2817 2876 2818 2877 void VspBspTree::ConstructBspRays(vector<BspRay *> &bspRays,2878 const VssRayContainer &rays)2879 {2880 VssRayContainer::const_iterator it, it_end = rays.end();2881 2882 for (it = rays.begin(); it != rays.end(); ++ it)2883 {2884 VssRay *vssRay = *it;2885 BspRay *ray = new BspRay(vssRay);2886 2887 ViewCellContainer viewCells;2888 2889 Ray hray(*vssRay);2890 float tmin = 0, tmax = 1.0;2891 // matt TODO: remove this!!2892 //hray.Init(ray.GetOrigin(), ray.GetDir(), Ray::LINE_SEGMENT);2893 if (!mBox.GetRaySegment(hray, tmin, tmax) || (tmin > tmax))2894 continue;2895 2896 Vector3 origin = hray.Extrap(tmin);2897 Vector3 termination = hray.Extrap(tmax);2898 2899 // cast line segment to get intersections with bsp leaves2900 CastLineSegment(origin, termination, viewCells);2901 2902 ViewCellContainer::const_iterator vit, vit_end = viewCells.end();2903 for (vit = viewCells.begin(); vit != vit_end; ++ vit)2904 {2905 BspViewCell *vc = dynamic_cast<BspViewCell *>(*vit);2906 vector<BspLeaf *>::const_iterator it, it_end = vc->mLeaves.end();2907 //NOTE: not sorted!2908 for (it = vc->mLeaves.begin(); it != it_end; ++ it)2909 {2910 ray->intersections.push_back(BspIntersection(0, *it));2911 }2912 }2913 2914 bspRays.push_back(ray);2915 }2916 }2917 2918 2919 #if 12920 int VspBspTree::MergeViewCells(const VssRayContainer &rays, const ObjectContainer &objects)2921 {2922 BspMergeCandidate::sViewCellsManager = mViewCellsManager;2923 BspMergeCandidate::sUseArea = mUseAreaForPvs;2924 2925 2926 //-- compute statistics values of initial view cells2927 mViewCellsManager->EvaluateRenderStatistics(BspMergeCandidate::sOverallCost,2928 BspMergeCandidate::sExpectedCost,2929 BspMergeCandidate::sVariance);2930 2931 2932 //BspMergeCandidate::sExpectedCost =2933 // BspMergeCandidate::sOverallCost / BspMergeCandidate::sNumViewCells;2934 2935 2936 ViewCellsManager::PvsStatistics pvsStats;2937 mViewCellsManager->GetPvsStatistics(pvsStats);2938 2939 static float expectedValue = pvsStats.avgPvs;2940 2941 // the current view cells are kept in this container2942 ViewCellContainer viewCells;2943 if (mExportMergedViewCells)2944 {2945 ViewCell::NewMail();2946 CollectViewCells(mRoot, true, viewCells, true);2947 }2948 2949 2950 ViewCell::NewMail();2951 2952 MergeStatistics mergeStats;2953 mergeStats.Start();2954 2955 long startTime = GetTime();2956 2957 cout << "collecting merge candidates ... " << endl;2958 2959 if (mUseRaysForMerge)2960 {2961 mergeStats.nodes = CollectMergeCandidates(rays);2962 }2963 else2964 {2965 vector<BspLeaf *> leaves;2966 CollectLeaves(leaves);2967 mergeStats.nodes = CollectMergeCandidates(leaves);2968 }2969 2970 cout << "fininshed collecting candidates" << endl;2971 2972 mergeStats.collectTime = TimeDiff(startTime, GetTime());2973 mergeStats.candidates = (int)mMergeQueue.size();2974 startTime = GetTime();2975 2976 // frequency stats are updated2977 const int statsOut = 100;2978 2979 // number of view cells withouth the invalid ones2980 BspMergeCandidate::sNumViewCells = mBspStats.Leaves() - mBspStats.invalidLeaves;2981 2982 // passes are needed for statistics, because we don't want to record2983 // every merge2984 const int maxMergesPerPass = 100;2985 int pass = 0;2986 2987 // maximal ratio of old expected render cost to expected render2988 // when the the render queue has to be reset.2989 const float ercMaxRatio = 0.7f;2990 2991 cout << "actual merge starts now ... " << endl;2992 2993 2994 2995 //-- use priority queue to merge leaf pairs2996 2997 2998 while (!mMergeQueue.empty() &&2999 (BspMergeCandidate::sNumViewCells > mMergeMinViewCells) &&3000 (mMergeQueue.top().GetMergeCost() < mMergeMaxCostRatio * BspMergeCandidate::sOverallCost))3001 {3002 3003 int mergedPerPass = 0;3004 const float oldExpectedCost = BspMergeCandidate::sExpectedCost;3005 3006 //#ifdef _DEBUG3007 Debug << "abs mergecost: " << mMergeQueue.top().GetMergeCost() << " rel mergecost: "3008 << mMergeQueue.top().GetMergeCost() / BspMergeCandidate::sOverallCost3009 << " max ratio: " << mMergeMaxCostRatio << endl3010 << " expected value: " << oldExpectedCost << endl;3011 //#endif3012 3013 while (!mMergeQueue.empty() &&3014 (BspMergeCandidate::sNumViewCells > mMergeMinViewCells) &&3015 (ercMaxRatio > oldExpectedCost / BspMergeCandidate::sExpectedCost) &&3016 (mMergeQueue.top().GetMergeCost() < mMergeMaxCostRatio * BspMergeCandidate::sOverallCost) &&3017 (maxMergesPerPass < mergedPerPass));3018 {3019 Debug << "erc max ratio" << ercMaxRatio << endl;3020 3021 BspMergeCandidate mc = mMergeQueue.top();3022 mMergeQueue.pop();3023 3024 // both view cells equal!3025 if (mc.GetLeaf1()->GetViewCell() == mc.GetLeaf2()->GetViewCell())3026 continue;3027 3028 if (mc.Valid())3029 {3030 ViewCell::NewMail();3031 const float currentMergeCost = mc.GetMergeCost();3032 3033 MergeViewCells(mc.GetLeaf1(), mc.GetLeaf2());3034 3035 -- BspMergeCandidate::sNumViewCells;3036 ++ mergeStats.merged;3037 ++ mergedPerPass;3038 3039 // increase absolute merge cost3040 BspMergeCandidate::sOverallCost += mc.GetRenderCost();3041 BspMergeCandidate::sVariance = mc.GetVarianceIncr();3042 3043 BspMergeCandidate::sExpectedCost =3044 BspMergeCandidate::sOverallCost / (float)BspMergeCandidate::sNumViewCells;3045 3046 // stats3047 if (mc.GetLeaf1()->IsSibling(mc.GetLeaf2()))3048 ++ mergeStats.siblings;3049 3050 if (0)3051 {3052 const int dist =3053 TreeDistance(mc.GetLeaf1(), mc.GetLeaf2());3054 if (dist > mergeStats.maxTreeDist)3055 mergeStats.maxTreeDist = dist;3056 mergeStats.accTreeDist += dist;3057 }3058 3059 if ((mergeStats.merged % statsOut) == 0)3060 {3061 cout << "merged " << mergeStats.merged << " view cells" << endl;3062 3063 mStats3064 << "#Pass\n" << pass << endl3065 << "#Merged\n" << mergeStats.merged << endl3066 << "#Viewcells\n" << BspMergeCandidate::sNumViewCells << endl3067 << "#OverallCost\n" << BspMergeCandidate::sOverallCost << endl3068 << "#CurrentCost\n" << currentMergeCost << endl3069 << "#RelativeCost\n" << currentMergeCost / BspMergeCandidate::sOverallCost << endl3070 << "#CurrentPvs\n" << mc.GetLeaf1()->GetViewCell()->GetPvs().GetSize() << endl3071 << "#MergedSiblings\n" << mergeStats.siblings << endl3072 << "#AvgTreeDist\n" << mergeStats.AvgTreeDist() << endl3073 << "#ExpectedCost\n" << BspMergeCandidate::sExpectedCost << endl3074 << "#RatioExpectedCost\n" << oldExpectedCost / BspMergeCandidate::sExpectedCost << endl3075 << "#variance\n" << BspMergeCandidate::sVariance << endl;3076 3077 if (mExportMergedViewCells)3078 ExportMergedViewCells(viewCells, objects, BspMergeCandidate::sNumViewCells);3079 }3080 }3081 else3082 {3083 3084 // merge candidate not valid, because one of the leaves was already3085 // merged with another one => validate and reinsert into queue3086 mc.SetValid();3087 mMergeQueue.push(mc);3088 }3089 }3090 3091 3092 ++ pass;3093 }3094 3095 mergeStats.overallCost = BspMergeCandidate::sOverallCost;3096 3097 mergeStats.mergeTime = TimeDiff(startTime, GetTime());3098 mergeStats.Stop();3099 3100 Debug << mergeStats << endl << endl;3101 3102 // delete the view cells which were already merged3103 CLEAR_CONTAINER(mOldViewCells);3104 3105 3106 //TODO: should return sample contributions?3107 return mergeStats.merged;3108 }3109 3110 #else3111 3112 int VspBspTree::MergeViewCells(const VssRayContainer &rays, const ObjectContainer &objects)3113 {3114 BspMergeCandidate::sViewCellsManager = mViewCellsManager;3115 BspMergeCandidate::sUseArea = mUseAreaForPvs;3116 3117 ViewCellsManager::PvsStatistics pvsStats;3118 mViewCellsManager->GetPvsStatistics(pvsStats);3119 3120 static float expectedValue = pvsStats.avgPvs;3121 // the current view cells are kept in this container3122 ViewCellContainer viewCells;3123 if (mExportMergedViewCells)3124 {3125 ViewCell::NewMail();3126 CollectViewCells(mRoot, true, viewCells, true);3127 }3128 ViewCell::NewMail();3129 3130 MergeStatistics mergeStats;3131 mergeStats.Start();3132 3133 //BspMergeCandidate::sOverallCost = mBox.SurfaceArea() * mBspStats.maxPvs;3134 long startTime = GetTime();3135 3136 cout << "collecting merge candidates ... " << endl;3137 3138 if (mUseRaysForMerge)3139 {3140 mergeStats.nodes = CollectMergeCandidates(rays);3141 }3142 else3143 {3144 vector<BspLeaf *> leaves;3145 CollectLeaves(leaves);3146 mergeStats.nodes = CollectMergeCandidates(leaves);3147 }3148 3149 cout << "fininshed collecting candidates" << endl;3150 3151 mergeStats.collectTime = TimeDiff(startTime, GetTime());3152 mergeStats.candidates = (int)mMergeQueue.size();3153 startTime = GetTime();3154 3155 3156 // number of view cells withouth the invalid ones3157 int nViewCells = mBspStats.Leaves() - mBspStats.invalidLeaves;3158 BspMergeCandidate::sExpectedCost = BspMergeCandidate::sOverallCost / (float)nViewCells;3159 3160 // passes are needed for statistics, because we don't want to record3161 // every merge3162 const int mergesPerPass = 100;3163 3164 int nextPass = 0;3165 int pass = 0;3166 3167 3168 Debug << "stats: " << nextStats << " " << statsIncr << endl;3169 cout << "actual merge starts now ... " << endl;3170 3171 //-- use priority queue to merge leaf pairs3172 while (!mMergeQueue.empty() && (nViewCells > mMergeMinViewCells) &&3173 (mMergeQueue.top().GetMergeCost() <3174 mMergeMaxCostRatio * BspMergeCandidate::sOverallCost))3175 {3176 #ifdef _DEBUG3177 Debug << "abs mergecost: " << mMergeQueue.top().GetMergeCost() << " rel mergecost: "3178 << mMergeQueue.top().GetMergeCost() / BspMergeCandidate::sOverallCost3179 << " max ratio: " << mMergeMaxCostRatio << endl;3180 #endif3181 3182 BspMergeCandidate mc = mMergeQueue.top();3183 mMergeQueue.pop();3184 3185 3186 // both view cells equal!3187 if (mc.GetLeaf1()->GetViewCell() == mc.GetLeaf2()->GetViewCell())3188 continue;3189 3190 if (mc.Valid())3191 {3192 ViewCell::NewMail();3193 const float mergeCost = mc.GetMergeCost();3194 3195 MergeViewCells(mc.GetLeaf1(), mc.GetLeaf2());3196 3197 // increase absolute merge cost3198 BspMergeCandidate::sOverallCost += mc.GetMergeCost();3199 3200 3201 -- nViewCells;3202 ++ mergeStats.merged;3203 3204 if ((mergeStats.merged % 500) == 0)3205 cout << "merged " << mergeStats.merged << " view cells" << endl;3206 3207 // stats and visualizations3208 if (mExportMergeStats)3209 {3210 if (mc.GetLeaf1()->IsSibling(mc.GetLeaf2()))3211 ++ mergeStats.siblings;3212 3213 if (0)3214 const int dist =3215 TreeDistance(mc.GetLeaf1(), mc.GetLeaf2());3216 if (dist > mergeStats.maxTreeDist)3217 mergeStats.maxTreeDist = dist;3218 mergeStats.accTreeDist += dist;3219 3220 if ((mergeStats.merged == nextPass) || (nViewCells == mMergeMinViewCells))3221 {3222 nextPass += mergesPerPass;3223 3224 mStats3225 << "#Pass\n" << pass ++ << endl3226 << "#Merged\n" << mergeStats.merged << endl3227 << "#Viewcells\n" << nViewCells << endl3228 << "#OverallCost\n" << BspMergeCandidate::sOverallCost << endl3229 << "#CurrentCost\n" << mergeCost << endl3230 << "#RelativeCost\n" << mergeCost / BspMergeCandidate::sOverallCost << endl3231 << "#CurrentPvs\n" << mc.GetLeaf1()->GetViewCell()->GetPvs().GetSize() << endl3232 << "#MergedSiblings\n" << mergeStats.siblings << endl3233 << "#AvgTreeDist\n" << mergeStats.AvgTreeDist() << endl;3234 3235 if (mExportMergedViewCells)3236 ExportMergedViewCells(viewCells, objects, nViewCells);3237 }3238 }3239 }3240 // merge candidate not valid, because one of the leaves was already3241 // merged with another one => validate and reinsert into queue3242 else3243 {3244 mc.SetValid();3245 mMergeQueue.push(mc);3246 }3247 }3248 3249 mergeStats.overallCost = BspMergeCandidate::sOverallCost;3250 3251 mergeStats.mergeTime = TimeDiff(startTime, GetTime());3252 mergeStats.Stop();3253 3254 Debug << mergeStats << endl << endl;3255 3256 // delete the view cells which were already merged3257 CLEAR_CONTAINER(mOldViewCells);3258 3259 3260 //TODO: should return sample contributions?3261 return mergeStats.merged;3262 }3263 #endif3264 2819 3265 2820 … … 3297 2852 3298 2853 3299 void VspBspTree::ExportMergedViewCells(ViewCellContainer &viewCells,3300 const ObjectContainer &objects,3301 const int nViewCells)3302 {3303 ViewCellContainer::const_iterator vit, vit_end = viewCells.end();3304 3305 // find all already merged view cells and remove them from view cells3306 int i = 0;3307 3308 while (1)3309 {3310 //while (!viewCells.empty() && (viewCells.back()->mMailbox == -1))3311 while (!viewCells.empty() && (viewCells.back()->GetId() == -2))3312 {3313 //DEL_PTR(viewCells.back());3314 viewCells.pop_back();3315 }3316 // all merged view cells have been found3317 if (i >= viewCells.size())3318 break;3319 3320 // already merged view cell, put it to end of vector3321 //if (viewCells[i]->mMailbox == -1)3322 if (viewCells[i]->GetId() == -2)3323 swap(viewCells[i], viewCells.back());3324 3325 ++ i;3326 }3327 3328 int newVcSize = 0;3329 // add new view cells to container only if they don't have been3330 // merged in the mean time3331 while (!mNewViewCells.empty())3332 {3333 if (mNewViewCells.back()->GetId() != -2)3334 {3335 viewCells.push_back(mNewViewCells.back());3336 ++ newVcSize;3337 }3338 3339 mNewViewCells.pop_back();3340 }3341 3342 char s[64];3343 sprintf(s, "merged_viewcells%07d.x3d", nViewCells);3344 Exporter *exporter = Exporter::GetExporter(s);3345 3346 if (exporter)3347 {3348 cout << "exporting " << nViewCells << " merged view cells ... ";3349 exporter->ExportGeometry(objects);3350 //Debug << "vc size " << (int)viewCells.size() << " merge queue size: " << (int)mMergeQueue.size() << endl;3351 ViewCellContainer::const_iterator it, it_end = viewCells.end();3352 3353 int i = 0;3354 for (it = viewCells.begin(); it != it_end; ++ it)3355 {3356 Material m;3357 // assign special material to new view cells3358 // new view cells are on the back of container3359 if (i ++ >= (viewCells.size() - newVcSize))3360 {3361 //m = RandomMaterial();3362 m.mDiffuseColor.r = RandomValue(0.5f, 1.0f);3363 m.mDiffuseColor.g = RandomValue(0.5f, 1.0f);3364 m.mDiffuseColor.b = RandomValue(0.5f, 1.0f);3365 }3366 else3367 {3368 float col = RandomValue(0.1f, 0.4f);3369 m.mDiffuseColor.r = col;3370 m.mDiffuseColor.g = col;3371 m.mDiffuseColor.b = col;3372 }3373 3374 exporter->SetForcedMaterial(m);3375 mViewCellsManager->ExportVcGeometry(exporter, *it);3376 }3377 delete exporter;3378 cout << "finished" << endl;3379 }3380 3381 // delete the view cells which were merged3382 CLEAR_CONTAINER(mOldViewCells);3383 // remove the new view cells3384 mNewViewCells.clear();3385 }3386 3387 3388 int VspBspTree::RefineViewCells(const VssRayContainer &rays, const ObjectContainer &objects)3389 {3390 Debug << "refining " << (int)mMergeQueue.size() << " candidates " << endl;3391 3392 BspLeaf::NewMail();3393 3394 // Use priority queue of remaining leaf pairs3395 // The candidates either share the same view cells or3396 // are border leaves which share a boundary.3397 // We test if they can be shuffled, i.e.,3398 // either one leaf is made part of one view cell or the other3399 // leaf is made part of the other view cell. It is tested if the3400 // remaining view cells are "better" than the old ones.3401 //3402 // repeat the merging test numPasses times. For example, it could be3403 // that a shuffle only makes sense if another pair was shuffled before.3404 // Therefore we keep two queues and shift the merge candidates between3405 // those two queues until numPasses is reached3406 3407 queue<BspMergeCandidate> queue1;3408 queue<BspMergeCandidate> queue2;3409 3410 queue<BspMergeCandidate> *shuffleQueue = &queue1;3411 queue<BspMergeCandidate> *backQueue = &queue2;3412 3413 while (!mMergeQueue.empty())3414 {3415 BspMergeCandidate mc = mMergeQueue.top();3416 shuffleQueue->push(mc);3417 mMergeQueue.pop();3418 }3419 3420 const int numPasses = 5;3421 int pass = 0;3422 int passShuffled = 0;3423 int shuffled = 0;3424 3425 BspLeaf::NewMail();3426 3427 do3428 {3429 passShuffled = 0;3430 while (!shuffleQueue->empty())3431 {3432 BspMergeCandidate mc = shuffleQueue->front();3433 shuffleQueue->pop();3434 3435 // both view cells equal or already shuffled3436 if ((mc.GetLeaf1()->GetViewCell() == mc.GetLeaf2()->GetViewCell()))// ||3437 // (mc.GetLeaf1()->Mailed()) || (mc.GetLeaf2()->Mailed()))3438 continue;3439 3440 // candidate for shuffling3441 const bool wasShuffled =3442 ShuffleLeaves(mc.GetLeaf1(), mc.GetLeaf2());3443 3444 if (wasShuffled)3445 ++ passShuffled;3446 else3447 backQueue->push(mc);3448 }3449 3450 // now the back queue is the current shuffle queue3451 swap(shuffleQueue, backQueue);3452 shuffled += passShuffled;3453 Debug << "shuffled in pass: " << passShuffled << endl;3454 }3455 while (((++ pass) < numPasses) && passShuffled);3456 3457 while (!shuffleQueue->empty())3458 {3459 shuffleQueue->pop();3460 }3461 3462 return shuffled;3463 }3464 3465 3466 inline int AddedPvsSize(ObjectPvs pvs1, const ObjectPvs &pvs2)3467 {3468 return pvs1.AddPvs(pvs2);3469 }3470 3471 3472 // recomputes pvs size minus pvs of leaf l3473 #if 03474 inline int SubtractedPvsSize(BspViewCell *vc, BspLeaf *l, const ObjectPvs &pvs2)3475 {3476 ObjectPvs pvs;3477 vector<BspLeaf *>::const_iterator it, it_end = vc->mLeaves.end();3478 for (it = vc->mLeaves.begin(); it != vc->mLeaves.end(); ++ it)3479 if (*it != l)3480 pvs.AddPvs(*(*it)->mPvs);3481 return pvs.GetSize();3482 }3483 #endif3484 3485 // computes pvs1 minus pvs23486 inline int SubtractedPvsSize(ObjectPvs pvs1, const ObjectPvs &pvs2)3487 {3488 return pvs1.SubtractPvs(pvs2);3489 }3490 3491 3492 float VspBspTree::GetShuffledVcCost(BspLeaf *leaf, BspViewCell *vc1, BspViewCell *vc2) const3493 {3494 //const int pvs1 = SubtractedPvsSize(vc1, leaf, *leaf->mPvs);3495 const int pvs1 = SubtractedPvsSize(vc1->GetPvs(), *leaf->mPvs);3496 const int pvs2 = AddedPvsSize(vc2->GetPvs(), *leaf->mPvs);3497 3498 // don't shuffle leaves with pvs > max3499 if (pvs1 + pvs2 > mViewCellsManager->GetMaxPvsSize())3500 return 1e15f;3501 3502 #if 13503 float p1, p2;3504 3505 if (mUseAreaForPvs)3506 {3507 p1 = vc1->GetArea() - leaf->mProbability;3508 p2 = vc2->GetArea() + leaf->mProbability;3509 }3510 else3511 {3512 p1 = vc1->GetVolume() - leaf->mProbability;3513 p2 = vc2->GetVolume() + leaf->mProbability;3514 }3515 3516 const float cost1 = pvs1 * p1;3517 const float cost2 = pvs2 * p2;3518 #else3519 const float cost1 = pvs1;3520 const float cost2 = pvs2;3521 #endif3522 3523 return cost1 + cost2;3524 }3525 3526 3527 void VspBspTree::ShuffleLeaf(BspLeaf *leaf,3528 BspViewCell *vc1,3529 BspViewCell *vc2) const3530 {3531 // compute new pvs and area3532 vc1->GetPvs().SubtractPvs(*leaf->mPvs);3533 vc2->GetPvs().AddPvs(*leaf->mPvs);3534 3535 if (mUseAreaForPvs)3536 {3537 vc1->SetArea(vc1->GetArea() - leaf->mProbability);3538 vc2->SetArea(vc2->GetArea() + leaf->mProbability);3539 }3540 else3541 {3542 vc1->SetVolume(vc1->GetVolume() - leaf->mProbability);3543 vc2->SetVolume(vc2->GetVolume() + leaf->mProbability);3544 }3545 3546 /// add to second view cell3547 vc2->mLeaves.push_back(leaf);3548 3549 // erase leaf from old view cell3550 vector<BspLeaf *>::iterator it = vc1->mLeaves.begin();3551 3552 for (; *it != leaf; ++ it);3553 vc1->mLeaves.erase(it);3554 3555 /*vc1->GetPvs().mEntries.clear();3556 for (; it != vc1->mLeaves.end(); ++ it)3557 {3558 if (*it == leaf)3559 vc1->mLeaves.erase(it);3560 else3561 vc1->GetPvs().AddPvs(*(*it)->mPvs);3562 }*/3563 3564 leaf->SetViewCell(vc2); // finally change view cell3565 }3566 3567 3568 bool VspBspTree::ShuffleLeaves(BspLeaf *leaf1, BspLeaf *leaf2) const3569 {3570 BspViewCell *vc1 = leaf1->GetViewCell();3571 BspViewCell *vc2 = leaf2->GetViewCell();3572 3573 float cost1, cost2;3574 3575 #if 13576 if (mUseAreaForPvs)3577 {3578 cost1 = vc1->GetPvs().GetSize() * vc1->GetArea();3579 cost2 = vc2->GetPvs().GetSize() * vc2->GetArea();3580 }3581 else3582 {3583 cost1 = vc1->GetPvs().GetSize() * vc1->GetVolume();3584 cost2 = vc2->GetPvs().GetSize() * vc2->GetVolume();3585 }3586 #else3587 cost1 = vc1->GetPvs().GetSize();3588 cost2 = vc2->GetPvs().GetSize();3589 #endif3590 3591 const float oldCost = cost1 + cost2;3592 3593 float shuffledCost1 = Limits::Infinity;3594 float shuffledCost2 = Limits::Infinity;3595 3596 // the view cell should not be empty after the shuffle3597 if (vc1->mLeaves.size() > 1)3598 shuffledCost1 = GetShuffledVcCost(leaf1, vc1, vc2);3599 if (vc2->mLeaves.size() > 1)3600 shuffledCost2 = GetShuffledVcCost(leaf2, vc2, vc1);3601 3602 // shuffling unsuccessful3603 if ((oldCost <= shuffledCost1) && (oldCost <= shuffledCost2))3604 return false;3605 3606 if (shuffledCost1 < shuffledCost2)3607 {3608 ShuffleLeaf(leaf1, vc1, vc2);3609 leaf1->Mail();3610 }3611 else3612 {3613 ShuffleLeaf(leaf2, vc2, vc1);3614 leaf2->Mail();3615 }3616 3617 return true;3618 }3619 3620 3621 2854 bool VspBspTree::ViewPointValid(const Vector3 &viewPoint) const 3622 2855 { … … 3713 2946 } 3714 2947 } 3715 3716 3717 /**************************************************************************/3718 /* BspMergeCandidate implementation */3719 /**************************************************************************/3720 3721 3722 BspMergeCandidate::BspMergeCandidate(BspLeaf *l1, BspLeaf *l2):3723 mRenderCost(0),3724 mVarianceIncr(0),3725 mLeaf1(l1),3726 mLeaf2(l2),3727 mLeaf1Id(l1->GetViewCell()->mMailbox),3728 mLeaf2Id(l2->GetViewCell()->mMailbox)3729 {3730 //EvalMergeCost();3731 }3732 3733 3734 float BspMergeCandidate::GetRenderCost(ViewCell *vc) const3735 {3736 if (sUseArea)3737 return vc->GetPvs().GetSize() * vc->GetArea();3738 3739 return vc->GetPvs().GetSize() * vc->GetVolume();3740 }3741 3742 3743 float BspMergeCandidate::GetLeaf1Cost() const3744 {3745 BspViewCell *vc = mLeaf1->GetViewCell();3746 3747 return GetRenderCost(vc);3748 }3749 3750 3751 float BspMergeCandidate::GetLeaf2Cost() const3752 {3753 BspViewCell *vc = mLeaf2->GetViewCell();3754 3755 return GetRenderCost(vc);3756 }3757 3758 3759 int ComputeMergedPvsSize(const ObjectPvs &pvs1, const ObjectPvs &pvs2)3760 {3761 int pvs = pvs1.GetSize();3762 3763 // compute new pvs size3764 ObjectPvsMap::const_iterator it, it_end = pvs1.mEntries.end();3765 3766 Intersectable::NewMail();3767 3768 for (it = pvs1.mEntries.begin(); it != it_end; ++ it)3769 {3770 (*it).first->Mail();3771 }3772 3773 it_end = pvs2.mEntries.end();3774 3775 for (it = pvs2.mEntries.begin(); it != it_end; ++ it)3776 {3777 Intersectable *obj = (*it).first;3778 if (!obj->Mailed())3779 ++ pvs;3780 }3781 3782 return pvs;3783 }3784 3785 3786 3787 void BspMergeCandidate::EvalMergeCost()3788 {3789 //-- compute pvs difference3790 BspViewCell *vc1 = mLeaf1->GetViewCell();3791 BspViewCell *vc2 = mLeaf2->GetViewCell();3792 3793 const int newPvs = ComputeMergedPvsSize(vc1->GetPvs(), vc2->GetPvs());3794 const float newPenalty =3795 EvalPvsPenalty(newPvs,3796 sViewCellsManager->GetMinPvsSize(),3797 sViewCellsManager->GetMaxPvsSize());3798 3799 //-- compute ratio of old cost3800 // (i.e., added size of left and right view cell times pvs size)3801 // to new rendering cost (i.e, size of merged view cell times pvs size)3802 const float oldCost = GetLeaf1Cost() + GetLeaf2Cost();3803 3804 const float newCost = sUseArea ?3805 (float)newPvs * (vc1->GetArea() + vc2->GetArea()) :3806 (float)newPvs * (vc1->GetVolume() + vc2->GetVolume());3807 3808 3809 if (newPvs > sViewCellsManager->GetMaxPvsSize()) // strong penalty if pvs size too large3810 {3811 mRenderCost = 1e15;3812 }3813 else3814 {3815 mRenderCost = newCost - oldCost;3816 }3817 3818 // merge cost also takes variance into account3819 3820 const float oldVar1 = GetLeaf1Variance();3821 const float oldVar2 = GetLeaf2Variance();3822 3823 const float newVar = (sExpectedCost - mRenderCost) * (sExpectedCost - mRenderCost);3824 3825 mVarianceIncr = (newVar - oldVar1 - oldVar2) / sNumViewCells;3826 //mMergeCost = mRenderCost + fabs(newPenalty - BspMergeCandidate::sExpectedCost) ;3827 }3828 3829 3830 void BspMergeCandidate::SetLeaf1(BspLeaf *l)3831 {3832 mLeaf1 = l;3833 }3834 3835 3836 void BspMergeCandidate::SetLeaf2(BspLeaf *l)3837 {3838 mLeaf2 = l;3839 }3840 3841 3842 BspLeaf *BspMergeCandidate::GetLeaf1() const3843 {3844 return mLeaf1;3845 }3846 3847 3848 BspLeaf *BspMergeCandidate::GetLeaf2() const3849 {3850 return mLeaf2;3851 }3852 3853 3854 bool BspMergeCandidate::Valid() const3855 {3856 return3857 (mLeaf1->GetViewCell()->mMailbox == mLeaf1Id) &&3858 (mLeaf2->GetViewCell()->mMailbox == mLeaf2Id);3859 }3860 3861 3862 float BspMergeCandidate::GetMergeCost() const3863 {3864 return mRenderCost * sRenderCostWeight + mVarianceIncr * (1.0f - sRenderCostWeight);3865 }3866 3867 3868 float BspMergeCandidate::GetRenderCost() const3869 {3870 return mRenderCost;3871 }3872 3873 3874 float BspMergeCandidate::GetVarianceIncr() const3875 {3876 return mVarianceIncr;3877 }3878 3879 float BspMergeCandidate::GetLeaf1Variance() const3880 {3881 const float leafCost = GetLeaf1Cost();3882 3883 return (sExpectedCost - leafCost) * (sExpectedCost - leafCost);3884 }3885 3886 3887 float BspMergeCandidate::GetLeaf2Variance() const3888 {3889 const float leafCost = GetLeaf2Cost();3890 3891 return (sExpectedCost - leafCost) * (sExpectedCost - leafCost);3892 }3893 3894 3895 void BspMergeCandidate::SetValid()3896 {3897 mLeaf1Id = mLeaf1->GetViewCell()->mMailbox;3898 mLeaf2Id = mLeaf2->GetViewCell()->mMailbox;3899 3900 EvalMergeCost();3901 }3902 3903 3904 /************************************************************************/3905 /* MergeStatistics implementation */3906 /************************************************************************/3907 3908 3909 void MergeStatistics::Print(ostream &app) const3910 {3911 app << "===== Merge statistics ===============\n";3912 3913 app << setprecision(4);3914 3915 app << "#N_CTIME ( Overall time [s] )\n" << Time() << " \n";3916 3917 app << "#N_CCTIME ( Collect candidates time [s] )\n" << collectTime * 1e-3f << " \n";3918 3919 app << "#N_MTIME ( Merge time [s] )\n" << mergeTime * 1e-3f << " \n";3920 3921 app << "#N_NODES ( Number of nodes before merge )\n" << nodes << "\n";3922 3923 app << "#N_CANDIDATES ( Number of merge candidates )\n" << candidates << "\n";3924 3925 app << "#N_MERGEDSIBLINGS ( Number of merged siblings )\n" << siblings << "\n";3926 3927 app << "#OVERALLCOST ( overall merge cost )\n" << overallCost << "\n";3928 3929 app << "#N_MERGEDNODES ( Number of merged nodes )\n" << merged << "\n";3930 3931 app << "#MAX_TREEDIST ( Maximal distance in tree of merged leaves )\n" << maxTreeDist << "\n";3932 3933 app << "#AVG_TREEDIST ( Average distance in tree of merged leaves )\n" << AvgTreeDist() << "\n";3934 3935 app << "===== END OF BspTree statistics ==========\n";3936 }
Note: See TracChangeset
for help on using the changeset viewer.