Blender  V3.3
kernel/device/cpu/bvh.h
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Copyright 2021-2022 Blender Foundation */
3 
4 /* CPU Embree implementation of ray-scene intersection. */
5 
6 #pragma once
7 
8 #include <embree3/rtcore_ray.h>
9 #include <embree3/rtcore_scene.h>
10 
13 
14 #include "kernel/bvh/types.h"
15 #include "kernel/bvh/util.h"
16 #include "kernel/geom/object.h"
18 #include "kernel/sample/lcg.h"
19 
20 #include "util/vector.h"
21 
23 
24 #define EMBREE_IS_HAIR(x) (x & 1)
25 
26 /* Intersection context. */
27 
29  typedef enum {
32  RAY_LOCAL = 2,
33  RAY_SSS = 3,
35  } RayType;
36 
39 
40  /* For avoiding self intersections */
41  const Ray *ray;
42 
43  /* for shadow rays */
48  float throughput;
49  float max_t;
50  bool opaque_hit;
51 
52  /* for SSS Rays: */
56 
58  {
59  kg = kg_;
60  type = type_;
61  ray = NULL;
62  max_hits = 1;
63  num_hits = 0;
65  throughput = 1.0f;
66  max_t = FLT_MAX;
67  opaque_hit = false;
68  isect_s = NULL;
69  local_isect = NULL;
70  local_object_id = -1;
71  lcg_state = NULL;
72  }
73 };
74 
76  public:
78  {
79  rtcInitIntersectContext(&context);
80  userRayExt = ctx;
81  }
82  RTCIntersectContext context;
84 };
85 
86 /* Utilities. */
87 
89  RTCRay &rtc_ray,
90  const uint visibility)
91 {
92  rtc_ray.org_x = ray.P.x;
93  rtc_ray.org_y = ray.P.y;
94  rtc_ray.org_z = ray.P.z;
95  rtc_ray.dir_x = ray.D.x;
96  rtc_ray.dir_y = ray.D.y;
97  rtc_ray.dir_z = ray.D.z;
98  rtc_ray.tnear = ray.tmin;
99  rtc_ray.tfar = ray.tmax;
100  rtc_ray.time = ray.time;
101  rtc_ray.mask = visibility;
102 }
103 
105  RTCRayHit &rayhit,
106  const uint visibility)
107 {
108  kernel_embree_setup_ray(ray, rayhit.ray, visibility);
109  rayhit.hit.geomID = RTC_INVALID_GEOMETRY_ID;
110  rayhit.hit.instID[0] = RTC_INVALID_GEOMETRY_ID;
111 }
112 
114  const RTCHit *hit,
115  const Ray *ray)
116 {
117  int object, prim;
118 
119  if (hit->instID[0] != RTC_INVALID_GEOMETRY_ID) {
120  object = hit->instID[0] / 2;
121  if ((ray->self.object == object) || (ray->self.light_object == object)) {
122  RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(
123  rtcGetGeometry(kernel_data.device_bvh, hit->instID[0]));
124  prim = hit->primID +
125  (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID));
126  }
127  else {
128  return false;
129  }
130  }
131  else {
132  object = hit->geomID / 2;
133  if ((ray->self.object == object) || (ray->self.light_object == object)) {
134  prim = hit->primID +
135  (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(kernel_data.device_bvh, hit->geomID));
136  }
137  else {
138  return false;
139  }
140  }
141 
142  const bool is_hair = hit->geomID & 1;
143  if (is_hair) {
144  prim = kernel_data_fetch(curve_segments, prim).prim;
145  }
146 
147  return intersection_skip_self_shadow(ray->self, object, prim);
148 }
149 
151  const RTCRay *ray,
152  const RTCHit *hit,
153  Intersection *isect)
154 {
155  isect->t = ray->tfar;
156  if (hit->instID[0] != RTC_INVALID_GEOMETRY_ID) {
157  RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(
158  rtcGetGeometry(kernel_data.device_bvh, hit->instID[0]));
159  isect->prim = hit->primID +
160  (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID));
161  isect->object = hit->instID[0] / 2;
162  }
163  else {
164  isect->prim = hit->primID + (intptr_t)rtcGetGeometryUserData(
165  rtcGetGeometry(kernel_data.device_bvh, hit->geomID));
166  isect->object = hit->geomID / 2;
167  }
168 
169  const bool is_hair = hit->geomID & 1;
170  if (is_hair) {
171  const KernelCurveSegment segment = kernel_data_fetch(curve_segments, isect->prim);
172  isect->type = segment.type;
173  isect->prim = segment.prim;
174  isect->u = hit->u;
175  isect->v = hit->v;
176  }
177  else {
178  isect->type = kernel_data_fetch(objects, isect->object).primitive_type;
179  isect->u = hit->u;
180  isect->v = hit->v;
181  }
182 }
183 
185  KernelGlobals kg, const RTCRay *ray, const RTCHit *hit, Intersection *isect, int object)
186 {
187  isect->u = hit->u;
188  isect->v = hit->v;
189  isect->t = ray->tfar;
190  RTCScene inst_scene = (RTCScene)rtcGetGeometryUserData(
191  rtcGetGeometry(kernel_data.device_bvh, object * 2));
192  isect->prim = hit->primID +
193  (intptr_t)rtcGetGeometryUserData(rtcGetGeometry(inst_scene, hit->geomID));
194  isect->object = object;
195  isect->type = kernel_data_fetch(objects, object).primitive_type;
196 }
197 
198 /* Ray filter functions. */
199 
200 /* This gets called by Embree at every valid ray/object intersection.
201  * Things like recording subsurface or shadow hits for later evaluation
202  * as well as filtering for volume objects happen here.
203  * Cycles' own BVH does that directly inside the traversal calls. */
204 ccl_device void kernel_embree_filter_intersection_func(const RTCFilterFunctionNArguments *args)
205 {
206  /* Current implementation in Cycles assumes only single-ray intersection queries. */
207  assert(args->N == 1);
208 
209  RTCHit *hit = (RTCHit *)args->hit;
210  CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
211  const KernelGlobalsCPU *kg = ctx->kg;
212  const Ray *cray = ctx->ray;
213 
214  if (kernel_embree_is_self_intersection(kg, hit, cray)) {
215  *args->valid = 0;
216  }
217 }
218 
219 /* This gets called by Embree at every valid ray/object intersection.
220  * Things like recording subsurface or shadow hits for later evaluation
221  * as well as filtering for volume objects happen here.
222  * Cycles' own BVH does that directly inside the traversal calls.
223  */
224 ccl_device void kernel_embree_filter_occluded_func(const RTCFilterFunctionNArguments *args)
225 {
226  /* Current implementation in Cycles assumes only single-ray intersection queries. */
227  assert(args->N == 1);
228 
229  const RTCRay *ray = (RTCRay *)args->ray;
230  RTCHit *hit = (RTCHit *)args->hit;
231  CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
232  const KernelGlobalsCPU *kg = ctx->kg;
233  const Ray *cray = ctx->ray;
234 
235  switch (ctx->type) {
237  Intersection current_isect;
238  kernel_embree_convert_hit(kg, ray, hit, &current_isect);
239  if (intersection_skip_self_shadow(cray->self, current_isect.object, current_isect.prim)) {
240  *args->valid = 0;
241  return;
242  }
243  /* If no transparent shadows or max number of hits exceeded, all light is blocked. */
244  const int flags = intersection_get_shader_flags(kg, current_isect.prim, current_isect.type);
245  if (!(flags & (SD_HAS_TRANSPARENT_SHADOW)) || ctx->num_hits >= ctx->max_hits) {
246  ctx->opaque_hit = true;
247  return;
248  }
249 
250  ++ctx->num_hits;
251 
252  /* Always use baked shadow transparency for curves. */
253  if (current_isect.type & PRIMITIVE_CURVE) {
255  kg, current_isect.object, current_isect.prim, current_isect.type, current_isect.u);
256 
258  ctx->opaque_hit = true;
259  return;
260  }
261  else {
262  *args->valid = 0;
263  return;
264  }
265  }
266 
267  /* Test if we need to record this transparent intersection. */
268  const uint max_record_hits = min(ctx->max_hits, INTEGRATOR_SHADOW_ISECT_SIZE);
269  if (ctx->num_recorded_hits < max_record_hits || ray->tfar < ctx->max_t) {
270  /* If maximum number of hits was reached, replace the intersection with the
271  * highest distance. We want to find the N closest intersections. */
272  const uint num_recorded_hits = min(ctx->num_recorded_hits, max_record_hits);
273  uint isect_index = num_recorded_hits;
274  if (num_recorded_hits + 1 >= max_record_hits) {
275  float max_t = ctx->isect_s[0].t;
276  uint max_recorded_hit = 0;
277 
278  for (uint i = 1; i < num_recorded_hits; ++i) {
279  if (ctx->isect_s[i].t > max_t) {
280  max_recorded_hit = i;
281  max_t = ctx->isect_s[i].t;
282  }
283  }
284 
285  if (num_recorded_hits >= max_record_hits) {
286  isect_index = max_recorded_hit;
287  }
288 
289  /* Limit the ray distance and stop counting hits beyond this.
290  * TODO: is there some way we can tell Embree to stop intersecting beyond
291  * this distance when max number of hits is reached?. Or maybe it will
292  * become irrelevant if we make max_hits a very high number on the CPU. */
293  ctx->max_t = max(current_isect.t, max_t);
294  }
295 
296  ctx->isect_s[isect_index] = current_isect;
297  }
298 
299  /* Always increase the number of recorded hits, even beyond the maximum,
300  * so that we can detect this and trace another ray if needed. */
301  ++ctx->num_recorded_hits;
302 
303  /* This tells Embree to continue tracing. */
304  *args->valid = 0;
305  break;
306  }
309  /* Check if it's hitting the correct object. */
310  Intersection current_isect;
311  if (ctx->type == CCLIntersectContext::RAY_SSS) {
312  kernel_embree_convert_sss_hit(kg, ray, hit, &current_isect, ctx->local_object_id);
313  }
314  else {
315  kernel_embree_convert_hit(kg, ray, hit, &current_isect);
316  if (ctx->local_object_id != current_isect.object) {
317  /* This tells Embree to continue tracing. */
318  *args->valid = 0;
319  break;
320  }
321  }
322  if (intersection_skip_self_local(cray->self, current_isect.prim)) {
323  *args->valid = 0;
324  return;
325  }
326 
327  /* No intersection information requested, just return a hit. */
328  if (ctx->max_hits == 0) {
329  break;
330  }
331 
332  /* Ignore curves. */
333  if (EMBREE_IS_HAIR(hit->geomID)) {
334  /* This tells Embree to continue tracing. */
335  *args->valid = 0;
336  break;
337  }
338 
339  LocalIntersection *local_isect = ctx->local_isect;
340  int hit_idx = 0;
341 
342  if (ctx->lcg_state) {
343  /* See triangle_intersect_subsurface() for the native equivalent. */
344  for (int i = min((int)ctx->max_hits, local_isect->num_hits) - 1; i >= 0; --i) {
345  if (local_isect->hits[i].t == ray->tfar) {
346  /* This tells Embree to continue tracing. */
347  *args->valid = 0;
348  return;
349  }
350  }
351 
352  local_isect->num_hits++;
353 
354  if (local_isect->num_hits <= ctx->max_hits) {
355  hit_idx = local_isect->num_hits - 1;
356  }
357  else {
358  /* reservoir sampling: if we are at the maximum number of
359  * hits, randomly replace element or skip it */
360  hit_idx = lcg_step_uint(ctx->lcg_state) % local_isect->num_hits;
361 
362  if (hit_idx >= ctx->max_hits) {
363  /* This tells Embree to continue tracing. */
364  *args->valid = 0;
365  return;
366  }
367  }
368  }
369  else {
370  /* Record closest intersection only. */
371  if (local_isect->num_hits && current_isect.t > local_isect->hits[0].t) {
372  *args->valid = 0;
373  return;
374  }
375 
376  local_isect->num_hits = 1;
377  }
378 
379  /* record intersection */
380  local_isect->hits[hit_idx] = current_isect;
381  local_isect->Ng[hit_idx] = normalize(make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z));
382  /* This tells Embree to continue tracing. */
383  *args->valid = 0;
384  break;
385  }
387  /* Append the intersection to the end of the array. */
388  if (ctx->num_hits < ctx->max_hits) {
389  Intersection current_isect;
390  kernel_embree_convert_hit(kg, ray, hit, &current_isect);
391  if (intersection_skip_self(cray->self, current_isect.object, current_isect.prim)) {
392  *args->valid = 0;
393  return;
394  }
395 
396  Intersection *isect = &ctx->isect_s[ctx->num_hits];
397  ++ctx->num_hits;
398  *isect = current_isect;
399  /* Only primitives from volume object. */
400  uint tri_object = isect->object;
401  int object_flag = kernel_data_fetch(object_flag, tri_object);
402  if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
403  --ctx->num_hits;
404  }
405  /* This tells Embree to continue tracing. */
406  *args->valid = 0;
407  }
408  break;
409  }
411  default:
412  if (kernel_embree_is_self_intersection(kg, hit, cray)) {
413  *args->valid = 0;
414  return;
415  }
416  break;
417  }
418 }
419 
420 ccl_device void kernel_embree_filter_func_backface_cull(const RTCFilterFunctionNArguments *args)
421 {
422  const RTCRay *ray = (RTCRay *)args->ray;
423  RTCHit *hit = (RTCHit *)args->hit;
424 
425  /* Always ignore back-facing intersections. */
426  if (dot(make_float3(ray->dir_x, ray->dir_y, ray->dir_z),
427  make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z)) > 0.0f) {
428  *args->valid = 0;
429  return;
430  }
431 
432  CCLIntersectContext *ctx = ((IntersectContext *)args->context)->userRayExt;
433  const KernelGlobalsCPU *kg = ctx->kg;
434  const Ray *cray = ctx->ray;
435 
436  if (kernel_embree_is_self_intersection(kg, hit, cray)) {
437  *args->valid = 0;
438  }
439 }
440 
442  const RTCFilterFunctionNArguments *args)
443 {
444  const RTCRay *ray = (RTCRay *)args->ray;
445  RTCHit *hit = (RTCHit *)args->hit;
446 
447  /* Always ignore back-facing intersections. */
448  if (dot(make_float3(ray->dir_x, ray->dir_y, ray->dir_z),
449  make_float3(hit->Ng_x, hit->Ng_y, hit->Ng_z)) > 0.0f) {
450  *args->valid = 0;
451  return;
452  }
453 
455 }
456 
457 /* Scene intersection. */
458 
460  ccl_private const Ray *ray,
461  const uint visibility,
462  ccl_private Intersection *isect)
463 {
464  isect->t = ray->tmax;
466  IntersectContext rtc_ctx(&ctx);
467  RTCRayHit ray_hit;
468  ctx.ray = ray;
469  kernel_embree_setup_rayhit(*ray, ray_hit, visibility);
470  rtcIntersect1(kernel_data.device_bvh, &rtc_ctx.context, &ray_hit);
471  if (ray_hit.hit.geomID == RTC_INVALID_GEOMETRY_ID ||
472  ray_hit.hit.primID == RTC_INVALID_GEOMETRY_ID) {
473  return false;
474  }
475 
476  kernel_embree_convert_hit(kg, &ray_hit.ray, &ray_hit.hit, isect);
477  return true;
478 }
479 
480 #ifdef __BVH_LOCAL__
481 ccl_device_intersect bool kernel_embree_intersect_local(KernelGlobals kg,
482  ccl_private const Ray *ray,
483  ccl_private LocalIntersection *local_isect,
484  int local_object,
485  ccl_private uint *lcg_state,
486  int max_hits)
487 {
488  const bool has_bvh = !(kernel_data_fetch(object_flag, local_object) &
490  CCLIntersectContext ctx(kg,
492  ctx.lcg_state = lcg_state;
493  ctx.max_hits = max_hits;
494  ctx.ray = ray;
495  ctx.local_isect = local_isect;
496  if (local_isect) {
497  local_isect->num_hits = 0;
498  }
499  ctx.local_object_id = local_object;
500  IntersectContext rtc_ctx(&ctx);
501  RTCRay rtc_ray;
503 
504  /* If this object has its own BVH, use it. */
505  if (has_bvh) {
506  RTCGeometry geom = rtcGetGeometry(kernel_data.device_bvh, local_object * 2);
507  if (geom) {
508  float3 P = ray->P;
509  float3 dir = ray->D;
510  float3 idir = ray->D;
511  bvh_instance_motion_push(kg, local_object, ray, &P, &dir, &idir);
512 
513  rtc_ray.org_x = P.x;
514  rtc_ray.org_y = P.y;
515  rtc_ray.org_z = P.z;
516  rtc_ray.dir_x = dir.x;
517  rtc_ray.dir_y = dir.y;
518  rtc_ray.dir_z = dir.z;
519  rtc_ray.tnear = ray->tmin;
520  rtc_ray.tfar = ray->tmax;
521  RTCScene scene = (RTCScene)rtcGetGeometryUserData(geom);
523  if (scene) {
524  rtcOccluded1(scene, &rtc_ctx.context, &rtc_ray);
525  }
526  }
527  }
528  else {
529  rtcOccluded1(kernel_data.device_bvh, &rtc_ctx.context, &rtc_ray);
530  }
531 
532  /* rtcOccluded1 sets tfar to -inf if a hit was found. */
533  return (local_isect && local_isect->num_hits > 0) || (rtc_ray.tfar < 0);
534 }
535 #endif
536 
537 #ifdef __SHADOW_RECORD_ALL__
538 ccl_device_intersect bool kernel_embree_intersect_shadow_all(KernelGlobals kg,
540  ccl_private const Ray *ray,
541  uint visibility,
542  uint max_hits,
543  ccl_private uint *num_recorded_hits,
544  ccl_private float *throughput)
545 {
547  Intersection *isect_array = (Intersection *)state->shadow_isect;
548  ctx.isect_s = isect_array;
549  ctx.max_hits = max_hits;
550  ctx.ray = ray;
551  IntersectContext rtc_ctx(&ctx);
552  RTCRay rtc_ray;
553  kernel_embree_setup_ray(*ray, rtc_ray, visibility);
554  rtcOccluded1(kernel_data.device_bvh, &rtc_ctx.context, &rtc_ray);
555 
556  *num_recorded_hits = ctx.num_recorded_hits;
557  *throughput = ctx.throughput;
558  return ctx.opaque_hit;
559 }
560 #endif
561 
562 #ifdef __VOLUME__
563 ccl_device_intersect uint kernel_embree_intersect_volume(KernelGlobals kg,
564  ccl_private const Ray *ray,
565  ccl_private Intersection *isect,
566  const uint max_hits,
567  const uint visibility)
568 {
570  ctx.isect_s = isect;
571  ctx.max_hits = max_hits;
572  ctx.num_hits = 0;
573  ctx.ray = ray;
574  IntersectContext rtc_ctx(&ctx);
575  RTCRay rtc_ray;
576  kernel_embree_setup_ray(*ray, rtc_ray, visibility);
577  rtcOccluded1(kernel_data.device_bvh, &rtc_ctx.context, &rtc_ray);
578  return ctx.num_hits;
579 }
580 #endif
581 
unsigned int uint
Definition: BLI_sys_types.h:67
IntersectContext(CCLIntersectContext *ctx)
CCLIntersectContext * userRayExt
RTCIntersectContext context
#define kernel_assert(cond)
Definition: cpu/compat.h:34
#define ccl_device
Definition: cuda/compat.h:32
#define ccl_private
Definition: cuda/compat.h:48
#define ccl_device_inline
Definition: cuda/compat.h:34
#define CCL_NAMESPACE_END
Definition: cuda/compat.h:9
ccl_device_forceinline int intersection_get_shader_flags(KernelGlobals kg, const int prim, const int type)
ccl_device_inline bool intersection_skip_self_local(ccl_private const RaySelfPrimitives &self, const int prim)
#define CURVE_SHADOW_TRANSPARENCY_CUTOFF
ccl_device_inline float intersection_curve_shadow_transparency(KernelGlobals kg, const int object, const int prim, const int type, const float u)
ccl_device_inline bool intersection_skip_self_shadow(ccl_private const RaySelfPrimitives &self, const int object, const int prim)
ccl_device_inline bool intersection_skip_self(ccl_private const RaySelfPrimitives &self, const int object, const int prim)
Scene scene
#define kernel_data
const KernelGlobalsCPU *ccl_restrict KernelGlobals
#define kernel_data_fetch(name, index)
#define ccl_device_intersect
ccl_device_inline void kernel_embree_setup_rayhit(const Ray &ray, RTCRayHit &rayhit, const uint visibility)
ccl_device_inline bool kernel_embree_is_self_intersection(const KernelGlobals kg, const RTCHit *hit, const Ray *ray)
ccl_device_intersect bool kernel_embree_intersect(KernelGlobals kg, ccl_private const Ray *ray, const uint visibility, ccl_private Intersection *isect)
ccl_device void kernel_embree_filter_occluded_func(const RTCFilterFunctionNArguments *args)
ccl_device void kernel_embree_filter_occluded_func_backface_cull(const RTCFilterFunctionNArguments *args)
#define EMBREE_IS_HAIR(x)
ccl_device void kernel_embree_filter_intersection_func(const RTCFilterFunctionNArguments *args)
ccl_device_inline void kernel_embree_convert_sss_hit(KernelGlobals kg, const RTCRay *ray, const RTCHit *hit, Intersection *isect, int object)
ccl_device void kernel_embree_filter_func_backface_cull(const RTCFilterFunctionNArguments *args)
ccl_device_inline void kernel_embree_convert_hit(KernelGlobals kg, const RTCRay *ray, const RTCHit *hit, Intersection *isect)
ccl_device_inline void kernel_embree_setup_ray(const Ray &ray, RTCRay &rtc_ray, const uint visibility)
const int state
@ SD_HAS_TRANSPARENT_SHADOW
Definition: kernel/types.h:766
@ PRIMITIVE_CURVE
Definition: kernel/types.h:564
@ PATH_RAY_ALL_VISIBILITY
Definition: kernel/types.h:217
#define INTEGRATOR_SHADOW_ISECT_SIZE
Definition: kernel/types.h:53
@ SD_OBJECT_HAS_VOLUME
Definition: kernel/types.h:812
@ SD_OBJECT_TRANSFORM_APPLIED
Definition: kernel/types.h:808
CCL_NAMESPACE_BEGIN ccl_device uint lcg_step_uint(T rng)
Definition: lcg.h:11
static float P(float k)
Definition: math_interp.c:25
#define make_float3(x, y, z)
Definition: metal/compat.h:204
Segment< FEdge *, Vec3r > segment
T dot(const vec_base< T, Size > &a, const vec_base< T, Size > &b)
vec_base< T, Size > normalize(const vec_base< T, Size > &v)
#define min(a, b)
Definition: sort.c:35
_W64 int intptr_t
Definition: stdint.h:118
LocalIntersection * local_isect
CCLIntersectContext(KernelGlobals kg_, RayType type_)
struct Intersection hits[LOCAL_MAX_HITS]
Definition: kernel/types.h:973
float3 Ng[LOCAL_MAX_HITS]
Definition: kernel/types.h:974
float tmax
Definition: kernel/types.h:527
float tmin
Definition: kernel/types.h:526
float3 P
Definition: kernel/types.h:524
float time
Definition: kernel/types.h:528
RaySelfPrimitives self
Definition: kernel/types.h:530
float3 D
Definition: kernel/types.h:525
float z
float y
float x
float max