Blender V4.3
traversal.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009-2010 NVIDIA Corporation
2 * SPDX-FileCopyrightText: 2009-2012 Intel Corporation
3 * SPDX-FileCopyrightText: 2011-2022 Blender Foundation
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Adapted code from NVIDIA Corporation. */
8
9#if BVH_FEATURE(BVH_HAIR)
10# define NODE_INTERSECT bvh_node_intersect
11#else
12# define NODE_INTERSECT bvh_aligned_node_intersect
13#endif
14
15/* This is a template BVH traversal function, where various features can be
16 * enabled/disabled. This way we can compile optimized versions for each case
17 * without new features slowing things down.
18 *
19 * BVH_HAIR: hair curve rendering
20 * BVH_POINTCLOUD: point cloud rendering
21 * BVH_MOTION: motion blur rendering
22 */
23
25 ccl_private const Ray *ray,
27 const uint visibility)
28{
29 /* todo:
30 * - test if pushing distance on the stack helps (for non shadow rays)
31 * - separate version for shadow rays
32 * - likely and unlikely for if() statements
33 * - test restrict attribute for pointers
34 */
35
36 /* traversal stack in CUDA thread-local memory */
39
40 /* traversal variables in registers */
41 int stack_ptr = 0;
42 int node_addr = kernel_data.bvh.root;
43
44 /* ray parameters in registers */
45 float3 P = ray->P;
46 float3 dir = bvh_clamp_direction(ray->D);
47 float3 idir = bvh_inverse_direction(dir);
48 const float tmin = ray->tmin;
49 int object = OBJECT_NONE;
50
51 isect->t = ray->tmax;
52 isect->u = 0.0f;
53 isect->v = 0.0f;
54 isect->prim = PRIM_NONE;
55 isect->object = OBJECT_NONE;
56
57 /* traversal loop */
58 do {
59 do {
60 /* traverse internal nodes */
61 while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
62 int node_addr_child1, traverse_mask;
63 float dist[2];
64 float4 cnodes = kernel_data_fetch(bvh_nodes, node_addr + 0);
65
66 {
67 traverse_mask = NODE_INTERSECT(kg,
68 P,
70 dir,
71#endif
72 idir,
73 tmin,
74 isect->t,
75 node_addr,
76 visibility,
77 dist);
78 }
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
118 /* pop */
119 node_addr = traversal_stack[stack_ptr];
120 --stack_ptr;
121
122 /* primitive intersection */
123 for (; prim_addr < prim_addr2; prim_addr++) {
124 kernel_assert(kernel_data_fetch(prim_type, prim_addr) == type);
125
126 const int prim_object = (object == OBJECT_NONE) ?
127 kernel_data_fetch(prim_object, prim_addr) :
128 object;
129 const int prim = kernel_data_fetch(prim_index, prim_addr);
130 if (intersection_skip_self_shadow(ray->self, prim_object, prim)) {
131 continue;
132 }
133
134#ifdef __SHADOW_LINKING__
135 if (intersection_skip_shadow_link(kg, ray->self, prim_object)) {
136 continue;
137 }
138#endif
139
140 switch (type & PRIMITIVE_ALL) {
141 case PRIMITIVE_TRIANGLE: {
142 if (triangle_intersect(kg,
143 isect,
144 P,
145 dir,
146 tmin,
147 isect->t,
148 visibility,
149 prim_object,
150 prim,
151 prim_addr))
152 {
153 /* shadow ray early termination */
154 if (visibility & PATH_RAY_SHADOW_OPAQUE) {
155 return true;
156 }
157 }
158 break;
159 }
160#if BVH_FEATURE(BVH_MOTION)
163 isect,
164 P,
165 dir,
166 tmin,
167 isect->t,
168 ray->time,
169 visibility,
170 prim_object,
171 prim,
172 prim_addr))
173 {
174 /* shadow ray early termination */
175 if (visibility & PATH_RAY_SHADOW_OPAQUE)
176 return true;
177 }
178 break;
179 }
180#endif /* BVH_FEATURE(BVH_MOTION) */
181#if BVH_FEATURE(BVH_HAIR) && defined(__HAIR__)
186 if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
187 const float2 prim_time = kernel_data_fetch(prim_time, prim_addr);
188 if (ray->time < prim_time.x || ray->time > prim_time.y) {
189 break;
190 }
191 }
192
193 const int curve_type = kernel_data_fetch(prim_type, prim_addr);
194 const bool hit = curve_intersect(
195 kg, isect, P, dir, tmin, isect->t, prim_object, prim, ray->time, curve_type);
196 if (hit) {
197 /* shadow ray early termination */
198 if (visibility & PATH_RAY_SHADOW_OPAQUE)
199 return true;
200 }
201 break;
202 }
203#endif /* BVH_FEATURE(BVH_HAIR) */
204#if BVH_FEATURE(BVH_POINTCLOUD) && defined(__POINTCLOUD__)
205 case PRIMITIVE_POINT:
207 if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
208 const float2 prim_time = kernel_data_fetch(prim_time, prim_addr);
209 if (ray->time < prim_time.x || ray->time > prim_time.y) {
210 break;
211 }
212 }
213
214 const int point_type = kernel_data_fetch(prim_type, prim_addr);
215 const bool hit = point_intersect(
216 kg, isect, P, dir, tmin, isect->t, prim_object, prim, ray->time, point_type);
217 if (hit) {
218 /* shadow ray early termination */
219 if (visibility & PATH_RAY_SHADOW_OPAQUE)
220 return true;
221 }
222 break;
223 }
224#endif /* BVH_FEATURE(BVH_POINTCLOUD) */
225 }
226 }
227 }
228 else {
229 /* instance push */
230 object = kernel_data_fetch(prim_object, -prim_addr - 1);
231
232#if BVH_FEATURE(BVH_MOTION)
233 bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir);
234#else
235 bvh_instance_push(kg, object, ray, &P, &dir, &idir);
236#endif
237
238 ++stack_ptr;
239 kernel_assert(stack_ptr < BVH_STACK_SIZE);
241
242 node_addr = kernel_data_fetch(object_node, object);
243 }
244 }
245 } while (node_addr != ENTRYPOINT_SENTINEL);
246
247 if (stack_ptr >= 0) {
248 kernel_assert(object != OBJECT_NONE);
249
250 /* instance pop */
251 bvh_instance_pop(ray, &P, &dir, &idir);
252
253 object = OBJECT_NONE;
254 node_addr = traversal_stack[stack_ptr];
255 --stack_ptr;
256 }
257 } while (node_addr != ENTRYPOINT_SENTINEL);
258
259 return (isect->prim != PRIM_NONE);
260}
261
263 ccl_private const Ray *ray,
265 const uint visibility)
266{
267 return BVH_FUNCTION_FULL_NAME(BVH)(kg, ray, isect, visibility);
268}
269
270#undef BVH_FUNCTION_NAME
271#undef BVH_FUNCTION_FEATURES
272#undef NODE_INTERSECT
unsigned int uint
Definition bvh/bvh.h:66
ccl_device_inline bool intersection_skip_shadow_link(KernelGlobals kg, ccl_ray_data const RaySelfPrimitives &self, const int isect_object)
ccl_device_inline bool intersection_skip_self_shadow(ccl_ray_data const RaySelfPrimitives &self, const int object, const int prim)
BLI_Stack * traversal_stack
#define kernel_assert(cond)
#define kernel_data
const KernelGlobalsCPU *ccl_restrict KernelGlobals
#define kernel_data_fetch(name, index)
#define ccl_private
#define ccl_device_inline
#define ccl_device_noinline
#define __float_as_int(x)
#define BVH_FUNCTION_NAME
#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_MOTION_CURVE_RIBBON
@ PRIMITIVE_ALL
@ PRIMITIVE_MOTION
@ PRIMITIVE_MOTION_TRIANGLE
@ PRIMITIVE_CURVE_RIBBON
@ PRIMITIVE_MOTION_CURVE_THICK
@ PRIMITIVE_CURVE_THICK
@ PRIMITIVE_TRIANGLE
@ PRIMITIVE_MOTION_POINT
@ PRIMITIVE_POINT
#define PRIM_NONE
@ PATH_RAY_SHADOW_OPAQUE
#define OBJECT_NONE
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)
float x
float y
#define NODE_INTERSECT
Definition traversal.h:12
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)