00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026 #include <iostream>
00027 #include <functional>
00028 #include <algorithm>
00029 #include <limits>
00030
00031 #include "luxrays/accelerators/bvhaccel.h"
00032 #include "luxrays/core/utils.h"
00033 #include "luxrays/core/context.h"
00034
00035 using std::bind2nd;
00036 using std::ptr_fun;
00037
00038 using namespace luxrays;
00039
00040
00041
00042 BVHAccel::BVHAccel(const Context *context,
00043 const unsigned int treetype, const int csamples, const int icost,
00044 const int tcost, const float ebonus) :
00045 costSamples(csamples), isectCost(icost), traversalCost(tcost), emptyBonus(ebonus), ctx(context) {
00046
00047 if (treetype <= 2) treeType = 2;
00048 else if (treetype <= 4) treeType = 4;
00049 else treeType = 8;
00050
00051 initialized = false;
00052 }
00053
00054 void BVHAccel::Init(const std::deque<Mesh *> &meshes, const unsigned int totalVertexCount,
00055 const unsigned int totalTriangleCount) {
00056 assert (!initialized);
00057
00058 preprocessedMesh = TriangleMesh::Merge(totalVertexCount, totalTriangleCount,
00059 meshes, &preprocessedMeshIDs, &preprocessedMeshTriangleIDs);
00060 assert (preprocessedMesh->GetTotalVertexCount() == totalVertexCount);
00061 assert (preprocessedMesh->GetTotalTriangleCount() == totalTriangleCount);
00062
00063 LR_LOG(ctx, "Total vertices memory usage: " << totalVertexCount * sizeof(Point) / 1024 << "Kbytes");
00064 LR_LOG(ctx, "Total triangles memory usage: " << totalTriangleCount * sizeof(Triangle) / 1024 << "Kbytes");
00065
00066 const Point *v = preprocessedMesh->GetVertices();
00067 const Triangle *p = preprocessedMesh->GetTriangles();
00068
00069 std::vector<BVHAccelTreeNode *> bvList;
00070 for (unsigned int i = 0; i < totalTriangleCount; ++i) {
00071 BVHAccelTreeNode *ptr = new BVHAccelTreeNode();
00072 ptr->bbox = p[i].WorldBound(v);
00073
00074 ptr->bbox.Expand(RAY_EPSILON);
00075 ptr->primitive = i;
00076 ptr->leftChild = NULL;
00077 ptr->rightSibling = NULL;
00078 bvList.push_back(ptr);
00079 }
00080
00081 LR_LOG(ctx, "Building Bounding Volume Hierarchy, primitives: " << totalTriangleCount);
00082
00083 nNodes = 0;
00084 BVHAccelTreeNode *rootNode = BuildHierarchy(bvList, 0, bvList.size(), 2);
00085
00086 LR_LOG(ctx, "Pre-processing Bounding Volume Hierarchy, total nodes: " << nNodes);
00087
00088 bvhTree = new BVHAccelArrayNode[nNodes];
00089 BuildArray(rootNode, 0);
00090 FreeHierarchy(rootNode);
00091
00092 LR_LOG(ctx, "Total BVH memory usage: " << nNodes * sizeof(BVHAccelArrayNode) / 1024 << "Kbytes");
00093 LR_LOG(ctx, "Finished building Bounding Volume Hierarchy array");
00094
00095 initialized = true;
00096 }
00097
00098 BVHAccel::~BVHAccel() {
00099 if (initialized) {
00100 preprocessedMesh->Delete();
00101 delete preprocessedMesh;
00102 delete[] preprocessedMeshIDs;
00103 delete[] preprocessedMeshTriangleIDs;
00104 delete bvhTree;
00105 }
00106 }
00107
00108 void BVHAccel::FreeHierarchy(BVHAccelTreeNode *node) {
00109 if (node) {
00110 FreeHierarchy(node->leftChild);
00111 FreeHierarchy(node->rightSibling);
00112
00113 delete node;
00114 }
00115 }
00116
00117
00118
00119 bool bvh_ltf_x(BVHAccelTreeNode *n, float v) {
00120 return n->bbox.pMax.x + n->bbox.pMin.x < v;
00121 }
00122
00123 bool bvh_ltf_y(BVHAccelTreeNode *n, float v) {
00124 return n->bbox.pMax.y + n->bbox.pMin.y < v;
00125 }
00126
00127 bool bvh_ltf_z(BVHAccelTreeNode *n, float v) {
00128 return n->bbox.pMax.z + n->bbox.pMin.z < v;
00129 }
00130
00131 bool (* const bvh_ltf[3])(BVHAccelTreeNode *n, float v) = {bvh_ltf_x, bvh_ltf_y, bvh_ltf_z};
00132
00133 BVHAccelTreeNode *BVHAccel::BuildHierarchy(std::vector<BVHAccelTreeNode *> &list, unsigned int begin, unsigned int end, unsigned int axis) {
00134 unsigned int splitAxis = axis;
00135 float splitValue;
00136
00137 nNodes += 1;
00138 if (end - begin == 1)
00139 return list[begin];
00140
00141 BVHAccelTreeNode *parent = new BVHAccelTreeNode();
00142 parent->primitive = 0xffffffffu;
00143 parent->leftChild = NULL;
00144 parent->rightSibling = NULL;
00145
00146 std::vector<unsigned int> splits;
00147 splits.reserve(treeType + 1);
00148 splits.push_back(begin);
00149 splits.push_back(end);
00150 for (unsigned int i = 2; i <= treeType; i *= 2) {
00151 for (unsigned int j = 0, offset = 0; j + offset < i && splits.size() > j + 1; j += 2) {
00152 if (splits[j + 1] - splits[j] < 2) {
00153 j--;
00154 offset++;
00155 continue;
00156 }
00157
00158 FindBestSplit(list, splits[j], splits[j + 1], &splitValue, &splitAxis);
00159
00160 std::vector<BVHAccelTreeNode *>::iterator it =
00161 partition(list.begin() + splits[j], list.begin() + splits[j + 1], bind2nd(ptr_fun(bvh_ltf[splitAxis]), splitValue));
00162 unsigned int middle = distance(list.begin(), it);
00163 middle = Max(splits[j] + 1, Min(splits[j + 1] - 1, middle));
00164 splits.insert(splits.begin() + j + 1, middle);
00165 }
00166 }
00167
00168 BVHAccelTreeNode *child, *lastChild;
00169
00170 child = BuildHierarchy(list, splits[0], splits[1], splitAxis);
00171 parent->leftChild = child;
00172 parent->bbox = child->bbox;
00173 lastChild = child;
00174
00175
00176 for (unsigned int i = 1; i < splits.size() - 1; i++) {
00177 child = BuildHierarchy(list, splits[i], splits[i + 1], splitAxis);
00178 lastChild->rightSibling = child;
00179 parent->bbox = Union(parent->bbox, child->bbox);
00180 lastChild = child;
00181 }
00182
00183 return parent;
00184 }
00185
00186 void BVHAccel::FindBestSplit(std::vector<BVHAccelTreeNode *> &list, unsigned int begin, unsigned int end, float *splitValue, unsigned int *bestAxis) {
00187 if (end - begin == 2) {
00188
00189 *splitValue = (list[begin]->bbox.pMax[0] + list[begin]->bbox.pMin[0] +
00190 list[end - 1]->bbox.pMax[0] + list[end - 1]->bbox.pMin[0]) / 2;
00191 *bestAxis = 0;
00192 } else {
00193
00194 Point mean2(0, 0, 0), var(0, 0, 0);
00195 for (unsigned int i = begin; i < end; i++)
00196 mean2 += list[i]->bbox.pMax + list[i]->bbox.pMin;
00197 mean2 /= end - begin;
00198
00199
00200 for (unsigned int i = begin; i < end; i++) {
00201 Vector v = list[i]->bbox.pMax + list[i]->bbox.pMin - mean2;
00202 v.x *= v.x;
00203 v.y *= v.y;
00204 v.z *= v.z;
00205 var += v;
00206 }
00207
00208 if (var.x > var.y && var.x > var.z)
00209 *bestAxis = 0;
00210 else if (var.y > var.z)
00211 *bestAxis = 1;
00212 else
00213 *bestAxis = 2;
00214
00215 if (costSamples > 1) {
00216 BBox nodeBounds;
00217 for (unsigned int i = begin; i < end; i++)
00218 nodeBounds = Union(nodeBounds, list[i]->bbox);
00219
00220 Vector d = nodeBounds.pMax - nodeBounds.pMin;
00221 const float invTotalSA = 1.f / nodeBounds.SurfaceArea();
00222
00223
00224 float increment = 2 * d[*bestAxis] / (costSamples + 1);
00225 float bestCost = INFINITY;
00226 for (float splitVal = 2 * nodeBounds.pMin[*bestAxis] + increment; splitVal < 2 * nodeBounds.pMax[*bestAxis]; splitVal += increment) {
00227 int nBelow = 0, nAbove = 0;
00228 BBox bbBelow, bbAbove;
00229 for (unsigned int j = begin; j < end; j++) {
00230 if ((list[j]->bbox.pMax[*bestAxis] + list[j]->bbox.pMin[*bestAxis]) < splitVal) {
00231 nBelow++;
00232 bbBelow = Union(bbBelow, list[j]->bbox);
00233 } else {
00234 nAbove++;
00235 bbAbove = Union(bbAbove, list[j]->bbox);
00236 }
00237 }
00238 const float pBelow = bbBelow.SurfaceArea() * invTotalSA;
00239 const float pAbove = bbAbove.SurfaceArea() * invTotalSA;
00240 float eb = (nAbove == 0 || nBelow == 0) ? emptyBonus : 0.f;
00241 float cost = traversalCost + isectCost * (1.f - eb) * (pBelow * nBelow + pAbove * nAbove);
00242
00243 if (cost < bestCost) {
00244 bestCost = cost;
00245 *splitValue = splitVal;
00246 }
00247 }
00248 } else {
00249
00250 *splitValue = mean2[*bestAxis];
00251 }
00252 }
00253 }
00254
00255 unsigned int BVHAccel::BuildArray(BVHAccelTreeNode *node, unsigned int offset) {
00256
00257 while (node) {
00258 BVHAccelArrayNode *p = &bvhTree[offset];
00259
00260 p->bbox = node->bbox;
00261 p->primitive = node->primitive;
00262 offset = BuildArray(node->leftChild, offset + 1);
00263 p->skipIndex = offset;
00264
00265 node = node->rightSibling;
00266 }
00267
00268 return offset;
00269 }
00270
00271 bool BVHAccel::Intersect(const Ray *ray, RayHit *rayHit) const {
00272 assert (initialized);
00273
00274 unsigned int currentNode = 0;
00275 unsigned int stopNode = bvhTree[0].skipIndex;
00276 bool hit = false;
00277 rayHit->t = std::numeric_limits<float>::infinity();
00278 rayHit->index = 0xffffffffu;
00279 RayHit triangleHit;
00280
00281 const Point *vertices = preprocessedMesh->GetVertices();
00282 const Triangle *triangles = preprocessedMesh->GetTriangles();
00283
00284 while (currentNode < stopNode) {
00285 if (bvhTree[currentNode].bbox.IntersectP(*ray)) {
00286 if (bvhTree[currentNode].primitive != 0xffffffffu) {
00287 if (triangles[bvhTree[currentNode].primitive].Intersect(*ray, vertices, &triangleHit)) {
00288 hit = true;
00289 if (triangleHit.t < rayHit->t) {
00290 rayHit->t = triangleHit.t;
00291 rayHit->b1 = triangleHit.b1;
00292 rayHit->b2 = triangleHit.b2;
00293 rayHit->index = bvhTree[currentNode].primitive;
00294 }
00295 }
00296 }
00297
00298 currentNode++;
00299 } else
00300 currentNode = bvhTree[currentNode].skipIndex;
00301 }
00302
00303 return hit;
00304 }