| 1 | // Copyright 2009-2021 Intel Corporation | 
| 2 | // SPDX-License-Identifier: Apache-2.0 | 
| 3 |  | 
| 4 | #include "bvh_intersector1.h" | 
| 5 | #include "node_intersector1.h" | 
| 6 | #include "bvh_traverser1.h" | 
| 7 |  | 
| 8 | #include "../geometry/intersector_iterators.h" | 
| 9 | #include "../geometry/triangle_intersector.h" | 
| 10 | #include "../geometry/trianglev_intersector.h" | 
| 11 | #include "../geometry/trianglev_mb_intersector.h" | 
| 12 | #include "../geometry/trianglei_intersector.h" | 
| 13 | #include "../geometry/quadv_intersector.h" | 
| 14 | #include "../geometry/quadi_intersector.h" | 
| 15 | #include "../geometry/curveNv_intersector.h" | 
| 16 | #include "../geometry/curveNi_intersector.h" | 
| 17 | #include "../geometry/curveNi_mb_intersector.h" | 
| 18 | #include "../geometry/linei_intersector.h" | 
| 19 | #include "../geometry/subdivpatch1_intersector.h" | 
| 20 | #include "../geometry/object_intersector.h" | 
| 21 | #include "../geometry/instance_intersector.h" | 
| 22 | #include "../geometry/subgrid_intersector.h" | 
| 23 | #include "../geometry/subgrid_mb_intersector.h" | 
| 24 | #include "../geometry/curve_intersector_virtual.h" | 
| 25 |  | 
| 26 | namespace embree | 
| 27 | { | 
| 28 |   namespace isa | 
| 29 |   { | 
| 30 |     template<int N, int types, bool robust, typename PrimitiveIntersector1> | 
| 31 |     void BVHNIntersector1<N, types, robust, PrimitiveIntersector1>::intersect(const Accel::Intersectors* __restrict__ This, | 
| 32 |                                                                               RayHit& __restrict__ ray, | 
| 33 |                                                                               IntersectContext* __restrict__ context) | 
| 34 |     { | 
| 35 |       const BVH* __restrict__ bvh = (const BVH*)This->ptr; | 
| 36 |        | 
| 37 |       /* we may traverse an empty BVH in case all geometry was invalid */ | 
| 38 |       if (bvh->root == BVH::emptyNode) | 
| 39 |         return; | 
| 40 |        | 
| 41 |       /* perform per ray precalculations required by the primitive intersector */ | 
| 42 |       Precalculations pre(ray, bvh); | 
| 43 |  | 
| 44 |       /* stack state */ | 
| 45 |       StackItemT<NodeRef> stack[stackSize];    // stack of nodes | 
| 46 |       StackItemT<NodeRef>* stackPtr = stack+1; // current stack pointer | 
| 47 |       StackItemT<NodeRef>* stackEnd = stack+stackSize; | 
| 48 |       stack[0].ptr  = bvh->root; | 
| 49 |       stack[0].dist = neg_inf; | 
| 50 |        | 
| 51 |       if (bvh->root == BVH::emptyNode) | 
| 52 |         return; | 
| 53 |        | 
| 54 |       /* filter out invalid rays */ | 
| 55 | #if defined(EMBREE_IGNORE_INVALID_RAYS) | 
| 56 |       if (!ray.valid()) return; | 
| 57 | #endif | 
| 58 |       /* verify correct input */ | 
| 59 |       assert(ray.valid()); | 
| 60 |       assert(ray.tnear() >= 0.0f); | 
| 61 |       assert(!(types & BVH_MB) || (ray.time() >= 0.0f && ray.time() <= 1.0f)); | 
| 62 |  | 
| 63 |       /* load the ray into SIMD registers */ | 
| 64 |       TravRay<N,robust> tray(ray.org, ray.dir, max(a: ray.tnear(), b: 0.0f), max(a: ray.tfar, b: 0.0f)); | 
| 65 |  | 
| 66 |       /* initialize the node traverser */ | 
| 67 |       BVHNNodeTraverser1Hit<N, types> nodeTraverser; | 
| 68 |  | 
| 69 |       /* pop loop */ | 
| 70 |       while (true) pop: | 
| 71 |       { | 
| 72 |         /* pop next node */ | 
| 73 |         if (unlikely(stackPtr == stack)) break; | 
| 74 |         stackPtr--; | 
| 75 |         NodeRef cur = NodeRef(stackPtr->ptr); | 
| 76 |  | 
| 77 |         /* if popped node is too far, pop next one */ | 
| 78 |         if (unlikely(*(float*)&stackPtr->dist > ray.tfar)) | 
| 79 |           continue; | 
| 80 |  | 
| 81 |         /* downtraversal loop */ | 
| 82 |         while (true) | 
| 83 |         { | 
| 84 |           /* intersect node */ | 
| 85 |           size_t mask; vfloat<N> tNear; | 
| 86 |           STAT3(normal.trav_nodes,1,1,1); | 
| 87 |           bool nodeIntersected = BVHNNodeIntersector1<N, types, robust>::intersect(cur, tray, ray.time(), tNear, mask); | 
| 88 |           if (unlikely(!nodeIntersected)) { STAT3(normal.trav_nodes,-1,-1,-1); break; } | 
| 89 |  | 
| 90 |           /* if no child is hit, pop next node */ | 
| 91 |           if (unlikely(mask == 0)) | 
| 92 |             goto pop; | 
| 93 |  | 
| 94 |           /* select next child and push other children */ | 
| 95 |           nodeTraverser.traverseClosestHit(cur, mask, tNear, stackPtr, stackEnd); | 
| 96 |         } | 
| 97 |  | 
| 98 |         /* this is a leaf node */ | 
| 99 |         assert(cur != BVH::emptyNode); | 
| 100 |         STAT3(normal.trav_leaves,1,1,1); | 
| 101 |         size_t num; Primitive* prim = (Primitive*)cur.leaf(num); | 
| 102 |         size_t lazy_node = 0; | 
| 103 |         PrimitiveIntersector1::intersect(This, pre, ray, context, prim, num, tray, lazy_node); | 
| 104 |         tray.tfar = ray.tfar; | 
| 105 |  | 
| 106 |         /* push lazy node onto stack */ | 
| 107 |         if (unlikely(lazy_node)) { | 
| 108 |           stackPtr->ptr = lazy_node; | 
| 109 |           stackPtr->dist = neg_inf; | 
| 110 |           stackPtr++; | 
| 111 |         } | 
| 112 |       } | 
| 113 |     } | 
| 114 |  | 
| 115 |     template<int N, int types, bool robust, typename PrimitiveIntersector1> | 
| 116 |     void BVHNIntersector1<N, types, robust, PrimitiveIntersector1>::occluded(const Accel::Intersectors* __restrict__ This, | 
| 117 |                                                                              Ray& __restrict__ ray, | 
| 118 |                                                                              IntersectContext* __restrict__ context) | 
| 119 |     { | 
| 120 |       const BVH* __restrict__ bvh = (const BVH*)This->ptr; | 
| 121 |        | 
| 122 |       /* we may traverse an empty BVH in case all geometry was invalid */ | 
| 123 |       if (bvh->root == BVH::emptyNode) | 
| 124 |         return; | 
| 125 |         | 
| 126 |       /* early out for already occluded rays */ | 
| 127 |       if (unlikely(ray.tfar < 0.0f)) | 
| 128 |         return; | 
| 129 |  | 
| 130 |       /* perform per ray precalculations required by the primitive intersector */ | 
| 131 |       Precalculations pre(ray, bvh); | 
| 132 |  | 
| 133 |       /* stack state */ | 
| 134 |       NodeRef stack[stackSize];    // stack of nodes that still need to get traversed | 
| 135 |       NodeRef* stackPtr = stack+1; // current stack pointer | 
| 136 |       NodeRef* stackEnd = stack+stackSize; | 
| 137 |       stack[0] = bvh->root; | 
| 138 |  | 
| 139 |       /* filter out invalid rays */ | 
| 140 | #if defined(EMBREE_IGNORE_INVALID_RAYS) | 
| 141 |       if (!ray.valid()) return; | 
| 142 | #endif | 
| 143 |  | 
| 144 |       /* verify correct input */ | 
| 145 |       assert(ray.valid()); | 
| 146 |       assert(ray.tnear() >= 0.0f); | 
| 147 |       assert(!(types & BVH_MB) || (ray.time() >= 0.0f && ray.time() <= 1.0f)); | 
| 148 |  | 
| 149 |       /* load the ray into SIMD registers */ | 
| 150 |       TravRay<N,robust> tray(ray.org, ray.dir, max(a: ray.tnear(), b: 0.0f), max(a: ray.tfar, b: 0.0f)); | 
| 151 |  | 
| 152 |       /* initialize the node traverser */ | 
| 153 |       BVHNNodeTraverser1Hit<N, types> nodeTraverser; | 
| 154 |  | 
| 155 |       /* pop loop */ | 
| 156 |       while (true) pop: | 
| 157 |       { | 
| 158 |         /* pop next node */ | 
| 159 |         if (unlikely(stackPtr == stack)) break; | 
| 160 |         stackPtr--; | 
| 161 |         NodeRef cur = (NodeRef)*stackPtr; | 
| 162 |  | 
| 163 |         /* downtraversal loop */ | 
| 164 |         while (true) | 
| 165 |         { | 
| 166 |           /* intersect node */ | 
| 167 |           size_t mask; vfloat<N> tNear; | 
| 168 |           STAT3(shadow.trav_nodes,1,1,1); | 
| 169 |           bool nodeIntersected = BVHNNodeIntersector1<N, types, robust>::intersect(cur, tray, ray.time(), tNear, mask); | 
| 170 |           if (unlikely(!nodeIntersected)) { STAT3(shadow.trav_nodes,-1,-1,-1); break; } | 
| 171 |  | 
| 172 |           /* if no child is hit, pop next node */ | 
| 173 |           if (unlikely(mask == 0)) | 
| 174 |             goto pop; | 
| 175 |  | 
| 176 |           /* select next child and push other children */ | 
| 177 |           nodeTraverser.traverseAnyHit(cur, mask, tNear, stackPtr, stackEnd); | 
| 178 |         } | 
| 179 |  | 
| 180 |         /* this is a leaf node */ | 
| 181 |         assert(cur != BVH::emptyNode); | 
| 182 |         STAT3(shadow.trav_leaves,1,1,1); | 
| 183 |         size_t num; Primitive* prim = (Primitive*)cur.leaf(num); | 
| 184 |         size_t lazy_node = 0; | 
| 185 |         if (PrimitiveIntersector1::occluded(This, pre, ray, context, prim, num, tray, lazy_node)) { | 
| 186 |           ray.tfar = neg_inf; | 
| 187 |           break; | 
| 188 |         } | 
| 189 |  | 
| 190 |         /* push lazy node onto stack */ | 
| 191 |         if (unlikely(lazy_node)) { | 
| 192 |           *stackPtr = (NodeRef)lazy_node; | 
| 193 |           stackPtr++; | 
| 194 |         } | 
| 195 |       } | 
| 196 |     } | 
| 197 |  | 
| 198 |     template<int N, int types, bool robust, typename PrimitiveIntersector1> | 
| 199 |     struct PointQueryDispatch | 
| 200 |     { | 
| 201 |       typedef typename PrimitiveIntersector1::Precalculations Precalculations; | 
| 202 |       typedef typename PrimitiveIntersector1::Primitive Primitive; | 
| 203 |       typedef BVHN<N> BVH; | 
| 204 |       typedef typename BVH::NodeRef NodeRef; | 
| 205 |       typedef typename BVH::AABBNode AABBNode; | 
| 206 |       typedef typename BVH::AABBNodeMB4D AABBNodeMB4D; | 
| 207 |  | 
| 208 |       static const size_t stackSize = 1+(N-1)*BVH::maxDepth+3; // +3 due to 16-wide store | 
| 209 |  | 
| 210 |       static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context) | 
| 211 |       { | 
| 212 |         const BVH* __restrict__ bvh = (const BVH*)This->ptr; | 
| 213 |          | 
| 214 |         /* we may traverse an empty BVH in case all geometry was invalid */ | 
| 215 |         if (bvh->root == BVH::emptyNode) | 
| 216 |           return false; | 
| 217 |          | 
| 218 |         /* stack state */ | 
| 219 |         StackItemT<NodeRef> stack[stackSize];    // stack of nodes | 
| 220 |         StackItemT<NodeRef>* stackPtr = stack+1; // current stack pointer | 
| 221 |         StackItemT<NodeRef>* stackEnd = stack+stackSize; | 
| 222 |         stack[0].ptr  = bvh->root; | 
| 223 |         stack[0].dist = neg_inf; | 
| 224 |          | 
| 225 |         /* verify correct input */ | 
| 226 |         assert(!(types & BVH_MB) || (query->time >= 0.0f && query->time <= 1.0f)); | 
| 227 |  | 
| 228 |         /* load the point query into SIMD registers */ | 
| 229 |         TravPointQuery<N> tquery(query->p, context->query_radius); | 
| 230 |  | 
| 231 |         /* initialize the node traverser */ | 
| 232 |         BVHNNodeTraverser1Hit<N,types> nodeTraverser; | 
| 233 |  | 
| 234 |         bool changed = false; | 
| 235 |         float cull_radius = context->query_type == POINT_QUERY_TYPE_SPHERE | 
| 236 |                           ? query->radius * query->radius | 
| 237 |                           : dot(a: context->query_radius, b: context->query_radius); | 
| 238 |  | 
| 239 |         /* pop loop */ | 
| 240 |         while (true) pop: | 
| 241 |         { | 
| 242 |           /* pop next node */ | 
| 243 |           if (unlikely(stackPtr == stack)) break; | 
| 244 |           stackPtr--; | 
| 245 |           NodeRef cur = NodeRef(stackPtr->ptr); | 
| 246 |  | 
| 247 |           /* if popped node is too far, pop next one */ | 
| 248 |           if (unlikely(*(float*)&stackPtr->dist > cull_radius)) | 
| 249 |             continue; | 
| 250 |  | 
| 251 |           /* downtraversal loop */ | 
| 252 |           while (true) | 
| 253 |           { | 
| 254 |             /* intersect node */ | 
| 255 |             size_t mask; vfloat<N> tNear; | 
| 256 |             STAT3(point_query.trav_nodes,1,1,1); | 
| 257 |             bool nodeIntersected; | 
| 258 |             if (likely(context->query_type == POINT_QUERY_TYPE_SPHERE)) { | 
| 259 |               nodeIntersected = BVHNNodePointQuerySphere1<N, types>::pointQuery(cur, tquery, query->time, tNear, mask); | 
| 260 |             } else { | 
| 261 |               nodeIntersected = BVHNNodePointQueryAABB1  <N, types>::pointQuery(cur, tquery, query->time, tNear, mask); | 
| 262 |             } | 
| 263 |             if (unlikely(!nodeIntersected)) { STAT3(point_query.trav_nodes,-1,-1,-1); break; } | 
| 264 |  | 
| 265 |             /* if no child is hit, pop next node */ | 
| 266 |             if (unlikely(mask == 0)) | 
| 267 |               goto pop; | 
| 268 |  | 
| 269 |             /* select next child and push other children */ | 
| 270 |             nodeTraverser.traverseClosestHit(cur, mask, tNear, stackPtr, stackEnd); | 
| 271 |           } | 
| 272 |  | 
| 273 |           /* this is a leaf node */ | 
| 274 |           assert(cur != BVH::emptyNode); | 
| 275 |           STAT3(point_query.trav_leaves,1,1,1); | 
| 276 |           size_t num; Primitive* prim = (Primitive*)cur.leaf(num); | 
| 277 |           size_t lazy_node = 0; | 
| 278 |           if (PrimitiveIntersector1::pointQuery(This, query, context, prim, num, tquery, lazy_node)) | 
| 279 |           { | 
| 280 |             changed = true; | 
| 281 |             tquery.rad = context->query_radius; | 
| 282 |             cull_radius = context->query_type == POINT_QUERY_TYPE_SPHERE | 
| 283 |                         ? query->radius * query->radius | 
| 284 |                         : dot(a: context->query_radius, b: context->query_radius); | 
| 285 |           } | 
| 286 |  | 
| 287 |           /* push lazy node onto stack */ | 
| 288 |           if (unlikely(lazy_node)) { | 
| 289 |             stackPtr->ptr = lazy_node; | 
| 290 |             stackPtr->dist = neg_inf; | 
| 291 |             stackPtr++; | 
| 292 |           } | 
| 293 |         } | 
| 294 |         return changed; | 
| 295 |       } | 
| 296 |     }; | 
| 297 |  | 
| 298 |     /* disable point queries for not yet supported geometry types */ | 
| 299 |     template<int N, int types, bool robust> | 
| 300 |     struct PointQueryDispatch<N, types, robust, VirtualCurveIntersector1> { | 
| 301 |       static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context) { return false; } | 
| 302 |     }; | 
| 303 |      | 
| 304 |     template<int N, int types, bool robust> | 
| 305 |     struct PointQueryDispatch<N, types, robust, SubdivPatch1Intersector1> { | 
| 306 |       static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context) { return false; } | 
| 307 |     }; | 
| 308 |      | 
| 309 |     template<int N, int types, bool robust> | 
| 310 |     struct PointQueryDispatch<N, types, robust, SubdivPatch1MBIntersector1> { | 
| 311 |       static __forceinline bool pointQuery(const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context) { return false; } | 
| 312 |     }; | 
| 313 |  | 
| 314 |     template<int N, int types, bool robust, typename PrimitiveIntersector1> | 
| 315 |     bool BVHNIntersector1<N, types, robust, PrimitiveIntersector1>::pointQuery( | 
| 316 |       const Accel::Intersectors* This, PointQuery* query, PointQueryContext* context) | 
| 317 |     { | 
| 318 |       return PointQueryDispatch<N, types, robust, PrimitiveIntersector1>::pointQuery(This, query, context); | 
| 319 |     } | 
| 320 |   } | 
| 321 | } | 
| 322 |  |