18 Float tmin = (b[ray.signs[
X]][
X] - ray.orig[
X]) * ray.invDir[
X];
19 Float tmax = (b[1 - ray.signs[
X]][
X] - ray.orig[
X]) * ray.invDir[
X];
20 SPH_ASSERT(!std::isnan(tmin) && !std::isnan(tmax));
21 const Float tymin = (b[ray.signs[
Y]][
Y] - ray.orig[
Y]) * ray.invDir[
Y];
22 const Float tymax = (b[1 - ray.signs[
Y]][
Y] - ray.orig[
Y]) * ray.invDir[
Y];
23 SPH_ASSERT(!std::isnan(tymin) && !std::isnan(tymax));
25 if ((tmin > tymax) || (tymin > tmax)) {
28 tmin =
max(tmin, tymin);
29 tmax =
min(tmax, tymax);
31 const Float tzmin = (b[ray.signs[
Z]][
Z] - ray.orig[
Z]) * ray.invDir[
Z];
32 const Float tzmax = (b[1 - ray.signs[
Z]][
Z] - ray.orig[
Z]) * ray.invDir[
Z];
33 SPH_ASSERT(!std::isnan(tzmin) && !std::isnan(tzmax));
35 if ((tmin > tzmax) || (tzmin > tmax)) {
38 tmin =
max(tmin, tzmin);
39 tmax =
min(tmax, tzmax);
48 template <
typename TBvhObject>
49 template <
typename TAddIntersection>
58 stack[stackIdx].idx = 0;
59 stack[stackIdx].t_min = 0._f;
61 while (stackIdx >= 0) {
62 const Size idx = stack[stackIdx].idx;
65 const BvhNode& node = nodes[idx];
71 if (node.rightOffset == 0) {
73 for (
Size primIdx = 0; primIdx < node.primCnt; ++primIdx) {
76 const TBvhObject& obj = objects[node.start + primIdx];
77 const bool hit = obj.getIntersection(ray, current);
81 const bool doContinue = addIntersection(current);
89 const bool hitc0 =
intersectBox(nodes[idx + 1].box, ray, boxHits[0], boxHits[1]);
90 const bool hitc1 =
intersectBox(nodes[idx + node.rightOffset].box, ray, boxHits[2], boxHits[3]);
94 other = idx + node.rightOffset;
96 if (boxHits[2] < boxHits[0]) {
105 stack[++stackIdx] =
BvhTraversal{ idx + 1, boxHits[0] };
107 stack[++stackIdx] =
BvhTraversal{ idx + node.rightOffset, boxHits[2] };
113 template <
typename TBvhObject>
116 intersection.
object =
nullptr;
119 if (current.
t < intersection.
t) {
120 intersection = current;
124 return intersection.
object !=
nullptr;
127 template <
typename TBvhObject>
128 template <
typename TOutIter>
140 template <
typename TBvhObject>
142 bool occluded =
false;
150 template <
typename TBvhObject>
152 objects = std::move(objs);
159 constexpr
Size UNTOUCHED = 0xffffffff;
160 constexpr
Size NO_PARENT = 0xfffffffc;
161 constexpr
Size TOUCHED_TWICE = 0xfffffffd;
164 stack[stackIdx].start = 0;
165 stack[stackIdx].
end = objects.size();
166 stack[stackIdx].parent = NO_PARENT;
171 buildNodes.
reserve(2 * objects.size());
173 while (stackIdx > 0) {
176 const Size end = nodeEntry.
end;
177 const Size primCnt = end - start;
181 node.primCnt = primCnt;
182 node.rightOffset = UNTOUCHED;
184 Box bbox = objects[start].getBBox();
185 const Vector center = objects[start].getCenter();
186 Box boxCenter(center, center);
187 for (
Size i = start + 1; i < end; ++i) {
188 bbox.
extend(objects[i].getBBox());
189 boxCenter.
extend(objects[i].getCenter());
193 if (primCnt <= leafSize) {
194 node.rightOffset = 0;
197 buildNodes.
push(node);
199 if (nodeEntry.
parent != NO_PARENT) {
200 buildNodes[nodeEntry.
parent].rightOffset--;
202 if (buildNodes[nodeEntry.
parent].rightOffset == TOUCHED_TWICE) {
203 buildNodes[nodeEntry.
parent].rightOffset = nodeCnt - 1 - nodeEntry.
parent;
207 if (node.rightOffset == 0) {
215 for (
Size i = start; i < end; ++i) {
216 if (objects[i].getCenter()[splitDim] <
split) {
222 if (mid == start || mid == end) {
223 mid = start + (end - start) / 2;
226 stack[stackIdx++] = { nodeCnt - 1, mid, end };
227 stack[stackIdx++] = { nodeCnt - 1, start, mid };
231 nodes = std::move(buildNodes);
234 template <
typename TBvhObject>
#define SPH_ASSERT(x,...)
bool intersectBox(const Box &box, const Ray &ray, Float &t_min, Float &t_max)
Finds intersections of ray with a box.
uint32_t Size
Integral type used to index arrays (by default).
double Float
Precision used withing the code. Use Float instead of float or double where precision is important.
constexpr INLINE T max(const T &f1, const T &f2)
NAMESPACE_SPH_BEGIN constexpr INLINE T min(const T &f1, const T &f2)
Minimum & Maximum value.
#define NAMESPACE_SPH_END
Array< std::string > split(const std::string &s, const char delimiter)
Splits a string into an array of string using given delimiter.
INLINE Size argMax(const Vector &v)
Returns the index of the maximum element.
void reserve(const TCounter newMaxSize)
Allocates enough memory to store the given number of elements.
INLINE void push(U &&u)
Adds new element to the end of the array, resizing the array if necessary.
INLINE TCounter size() const noexcept
Helper object defining three-dimensional interval (box).
INLINE void extend(const Vector &v)
Enlarges the box to contain the vector.
INLINE const Vector & lower() const
Returns lower bounds of the box.
INLINE const Vector & upper() const
Returns upper bounds of the box.
INLINE Vector size() const
Returns box dimensions.
Simple bounding volume hierarchy.
void build(Array< TBvhObject > &&objects)
Contructs the BVH from given set of objects.
Box getBoundingBox() const
Returns the bounding box of all objects in BVH.
bool isOccluded(const Ray &ray) const
Returns true if the ray is occluded by some geometry.
Size getAllIntersections(const Ray &ray, TOutIter iter) const
Returns all intersections of the ray.
bool getFirstIntersection(const Ray &ray, IntersectionInfo &intersection) const
Finds the closest intersection of the ray.
Array with fixed number of allocated elements.
INLINE Iterator< StorageType > end()
void swap(Sph::Array< T, TCounter > &ar1, Sph::Array< T, TCounter > &ar2)
Holds intormation about intersection.
Float t
Distance of the hit in units of ray.direction().
const BvhPrimitive * object
Object hit by the ray, or nullptr if nothing has been hit.