00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "luxrays/accelerators/mqbvhaccel.h"
00023 #include "luxrays/core/utils.h"
00024 #include "luxrays/core/context.h"
00025 #include "luxrays/utils/core/exttrianglemesh.h"
00026
00027 using namespace luxrays;
00028
00029 MQBVHAccel::MQBVHAccel(const Context *context,
00030 u_int fst, u_int sf) : fullSweepThreshold(fst),
00031 skipFactor(sf), accels(MeshPtrCompare), ctx(context) {
00032 initialized = false;
00033 }
00034
00035 MQBVHAccel::~MQBVHAccel() {
00036 if (initialized) {
00037 FreeAligned(nodes);
00038
00039 delete[] meshTriangleIDs;
00040 delete[] meshIDs;
00041 delete[] leafsOffset;
00042 delete[] leafsInvTransform;
00043 delete[] leafs;
00044
00045 for (std::map<Mesh *, QBVHAccel *, bool (*)(Mesh *, Mesh *)>::iterator it = accels.begin(); it != accels.end(); it++)
00046 delete it->second;
00047 }
00048 }
00049
00050 bool MQBVHAccel::MeshPtrCompare(Mesh *p0, Mesh *p1) {
00051 return p0 < p1;
00052 }
00053
00054 void MQBVHAccel::Init(const std::deque<Mesh *> &meshes, const unsigned int totalVertexCount,
00055 const unsigned int totalTriangleCount) {
00056 assert (!initialized);
00057
00058 meshList = meshes;
00059
00060
00061 nLeafs = meshList.size();
00062 LR_LOG(ctx, "MQBVH leaf count: " << nLeafs);
00063
00064 leafs = new QBVHAccel*[nLeafs];
00065 leafsInvTransform = new const Transform*[nLeafs];
00066 leafsOffset = new unsigned int[nLeafs];
00067 meshIDs = new TriangleMeshID[totalTriangleCount];
00068 meshTriangleIDs = new TriangleID[totalTriangleCount];
00069 unsigned int currentOffset = 0;
00070 double lastPrint = WallClockTime();
00071 for (unsigned int i = 0; i < nLeafs; ++i) {
00072 const double now = WallClockTime();
00073 if (now - lastPrint > 2.0) {
00074 LR_LOG(ctx, "Building QBVH for MQBVH leaf: " << i);
00075 lastPrint = now;
00076 }
00077
00078 switch (meshList[i]->GetType()) {
00079 case TYPE_TRIANGLE:
00080 case TYPE_EXT_TRIANGLE: {
00081 leafs[i] = new QBVHAccel(ctx, 4, 4 * 4, 1);
00082 leafs[i]->Init(meshList[i]);
00083 accels[meshList[i]] = leafs[i];
00084
00085 leafsInvTransform[i] = NULL;
00086 break;
00087 }
00088 case TYPE_TRIANGLE_INSTANCE: {
00089 InstanceTriangleMesh *itm = (InstanceTriangleMesh *)meshList[i];
00090
00091
00092 std::map<Mesh *, QBVHAccel *, bool (*)(Mesh *, Mesh *)>::iterator it = accels.find(itm->GetTriangleMesh());
00093
00094 if (it == accels.end()) {
00095
00096 leafs[i] = new QBVHAccel(ctx, 4, 4 * 4, 1);
00097 leafs[i]->Init(itm);
00098 accels[itm->GetTriangleMesh()] = leafs[i];
00099 } else {
00100
00101 leafs[i] = it->second;
00102 }
00103
00104 leafsInvTransform[i] = &itm->GetInvTransformation();
00105 break;
00106 }
00107 case TYPE_EXT_TRIANGLE_INSTANCE: {
00108 ExtInstanceTriangleMesh *eitm = (ExtInstanceTriangleMesh *)meshList[i];
00109
00110
00111 std::map<Mesh *, QBVHAccel *, bool (*)(Mesh *, Mesh *)>::iterator it = accels.find(eitm->GetExtTriangleMesh());
00112 if (it == accels.end()) {
00113
00114 leafs[i] = new QBVHAccel(ctx, 4, 4 * 4, 1);
00115 leafs[i]->Init(eitm);
00116 accels[eitm->GetExtTriangleMesh()] = leafs[i];
00117 } else {
00118
00119 leafs[i] = it->second;
00120 }
00121
00122 leafsInvTransform[i] = &eitm->GetInvTransformation();
00123 break;
00124 }
00125 default:
00126 assert (false);
00127 break;
00128 }
00129
00130 leafsOffset[i] = currentOffset;
00131
00132 for (unsigned int j = 0; j < meshList[i]->GetTotalTriangleCount(); ++j) {
00133 meshIDs[currentOffset + j] = i;
00134 meshTriangleIDs[currentOffset + j] = j;
00135 }
00136
00137 currentOffset += meshList[i]->GetTotalTriangleCount();
00138 }
00139
00140 maxNodes = 2 * nLeafs - 1;
00141 nodes = AllocAligned<QBVHNode>(maxNodes);
00142
00143 Update();
00144 }
00145
00146 void MQBVHAccel::Update() {
00147
00148 u_int *primsIndexes = new u_int[nLeafs];
00149
00150 nNodes = 0;
00151 for (u_int i = 0; i < maxNodes; ++i)
00152 nodes[i] = QBVHNode();
00153
00154
00155
00156
00157 BBox *primsBboxes = new BBox[nLeafs];
00158 Point *primsCentroids = new Point[nLeafs];
00159
00160 BBox centroidsBbox;
00161
00162
00163 for (u_int i = 0; i < nLeafs; ++i) {
00164
00165 primsIndexes[i] = i;
00166
00167
00168 primsBboxes[i] = meshList[i]->GetBBox();
00169 primsBboxes[i].Expand(RAY_EPSILON);
00170 primsCentroids[i] = (primsBboxes[i].pMin + primsBboxes[i].pMax) * .5f;
00171
00172
00173 worldBound = Union(worldBound, primsBboxes[i]);
00174 centroidsBbox = Union(centroidsBbox, primsCentroids[i]);
00175 }
00176
00177
00178 LR_LOG(ctx, "Building MQBVH, leafs: " << nLeafs << ", initial nodes: " << maxNodes);
00179
00180 BuildTree(0, nLeafs, primsIndexes, primsBboxes, primsCentroids,
00181 worldBound, centroidsBbox, -1, 0, 0);
00182
00183 LR_LOG(ctx, "MQBVH completed with " << nNodes << "/" << maxNodes << " nodes");
00184 LR_LOG(ctx, "Total MQBVH memory usage: " << nNodes * sizeof(QBVHNode) / 1024 << "Kbytes");
00185
00186
00187 delete[] primsBboxes;
00188 delete[] primsCentroids;
00189 delete[] primsIndexes;
00190 }
00191
00192 void MQBVHAccel::BuildTree(u_int start, u_int end, u_int *primsIndexes,
00193 BBox *primsBboxes, Point *primsCentroids, const BBox &nodeBbox,
00194 const BBox ¢roidsBbox, int32_t parentIndex, int32_t childIndex, int depth) {
00195
00196
00197 if (end - start == 1) {
00198 CreateLeaf(parentIndex, childIndex, primsIndexes[start], nodeBbox);
00199 return;
00200 }
00201
00202 int32_t currentNode = parentIndex;
00203 int32_t leftChildIndex = childIndex;
00204 int32_t rightChildIndex = childIndex + 1;
00205
00206
00207 int bins[NB_BINS];
00208
00209 BBox binsBbox[NB_BINS];
00210
00211
00212
00213
00214
00215
00216
00217 for (u_int i = 0; i < NB_BINS; ++i)
00218 bins[i] = 0;
00219
00220 u_int step = (end - start < fullSweepThreshold) ? 1 : skipFactor;
00221
00222
00223
00224
00225 const int axis = centroidsBbox.MaximumExtent();
00226
00227
00228
00229 const float k0 = centroidsBbox.pMin[axis];
00230 const float k1 = NB_BINS / (centroidsBbox.pMax[axis] - k0);
00231
00232 if (k1 == INFINITY)
00233 throw std::runtime_error("MQBVH unable to handle geometry, too many primitives with the same centroid");
00234
00235
00236
00237 if (depth % 2 == 0) {
00238 currentNode = CreateNode(parentIndex, childIndex, nodeBbox);
00239 leftChildIndex = 0;
00240 rightChildIndex = 2;
00241 }
00242
00243 for (u_int i = start; i < end; i += step) {
00244 u_int primIndex = primsIndexes[i];
00245
00246
00247
00248 const int binId = Min(NB_BINS - 1, Floor2Int(k1 * (primsCentroids[primIndex][axis] - k0)));
00249
00250 bins[binId]++;
00251 binsBbox[binId] = Union(binsBbox[binId], primsBboxes[primIndex]);
00252 }
00253
00254
00255
00256
00257
00258
00259 int nbPrimsLeft[NB_BINS];
00260 int nbPrimsRight[NB_BINS];
00261
00262 BBox bboxesLeft[NB_BINS];
00263 BBox bboxesRight[NB_BINS];
00264
00265
00266 float vLeft[NB_BINS];
00267 float vRight[NB_BINS];
00268
00269 BBox currentBboxLeft, currentBboxRight;
00270 int currentNbLeft = 0, currentNbRight = 0;
00271
00272 for (int i = 0; i < NB_BINS; ++i) {
00273
00274
00275
00276 currentNbLeft += bins[i];
00277 nbPrimsLeft[i] = currentNbLeft;
00278
00279 currentBboxLeft = Union(currentBboxLeft, binsBbox[i]);
00280 bboxesLeft[i] = currentBboxLeft;
00281
00282 vLeft[i] = currentBboxLeft.SurfaceArea();
00283
00284
00285
00286
00287
00288 int rightIndex = NB_BINS - 1 - i;
00289 currentNbRight += bins[rightIndex];
00290 nbPrimsRight[rightIndex] = currentNbRight;
00291
00292 currentBboxRight = Union(currentBboxRight, binsBbox[rightIndex]);
00293 bboxesRight[rightIndex] = currentBboxRight;
00294
00295 vRight[rightIndex] = currentBboxRight.SurfaceArea();
00296 }
00297
00298 int minBin = -1;
00299 float minCost = INFINITY;
00300
00301
00302 for (int i = 0; i < NB_BINS - 1; ++i) {
00303 float cost = vLeft[i] * nbPrimsLeft[i] +
00304 vRight[i + 1] * nbPrimsRight[i + 1];
00305 if (cost < minCost) {
00306 minBin = i;
00307 minCost = cost;
00308 }
00309 }
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320 float splitPos = centroidsBbox.pMin[axis] + (minBin + 1) *
00321 (centroidsBbox.pMax[axis] - centroidsBbox.pMin[axis]) / NB_BINS;
00322
00323 BBox leftChildBbox, rightChildBbox;
00324 BBox leftChildCentroidsBbox, rightChildCentroidsBbox;
00325
00326 u_int storeIndex = start;
00327 for (u_int i = start; i < end; ++i) {
00328 u_int primIndex = primsIndexes[i];
00329
00330 if (primsCentroids[primIndex][axis] <= splitPos) {
00331
00332 primsIndexes[i] = primsIndexes[storeIndex];
00333 primsIndexes[storeIndex] = primIndex;
00334 ++storeIndex;
00335
00336
00337
00338 leftChildBbox = Union(leftChildBbox, primsBboxes[primIndex]);
00339 leftChildCentroidsBbox = Union(leftChildCentroidsBbox, primsCentroids[primIndex]);
00340 } else {
00341
00342
00343 rightChildBbox = Union(rightChildBbox, primsBboxes[primIndex]);
00344 rightChildCentroidsBbox = Union(rightChildCentroidsBbox, primsCentroids[primIndex]);
00345 }
00346 }
00347
00348
00349 BuildTree(start, storeIndex, primsIndexes, primsBboxes, primsCentroids,
00350 leftChildBbox, leftChildCentroidsBbox, currentNode,
00351 leftChildIndex, depth + 1);
00352 BuildTree(storeIndex, end, primsIndexes, primsBboxes, primsCentroids,
00353 rightChildBbox, rightChildCentroidsBbox, currentNode,
00354 rightChildIndex, depth + 1);
00355 }
00356
00357 int32_t MQBVHAccel::CreateNode(int32_t parentIndex, int32_t childIndex,
00358 const BBox &nodeBbox) {
00359 int32_t index = nNodes++;
00360 if (nNodes >= maxNodes) {
00361 QBVHNode *newNodes = AllocAligned<QBVHNode>(2 * maxNodes);
00362 memcpy(newNodes, nodes, sizeof(QBVHNode) * maxNodes);
00363 for (u_int i = 0; i < maxNodes; ++i)
00364 newNodes[maxNodes + i] = QBVHNode();
00365 FreeAligned(nodes);
00366 nodes = newNodes;
00367 maxNodes *= 2;
00368 }
00369
00370 if (parentIndex >= 0) {
00371 nodes[parentIndex].children[childIndex] = index;
00372 nodes[parentIndex].SetBBox(childIndex, nodeBbox);
00373 }
00374
00375 return index;
00376 }
00377
00378 void MQBVHAccel::CreateLeaf(int32_t parentIndex, int32_t childIndex,
00379 u_int start, const BBox &nodeBbox) {
00380
00381 if (parentIndex < 0) {
00382
00383 nNodes = 1;
00384 parentIndex = 0;
00385 }
00386
00387 QBVHNode &node = nodes[parentIndex];
00388 node.SetBBox(childIndex, nodeBbox);
00389 node.InitializeLeaf(childIndex, 1, start);
00390 }
00391
00392 bool MQBVHAccel::Intersect(const Ray *ray, RayHit *rayHit) const {
00393
00394
00395 QuadRay ray4(*ray);
00396 __m128 invDir[3];
00397 invDir[0] = _mm_set1_ps(1.f / ray->d.x);
00398 invDir[1] = _mm_set1_ps(1.f / ray->d.y);
00399 invDir[2] = _mm_set1_ps(1.f / ray->d.z);
00400
00401 int signs[3];
00402 ray->GetDirectionSigns(signs);
00403
00404
00405
00406 int todoNode = 0;
00407 int32_t nodeStack[64];
00408 nodeStack[0] = 0;
00409
00410 while (todoNode >= 0) {
00411
00412 if (!QBVHNode::IsLeaf(nodeStack[todoNode])) {
00413 QBVHNode &node = nodes[nodeStack[todoNode]];
00414 --todoNode;
00415
00416
00417 const int32_t visit = node.BBoxIntersect(ray4, invDir, signs);
00418
00419 switch (visit) {
00420 case (0x1 | 0x0 | 0x0 | 0x0):
00421 nodeStack[++todoNode] = node.children[0];
00422 break;
00423 case (0x0 | 0x2 | 0x0 | 0x0):
00424 nodeStack[++todoNode] = node.children[1];
00425 break;
00426 case (0x1 | 0x2 | 0x0 | 0x0):
00427 nodeStack[++todoNode] = node.children[0];
00428 nodeStack[++todoNode] = node.children[1];
00429 break;
00430 case (0x0 | 0x0 | 0x4 | 0x0):
00431 nodeStack[++todoNode] = node.children[2];
00432 break;
00433 case (0x1 | 0x0 | 0x4 | 0x0):
00434 nodeStack[++todoNode] = node.children[0];
00435 nodeStack[++todoNode] = node.children[2];
00436 break;
00437 case (0x0 | 0x2 | 0x4 | 0x0):
00438 nodeStack[++todoNode] = node.children[1];
00439 nodeStack[++todoNode] = node.children[2];
00440 break;
00441 case (0x1 | 0x2 | 0x4 | 0x0):
00442 nodeStack[++todoNode] = node.children[0];
00443 nodeStack[++todoNode] = node.children[1];
00444 nodeStack[++todoNode] = node.children[2];
00445 break;
00446
00447 case (0x0 | 0x0 | 0x0 | 0x8):
00448 nodeStack[++todoNode] = node.children[3];
00449 break;
00450 case (0x1 | 0x0 | 0x0 | 0x8):
00451 nodeStack[++todoNode] = node.children[0];
00452 nodeStack[++todoNode] = node.children[3];
00453 break;
00454 case (0x0 | 0x2 | 0x0 | 0x8):
00455 nodeStack[++todoNode] = node.children[1];
00456 nodeStack[++todoNode] = node.children[3];
00457 break;
00458 case (0x1 | 0x2 | 0x0 | 0x8):
00459 nodeStack[++todoNode] = node.children[0];
00460 nodeStack[++todoNode] = node.children[1];
00461 nodeStack[++todoNode] = node.children[3];
00462 break;
00463 case (0x0 | 0x0 | 0x4 | 0x8):
00464 nodeStack[++todoNode] = node.children[2];
00465 nodeStack[++todoNode] = node.children[3];
00466 break;
00467 case (0x1 | 0x0 | 0x4 | 0x8):
00468 nodeStack[++todoNode] = node.children[0];
00469 nodeStack[++todoNode] = node.children[2];
00470 nodeStack[++todoNode] = node.children[3];
00471 break;
00472 case (0x0 | 0x2 | 0x4 | 0x8):
00473 nodeStack[++todoNode] = node.children[1];
00474 nodeStack[++todoNode] = node.children[2];
00475 nodeStack[++todoNode] = node.children[3];
00476 break;
00477 case (0x1 | 0x2 | 0x4 | 0x8):
00478 nodeStack[++todoNode] = node.children[0];
00479 nodeStack[++todoNode] = node.children[1];
00480 nodeStack[++todoNode] = node.children[2];
00481 nodeStack[++todoNode] = node.children[3];
00482 break;
00483 }
00484 } else {
00485
00486
00487
00488 const int32_t leafData = nodeStack[todoNode];
00489 --todoNode;
00490
00491 if (QBVHNode::IsEmpty(leafData))
00492 continue;
00493
00494 const unsigned int leafIndex = QBVHNode::FirstQuadIndex(leafData);
00495 QBVHAccel *qbvh = leafs[leafIndex];
00496
00497 if (leafsInvTransform[leafIndex]) {
00498 Ray r = (*leafsInvTransform[leafIndex])(*ray);
00499 RayHit rh;
00500 rh.SetMiss();
00501 if (qbvh->Intersect(&r, &rh)) {
00502 rayHit->t = rh.t;
00503 rayHit->b1 = rh.b1;
00504 rayHit->b2 = rh.b2;
00505 rayHit->index = rh.index + leafsOffset[leafIndex];
00506
00507 ray->maxt = rh.t;
00508 }
00509 } else {
00510 RayHit rh;
00511 rh.SetMiss();
00512 if (qbvh->Intersect(ray, &rh)) {
00513 rayHit->t = rh.t;
00514 rayHit->b1 = rh.b1;
00515 rayHit->b2 = rh.b2;
00516 rayHit->index = rh.index + leafsOffset[leafIndex];
00517 }
00518 }
00519 }
00520 }
00521
00522 return !rayHit->Miss();
00523 }