127 static inline bool IntersectP(
const BBox& bounds,
const Ray& ray,
const vec3& invDir,
128 const uint32_t dirIsNeg[3])
132 float tmin = (bounds[dirIsNeg[0]].x - ray.
getPosition().x) * invDir.x;
133 float tmax = (bounds[1 - dirIsNeg[0]].x - ray.
getPosition().x) * invDir.x;
134 float tymin = (bounds[dirIsNeg[1]].y - ray.
getPosition().y) * invDir.y;
135 float tymax = (bounds[1 - dirIsNeg[1]].y - ray.
getPosition().y) * invDir.y;
136 if ((tmin > tymax) || (tymin > tmax))
150 float tzmin = (bounds[dirIsNeg[2]].z - ray.
getPosition().z) * invDir.z;
151 float tzmax = (bounds[1 - dirIsNeg[2]].z - ray.
getPosition().z) * invDir.z;
152 if ((tmin > tzmax) || (tzmin > tmax))
178 else if (sm ==
"middle")
182 else if (sm ==
"equal")
191 for (
unsigned int i = 0; i < _initialMesh->size(); i++)
198 uint32_t end, uint32_t* totalNodes,
199 std::vector<Shape*>& orderedPrims)
206 for (uint32_t i = start; i < end; ++i)
208 bbox = bbox.
Union(buildData[i].bounds);
210 uint32_t nPrimitives = end - start;
211 if (nPrimitives == 1)
214 uint32_t firstPrimOffset =
static_cast<uint32_t
>(orderedPrims.size());
215 for (uint32_t i = start; i < end; ++i)
217 uint32_t primNum = buildData[i].primitiveNumber;
218 orderedPrims.push_back(
primitives.at(primNum));
220 node->
InitLeaf(firstPrimOffset, nPrimitives, bbox);
226 for (uint32_t i = start; i < end; ++i)
228 centroidBounds = centroidBounds.
Union(buildData[i].centroid);
233 uint32_t mid = (start + end) / 2;
235 if (centroidBounds.
pMax[dim] == centroidBounds.
pMin[dim])
238 uint32_t firstPrimOffset =
static_cast<uint32_t
>(orderedPrims.size());
239 for (uint32_t i = start; i < end; ++i)
241 uint32_t primNum = buildData[i].primitiveNumber;
242 orderedPrims.push_back(
primitives.at(primNum));
244 node->
InitLeaf(firstPrimOffset, nPrimitives, bbox);
254 float pmid = .5f * (centroidBounds.
pMin[dim] + centroidBounds.
pMax[dim]);
256 std::partition(&buildData[start], &buildData[end - 1] + 1,
CompareToMid(dim, pmid));
257 mid =
static_cast<uint32_t
>(midPtr - &buildData[0]);
258 if (mid != start && mid != end)
269 mid = (start + end) / 2;
270 std::nth_element(&buildData[start], &buildData[mid], &buildData[end - 1] + 1,
278 if (nPrimitives <= 4)
281 mid = (start + end) / 2;
282 std::nth_element(&buildData[start], &buildData[mid], &buildData[end - 1] + 1,
288 const int nBuckets = 12;
298 BucketInfo buckets[nBuckets];
301 for (uint32_t i = start; i < end; ++i)
303 int b = (int)(nBuckets * ((buildData[i].centroid[dim] - centroidBounds.
pMin[dim]) /
304 (centroidBounds.
pMax[dim] - centroidBounds.
pMin[dim])));
310 buckets[b].bounds = buckets[b].bounds.Union(buildData[i].bounds);
314 float cost[nBuckets - 1];
315 for (
int i = 0; i < nBuckets - 1; ++i)
318 int count0 = 0, count1 = 0;
319 for (
int j = 0; j <= i; ++j)
321 b0 = b0.
Union(buckets[j].bounds);
322 count0 += buckets[j].count;
324 for (
int j = i + 1; j < nBuckets; ++j)
326 b1 = b1.
Union(buckets[j].bounds);
327 count1 += buckets[j].count;
334 float minCost = cost[0];
335 uint32_t minCostSplit = 0;
336 for (
int i = 1; i < nBuckets - 1; ++i)
338 if (cost[i] < minCost)
349 std::partition(&buildData[start], &buildData[end - 1] + 1,
351 mid =
static_cast<uint32_t
>(pmid - &buildData[0]);
357 uint32_t firstPrimOffset =
static_cast<uint32_t
>(orderedPrims.size());
358 for (uint32_t i = start; i < end; ++i)
360 uint32_t primNum = buildData[i].primitiveNumber;
361 orderedPrims.push_back(
primitives.at(primNum));
363 node->
InitLeaf(firstPrimOffset, nPrimitives, bbox);
380 uint32_t myOffset = (*offset)++;
406 uint32_t dirIsNeg[3] = {invDir.x < 0, invDir.y < 0, invDir.z < 0};
408 uint32_t todoOffset = 0, nodeNum = 0;
414 if (::IntersectP(node->
bounds, ray, invDir, dirIsNeg))
427 ->getIntersection(*ray, currentIntersection) &&
428 currentIntersection.
t > 0.0001)
432 result.push_back(currentIntersection);
435 intermin = (*pLeafTreatmentFunction)(result, intermin);
447 nodeNum = todo[--todoOffset];
453 if (dirIsNeg[node->
axis])
455 todo[todoOffset++] = nodeNum + 1;
461 nodeNum = nodeNum + 1;
471 nodeNum = todo[--todoOffset];
487 std::vector<BVHPrimitiveInfo> buildData;
488 buildData.reserve(
shapes->size());
489 for (uint32_t i = 0; i <
shapes->size(); ++i)
497 uint32_t totalNodes = 0;
498 std::vector<Shape*> orderedPrims;
499 orderedPrims.reserve(
shapes->size());
506 for (uint32_t i = 0; i < totalNodes; ++i)
Base class for accelerators.
std::vector< Shape * > * shapes
Vector of pointers to shapes.
Definition of a bounding box which is aligned along the axis (BBox AABB).
vec3 pMax
Upper point of the BBox.
BBox Union(const BBox &b, const vec3 &p)
Union of a point and a BBox. A new BBox is created.
vec3 pMin
Lower point of the BBox.
double SurfaceArea() const
Return the BBox area (sum of the lateral areas). Used for the SAH calculation of the accelerators.
int MaximumExtend() const
Return the index of the dominant direction (maximal dimension). Index is 0 for x, 1 for y,...
virtual decimal traverse(Ray *r, std::list< Intersection > &result) const
Run this accelerator.
BVHBuildNode * recursiveBuild(std::vector< BVHPrimitiveInfo > &buildData, unsigned int start, unsigned int end, unsigned int *totalNodes, std::vector< Shape * > &orderedPrims)
std::vector< Shape * > primitives
Pointer to all the shapes (different from initialMesh) as it is reordered.
virtual bool build()
Build this accelerator.
SplitMethod splitMethod
Split method.
unsigned int maxPrimsInNode
Maximal primitives in node.
unsigned int flattenBVHTree(BVHBuildNode *node, unsigned int *offset)
BvhAccelerator(std::vector< Shape * > *_initialMesh=NULL, BBox _globalBox=BBox(), unsigned int maxProf=8, const string &sm="sah")
Default constructor.
LinearBVHNode * nodes
Nodes list.
: Describes a ray by a pair of unsigned int. The first one gives the source number (in the range 0-40...
decimal getMaxt() const
Return maxt.
decimal getMint() const
Return mint.
vec3 getPosition() const
Return starting point ray.
vec3 getDirection() const
Return direction of the ray.
base_vec3< decimal > vec3
void InitInterior(unsigned int axis, BVHBuildNode *c0, BVHBuildNode *c1)
void InitLeaf(unsigned int first, unsigned int n, const BBox &b)
unsigned int firstPrimOffset
BVHBuildNode * children[2]
BVHPrimitiveInfo(int pn, const BBox &b)
bool operator()(const BVHPrimitiveInfo &a, const BVHPrimitiveInfo &b) const
const BBox & centroidBounds
CompareToBucket(int split, int num, int d, const BBox &b)
bool operator()(const BVHPrimitiveInfo &p) const
CompareToMid(int d, decimal m)
bool operator()(const BVHPrimitiveInfo &a) const
uint32_t primitivesOffset
leaf
uint8_t axis
interior node: xyz
uint8_t pad[2]
ensure 32 byte total size
uint8_t nPrimitives
0 -> interior node
uint32_t secondChildOffset
interior