Blender  V3.3
volume_all.h
Go to the documentation of this file.
1 /* SPDX-License-Identifier: Apache-2.0
2  * Adapted from code Copyright 2009-2010 NVIDIA Corporation,
3  * and code copyright 2009-2012 Intel Corporation
4  *
5  * Modifications Copyright 2011-2022 Blender Foundation. */
6 
7 #if BVH_FEATURE(BVH_HAIR)
8 # define NODE_INTERSECT bvh_node_intersect
9 #else
10 # define NODE_INTERSECT bvh_aligned_node_intersect
11 #endif
12 
13 /* This is a template BVH traversal function for volumes, where
14  * various features can be enabled/disabled. This way we can compile optimized
15  * versions for each case without new features slowing things down.
16  *
17  * BVH_MOTION: motion blur rendering
18  */
19 
20 #ifndef __KERNEL_GPU__
22 #else
24 #endif
26  ccl_private const Ray *ray,
27  Intersection *isect_array,
28  const uint max_hits,
29  const uint visibility)
30 {
31  /* todo:
32  * - test if pushing distance on the stack helps (for non shadow rays)
33  * - separate version for shadow rays
34  * - likely and unlikely for if() statements
35  * - test restrict attribute for pointers
36  */
37 
38  /* traversal stack in CUDA thread-local memory */
41 
42  /* traversal variables in registers */
43  int stack_ptr = 0;
44  int node_addr = kernel_data.bvh.root;
45 
46  /* ray parameters in registers */
47  float3 P = ray->P;
48  float3 dir = bvh_clamp_direction(ray->D);
49  float3 idir = bvh_inverse_direction(dir);
50  const float tmin = ray->tmin;
51  int object = OBJECT_NONE;
52  float isect_t = ray->tmax;
53 
54  int num_hits_in_instance = 0;
55 
56  uint num_hits = 0;
57  isect_array->t = ray->tmax;
58 
59  /* traversal loop */
60  do {
61  do {
62  /* traverse internal nodes */
63  while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
64  int node_addr_child1, traverse_mask;
65  float dist[2];
66  float4 cnodes = kernel_data_fetch(bvh_nodes, node_addr + 0);
67 
68  traverse_mask = NODE_INTERSECT(kg,
69  P,
71  dir,
72 #endif
73  idir,
74  tmin,
75  isect_t,
76  node_addr,
77  visibility,
78  dist);
79 
80  node_addr = __float_as_int(cnodes.z);
81  node_addr_child1 = __float_as_int(cnodes.w);
82 
83  if (traverse_mask == 3) {
84  /* Both children were intersected, push the farther one. */
85  bool is_closest_child1 = (dist[1] < dist[0]);
86  if (is_closest_child1) {
87  int tmp = node_addr;
88  node_addr = node_addr_child1;
89  node_addr_child1 = tmp;
90  }
91 
92  ++stack_ptr;
93  kernel_assert(stack_ptr < BVH_STACK_SIZE);
94  traversal_stack[stack_ptr] = node_addr_child1;
95  }
96  else {
97  /* One child was intersected. */
98  if (traverse_mask == 2) {
99  node_addr = node_addr_child1;
100  }
101  else if (traverse_mask == 0) {
102  /* Neither child was intersected. */
103  node_addr = traversal_stack[stack_ptr];
104  --stack_ptr;
105  }
106  }
107  }
108 
109  /* if node is leaf, fetch triangle list */
110  if (node_addr < 0) {
111  float4 leaf = kernel_data_fetch(bvh_leaf_nodes, (-node_addr - 1));
112  int prim_addr = __float_as_int(leaf.x);
113 
114  if (prim_addr >= 0) {
115  const int prim_addr2 = __float_as_int(leaf.y);
116  const uint type = __float_as_int(leaf.w);
117  bool hit;
118 
119  /* pop */
120  node_addr = traversal_stack[stack_ptr];
121  --stack_ptr;
122 
123  /* primitive intersection */
124  switch (type & PRIMITIVE_ALL) {
125  case PRIMITIVE_TRIANGLE: {
126  /* intersect ray against primitive */
127  for (; prim_addr < prim_addr2; prim_addr++) {
128  kernel_assert(kernel_data_fetch(prim_type, prim_addr) == type);
129  /* only primitives from volume object */
130  const int prim_object = (object == OBJECT_NONE) ?
131  kernel_data_fetch(prim_object, prim_addr) :
132  object;
133  const int prim = kernel_data_fetch(prim_index, prim_addr);
134  if (intersection_skip_self(ray->self, prim_object, prim)) {
135  continue;
136  }
137  int object_flag = kernel_data_fetch(object_flag, prim_object);
138  if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
139  continue;
140  }
141  hit = triangle_intersect(kg,
142  isect_array,
143  P,
144  dir,
145  tmin,
146  isect_t,
147  visibility,
148  prim_object,
149  prim,
150  prim_addr);
151  if (hit) {
152  /* Move on to next entry in intersections array. */
153  isect_array++;
154  num_hits++;
155  num_hits_in_instance++;
156  isect_array->t = isect_t;
157  if (num_hits == max_hits) {
158  return num_hits;
159  }
160  }
161  }
162  break;
163  }
164 #if BVH_FEATURE(BVH_MOTION)
166  /* intersect ray against primitive */
167  for (; prim_addr < prim_addr2; prim_addr++) {
168  kernel_assert(kernel_data_fetch(prim_type, prim_addr) == type);
169  /* only primitives from volume object */
170  const int prim_object = (object == OBJECT_NONE) ?
171  kernel_data_fetch(prim_object, prim_addr) :
172  object;
173  const int prim = kernel_data_fetch(prim_index, prim_addr);
174  if (intersection_skip_self(ray->self, prim_object, prim)) {
175  continue;
176  }
177  int object_flag = kernel_data_fetch(object_flag, prim_object);
178  if ((object_flag & SD_OBJECT_HAS_VOLUME) == 0) {
179  continue;
180  }
181  hit = motion_triangle_intersect(kg,
182  isect_array,
183  P,
184  dir,
185  tmin,
186  isect_t,
187  ray->time,
188  visibility,
189  prim_object,
190  prim,
191  prim_addr);
192  if (hit) {
193  /* Move on to next entry in intersections array. */
194  isect_array++;
195  num_hits++;
196  num_hits_in_instance++;
197  isect_array->t = isect_t;
198  if (num_hits == max_hits) {
199  return num_hits;
200  }
201  }
202  }
203  break;
204  }
205 #endif /* BVH_MOTION */
206  default: {
207  break;
208  }
209  }
210  }
211  else {
212  /* instance push */
213  object = kernel_data_fetch(prim_object, -prim_addr - 1);
214  int object_flag = kernel_data_fetch(object_flag, object);
215  if (object_flag & SD_OBJECT_HAS_VOLUME) {
216 #if BVH_FEATURE(BVH_MOTION)
217  bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir);
218 #else
219  bvh_instance_push(kg, object, ray, &P, &dir, &idir);
220 #endif
221 
222  num_hits_in_instance = 0;
223  isect_array->t = isect_t;
224 
225  ++stack_ptr;
226  kernel_assert(stack_ptr < BVH_STACK_SIZE);
228 
229  node_addr = kernel_data_fetch(object_node, object);
230  }
231  else {
232  /* pop */
233  object = OBJECT_NONE;
234  node_addr = traversal_stack[stack_ptr];
235  --stack_ptr;
236  }
237  }
238  }
239  } while (node_addr != ENTRYPOINT_SENTINEL);
240 
241  if (stack_ptr >= 0) {
242  kernel_assert(object != OBJECT_NONE);
243 
244  /* Instance pop. */
245  bvh_instance_pop(ray, &P, &dir, &idir);
246 
247  object = OBJECT_NONE;
248  node_addr = traversal_stack[stack_ptr];
249  --stack_ptr;
250  }
251  } while (node_addr != ENTRYPOINT_SENTINEL);
252 
253  return num_hits;
254 }
255 
257  ccl_private const Ray *ray,
258  Intersection *isect_array,
259  const uint max_hits,
260  const uint visibility)
261 {
262  return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect_array, max_hits, visibility);
263 }
264 
265 #undef BVH_FUNCTION_NAME
266 #undef BVH_FUNCTION_FEATURES
267 #undef NODE_INTERSECT
unsigned int uint
Definition: BLI_sys_types.h:67
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
float float4[4]
Definition: bvh/bvh.h:63
#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
ccl_device_inline bool intersection_skip_self(ccl_private const RaySelfPrimitives &self, const int object, const int prim)
BLI_Stack * traversal_stack
#define kernel_data
const KernelGlobalsCPU *ccl_restrict KernelGlobals
#define kernel_data_fetch(name, index)
#define BVH_STACK_SIZE
#define BVH_FEATURE(f)
#define ENTRYPOINT_SENTINEL
#define BVH_HAIR
#define BVH_FUNCTION_FULL_NAME(prefix)
ccl_device_inline void bvh_instance_push(KernelGlobals kg, int object, ccl_private const Ray *ray, ccl_private float3 *P, ccl_private float3 *dir, ccl_private float3 *idir)
ccl_device_inline float3 bvh_clamp_direction(float3 dir)
ccl_device_inline void bvh_instance_pop(ccl_private const Ray *ray, ccl_private float3 *P, ccl_private float3 *dir, ccl_private float3 *idir)
ccl_device_inline float3 bvh_inverse_direction(float3 dir)
@ PRIMITIVE_ALL
Definition: kernel/types.h:566
@ PRIMITIVE_MOTION_TRIANGLE
Definition: kernel/types.h:559
@ PRIMITIVE_TRIANGLE
Definition: kernel/types.h:551
#define OBJECT_NONE
Definition: kernel/types.h:40
@ SD_OBJECT_HAS_VOLUME
Definition: kernel/types.h:812
static float P(float k)
Definition: math_interp.c:25
ccl_device_inline bool motion_triangle_intersect(KernelGlobals kg, ccl_private Intersection *isect, float3 P, float3 dir, float tmin, float tmax, float time, uint visibility, int object, int prim, int prim_addr)
CCL_NAMESPACE_BEGIN ccl_device_inline bool triangle_intersect(KernelGlobals kg, ccl_private Intersection *isect, float3 P, float3 dir, float tmin, float tmax, uint visibility, int object, int prim, int prim_addr)
ccl_device_inline int __float_as_int(float f)
Definition: util/math.h:243
#define NODE_INTERSECT
Definition: volume_all.h:10
ccl_device_inline uint BVH_FUNCTION_NAME(KernelGlobals kg, ccl_private const Ray *ray, Intersection *isect_array, const uint max_hits, const uint visibility)
Definition: volume_all.h:256