Blender V4.3
shadow_all.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
24#ifndef __KERNEL_GPU__
26#else
28#endif
29 bool
31 ccl_private const Ray *ray,
33 const uint visibility,
34 const uint max_hits,
35 ccl_private uint *r_num_recorded_hits,
36 ccl_private float *r_throughput)
37{
38 /* todo:
39 * - likely and unlikely for if() statements
40 * - test restrict attribute for pointers
41 */
42
43 /* traversal stack in CUDA thread-local memory */
46
47 /* traversal variables in registers */
48 int stack_ptr = 0;
49 int node_addr = kernel_data.bvh.root;
50
51 /* ray parameters in registers */
52 float3 P = ray->P;
53 float3 dir = bvh_clamp_direction(ray->D);
54 float3 idir = bvh_inverse_direction(dir);
55 float tmin = ray->tmin;
56 int object = OBJECT_NONE;
57 uint num_hits = 0;
58
59 /* Max distance in world space. May be dynamically reduced when max number of
60 * recorded hits is exceeded and we no longer need to find hits beyond the max
61 * distance found. */
62 const float tmax = ray->tmax;
63 float tmax_hits = tmax;
64
65 uint isect_index = 0;
66
67 *r_num_recorded_hits = 0;
68 *r_throughput = 1.0f;
69
70 /* traversal loop */
71 do {
72 do {
73 /* traverse internal nodes */
74 while (node_addr >= 0 && node_addr != ENTRYPOINT_SENTINEL) {
75 int node_addr_child1, traverse_mask;
76 float dist[2];
77 float4 cnodes = kernel_data_fetch(bvh_nodes, node_addr + 0);
78
79 traverse_mask = NODE_INTERSECT(kg,
80 P,
82 dir,
83#endif
84 idir,
85 tmin,
86 tmax,
87 node_addr,
88 visibility,
89 dist);
90
91 node_addr = __float_as_int(cnodes.z);
92 node_addr_child1 = __float_as_int(cnodes.w);
93
94 if (traverse_mask == 3) {
95 /* Both children were intersected, push the farther one. */
96 bool is_closest_child1 = (dist[1] < dist[0]);
97 if (is_closest_child1) {
98 int tmp = node_addr;
99 node_addr = node_addr_child1;
100 node_addr_child1 = tmp;
101 }
102
103 ++stack_ptr;
104 kernel_assert(stack_ptr < BVH_STACK_SIZE);
105 traversal_stack[stack_ptr] = node_addr_child1;
106 }
107 else {
108 /* One child was intersected. */
109 if (traverse_mask == 2) {
110 node_addr = node_addr_child1;
111 }
112 else if (traverse_mask == 0) {
113 /* Neither child was intersected. */
114 node_addr = traversal_stack[stack_ptr];
115 --stack_ptr;
116 }
117 }
118 }
119
120 /* if node is leaf, fetch triangle list */
121 if (node_addr < 0) {
122 float4 leaf = kernel_data_fetch(bvh_leaf_nodes, (-node_addr - 1));
123 int prim_addr = __float_as_int(leaf.x);
124
125 if (prim_addr >= 0) {
126 const int prim_addr2 = __float_as_int(leaf.y);
127 const uint type = __float_as_int(leaf.w);
128
129 /* pop */
130 node_addr = traversal_stack[stack_ptr];
131 --stack_ptr;
132
133 /* primitive intersection */
134 for (; prim_addr < prim_addr2; prim_addr++) {
135 kernel_assert((kernel_data_fetch(prim_type, prim_addr) & PRIMITIVE_ALL) ==
136 (type & PRIMITIVE_ALL));
137 bool hit;
138
139 /* todo: specialized intersect functions which don't fill in
140 * isect unless needed and check SD_HAS_TRANSPARENT_SHADOW?
141 * might give a few % performance improvement */
143
144 const int prim_object = (object == OBJECT_NONE) ?
145 kernel_data_fetch(prim_object, prim_addr) :
146 object;
147 const int prim = kernel_data_fetch(prim_index, prim_addr);
148 if (intersection_skip_self_shadow(ray->self, prim_object, prim)) {
149 continue;
150 }
151
152#ifdef __SHADOW_LINKING__
153 if (intersection_skip_shadow_link(kg, ray->self, prim_object)) {
154 continue;
155 }
156#endif
157
158 switch (type & PRIMITIVE_ALL) {
159 case PRIMITIVE_TRIANGLE: {
160 hit = triangle_intersect(
161 kg, &isect, P, dir, tmin, tmax, visibility, prim_object, prim, prim_addr);
162 break;
163 }
164#if BVH_FEATURE(BVH_MOTION)
167 &isect,
168 P,
169 dir,
170 tmin,
171 tmax,
172 ray->time,
173 visibility,
174 prim_object,
175 prim,
176 prim_addr);
177 break;
178 }
179#endif
180#if BVH_FEATURE(BVH_HAIR) && defined(__HAIR__)
185 if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
186 const float2 prim_time = kernel_data_fetch(prim_time, prim_addr);
187 if (ray->time < prim_time.x || ray->time > prim_time.y) {
188 hit = false;
189 break;
190 }
191 }
192
193 const int curve_type = kernel_data_fetch(prim_type, prim_addr);
194 hit = curve_intersect(
195 kg, &isect, P, dir, tmin, tmax, prim_object, prim, ray->time, curve_type);
196
197 break;
198 }
199#endif
200#if BVH_FEATURE(BVH_POINTCLOUD) && defined(__POINTCLOUD__)
201 case PRIMITIVE_POINT:
203 if ((type & PRIMITIVE_MOTION) && kernel_data.bvh.use_bvh_steps) {
204 const float2 prim_time = kernel_data_fetch(prim_time, prim_addr);
205 if (ray->time < prim_time.x || ray->time > prim_time.y) {
206 hit = false;
207 break;
208 }
209 }
210
211 const int point_type = kernel_data_fetch(prim_type, prim_addr);
212 hit = point_intersect(
213 kg, &isect, P, dir, tmin, tmax, prim_object, prim, ray->time, point_type);
214 break;
215 }
216#endif /* BVH_FEATURE(BVH_POINTCLOUD) */
217 default: {
218 hit = false;
219 break;
220 }
221 }
222
223 /* shadow ray early termination */
224 if (hit) {
225 /* detect if this surface has a shader with transparent shadows */
226 /* todo: optimize so primitive visibility flag indicates if
227 * the primitive has a transparent shadow shader? */
228 const int flags = intersection_get_shader_flags(kg, isect.prim, isect.type);
229
230 if (!(flags & SD_HAS_TRANSPARENT_SHADOW) || num_hits >= max_hits) {
231 /* If no transparent shadows, all light is blocked and we can
232 * stop immediately. */
233 return true;
234 }
235
236 num_hits++;
237
238 bool record_intersection = true;
239
240 /* Always use baked shadow transparency for curves. */
241 if (isect.type & PRIMITIVE_CURVE) {
243 kg, isect.object, isect.prim, isect.type, isect.u);
244
245 if (*r_throughput < CURVE_SHADOW_TRANSPARENCY_CUTOFF) {
246 return true;
247 }
248 else {
249 record_intersection = false;
250 }
251 }
252
253 if (record_intersection) {
254 /* Test if we need to record this transparent intersection. */
255
256 /* Always increase the number of recorded hits, even beyond the maximum,
257 * so that we can detect this and trace another ray if needed. */
258 ++(*r_num_recorded_hits);
259
260 const uint max_record_hits = min(max_hits, INTEGRATOR_SHADOW_ISECT_SIZE);
261 if (*r_num_recorded_hits <= max_record_hits || isect.t < tmax_hits) {
262 integrator_state_write_shadow_isect(state, &isect, isect_index);
263
264 if (*r_num_recorded_hits >= max_record_hits) {
265 /* If the maximum number of hits is reached, find the furthest intersection to
266 replace it with the next closer one. We want N closest intersections. */
267 isect_index = 0;
268 tmax_hits = INTEGRATOR_STATE_ARRAY(state, shadow_isect, 0, t);
269 for (uint i = 1; i < max_record_hits; ++i) {
270 const float isect_t = INTEGRATOR_STATE_ARRAY(state, shadow_isect, i, t);
271 if (isect_t > tmax_hits) {
272 isect_index = i;
273 tmax_hits = isect_t;
274 }
275 }
276 }
277 else {
278 isect_index = *r_num_recorded_hits;
279 }
280 }
281 }
282 }
283 }
284 }
285 else {
286 /* instance push */
287 object = kernel_data_fetch(prim_object, -prim_addr - 1);
288
289#if BVH_FEATURE(BVH_MOTION)
290 bvh_instance_motion_push(kg, object, ray, &P, &dir, &idir);
291#else
292 bvh_instance_push(kg, object, ray, &P, &dir, &idir);
293#endif
294
295 ++stack_ptr;
296 kernel_assert(stack_ptr < BVH_STACK_SIZE);
298
299 node_addr = kernel_data_fetch(object_node, object);
300 }
301 }
302 } while (node_addr != ENTRYPOINT_SENTINEL);
303
304 if (stack_ptr >= 0) {
305 kernel_assert(object != OBJECT_NONE);
306
307 /* Instance pop. */
308 bvh_instance_pop(ray, &P, &dir, &idir);
309
310 object = OBJECT_NONE;
311 node_addr = traversal_stack[stack_ptr];
312 --stack_ptr;
313 }
314 } while (node_addr != ENTRYPOINT_SENTINEL);
315
316 return false;
317}
318
320 ccl_private const Ray *ray,
322 const uint visibility,
323 const uint max_hits,
324 ccl_private uint *num_recorded_hits,
325 ccl_private float *throughput)
326{
328 kg, ray, state, visibility, max_hits, num_recorded_hits, throughput);
329}
330
331#undef BVH_FUNCTION_NAME
332#undef BVH_FUNCTION_FEATURES
333#undef NODE_INTERSECT
unsigned int uint
Definition bvh/bvh.h:66
ccl_device_forceinline int intersection_get_shader_flags(KernelGlobals kg, const int prim, const int type)
ccl_device_inline bool intersection_skip_shadow_link(KernelGlobals kg, ccl_ray_data const RaySelfPrimitives &self, const int isect_object)
#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_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_optional_struct_init
#define ccl_device
#define ccl_private
#define ccl_device_inline
#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)
@ SD_HAS_TRANSPARENT_SHADOW
@ PRIMITIVE_MOTION_CURVE_RIBBON
@ PRIMITIVE_ALL
@ PRIMITIVE_MOTION
@ PRIMITIVE_MOTION_TRIANGLE
@ PRIMITIVE_CURVE_RIBBON
@ PRIMITIVE_MOTION_CURVE_THICK
@ PRIMITIVE_CURVE
@ PRIMITIVE_CURVE_THICK
@ PRIMITIVE_TRIANGLE
@ PRIMITIVE_MOTION_POINT
@ PRIMITIVE_POINT
#define INTEGRATOR_SHADOW_ISECT_SIZE
#define OBJECT_NONE
static ulong state[N]
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)
#define NODE_INTERSECT
Definition shadow_all.h:12
#define min(a, b)
Definition sort.c:32
IntegratorShadowStateCPU *ccl_restrict IntegratorShadowState
Definition state.h:230
#define INTEGRATOR_STATE_ARRAY(state, nested_struct, array_index, member)
Definition state.h:238
ccl_device_forceinline void integrator_state_write_shadow_isect(IntegratorShadowState state, ccl_private const Intersection *ccl_restrict isect, const int index)
Definition state_util.h:263
float x
float y
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)