Blender V4.3
intersect_closest.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
8
10
14
15#include "kernel/geom/geom.h"
16
17#include "kernel/light/light.h"
18
19#include "kernel/bvh/bvh.h"
20
22
25{
26 /* When direct lighting is disabled for baking, we skip light sampling in
27 * integrate_surface_direct_light for the first bounce. Therefore, in order
28 * for MIS to be consistent, we also need to skip evaluating lights here. */
29 return (kernel_data.integrator.filter_closures & FILTER_CLOSURE_DIRECT_LIGHT) &&
30 (INTEGRATOR_STATE(state, path, bounce) == 1);
31}
32
35 const int shader_flags)
36{
37
38 /* Optional AO bounce termination.
39 * We continue evaluating emissive/transparent surfaces and volumes, similar
40 * to direct lighting. Only if we know there are none can we terminate the
41 * path immediately. */
42 if (path_state_ao_bounce(kg, state)) {
43 if (shader_flags & (SD_HAS_TRANSPARENT_SHADOW | SD_HAS_EMISSION)) {
45 }
46#ifdef __VOLUME__
47 else if (!integrator_state_volume_stack_is_empty(kg, state)) {
49 }
50#endif
51 else {
52 return true;
53 }
54 }
55
56 /* Load random number state. */
57 RNGState rng_state;
58 path_state_rng_load(state, &rng_state);
59
60 /* We perform path termination in this kernel to avoid launching shade_surface
61 * and evaluating the shader when not needed. Only for emission and transparent
62 * surfaces in front of emission do we need to evaluate the shader, since we
63 * perform MIS as part of indirect rays. */
64 const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
65 const float continuation_probability = path_state_continuation_probability(kg, state, path_flag);
66 INTEGRATOR_STATE_WRITE(state, path, continuation_probability) = continuation_probability;
67
68 guiding_record_continuation_probability(kg, state, continuation_probability);
69
70 if (continuation_probability != 1.0f) {
71 const float terminate = path_state_rng_1D(kg, &rng_state, PRNG_TERMINATE);
72
73 if (continuation_probability == 0.0f || terminate >= continuation_probability) {
74 if (shader_flags & SD_HAS_EMISSION) {
75 /* Mark path to be terminated right after shader evaluation on the surface. */
77 }
78#ifdef __VOLUME__
79 else if (!integrator_state_volume_stack_is_empty(kg, state)) {
80 /* TODO: only do this for emissive volumes. */
82 }
83#endif
84 else {
85 return true;
86 }
87 }
88 }
89
90 return false;
91}
92
93#ifdef __SHADOW_CATCHER__
94/* Split path if a shadow catcher was hit. */
95ccl_device_forceinline void integrator_split_shadow_catcher(
100{
101 /* Test if we hit a shadow catcher object, and potentially split the path to continue tracing two
102 * paths from here. */
103 const int object_flags = intersection_get_object_flags(kg, isect);
104 if (!kernel_shadow_catcher_is_path_split_bounce(kg, state, object_flags)) {
105 return;
106 }
107
108 film_write_shadow_catcher_bounce_data(kg, state, render_buffer);
109
110 /* Mark state as having done a shadow catcher split so that it stops contributing to
111 * the shadow catcher matte pass, but keeps contributing to the combined pass. */
113
114 /* Copy current state to new state. */
116
117 /* Initialize new state.
118 *
119 * Note that the splitting leaves kernel and sorting counters as-is, so use INIT semantic for
120 * the matte path. */
121
122 /* Mark current state so that it will only track contribution of shadow catcher objects ignoring
123 * non-catcher objects. */
125
126 if (kernel_data.film.pass_background != PASS_UNUSED && !kernel_data.background.transparent) {
127 /* If using background pass, schedule background shading kernel so that we have a background
128 * to alpha-over on. The background kernel will then continue the path afterwards. */
131 return;
132 }
133
134# ifdef __VOLUME__
135 if (!integrator_state_volume_stack_is_empty(kg, state)) {
136 /* Volume stack is not empty. Re-init the volume stack to exclude any non-shadow catcher
137 * objects from it, and then continue shading volume and shadow catcher surface after. */
139 return;
140 }
141# endif
142
143 /* Continue with shading shadow catcher surface. */
144 const int shader = intersection_get_shader(kg, isect);
145 const int flags = kernel_data_fetch(shaders, shader).flags;
146 const bool use_caustics = kernel_data.integrator.use_caustics &&
147 (object_flags & SD_OBJECT_CAUSTICS);
148 const bool use_raytrace_kernel = (flags & SD_HAS_RAYTRACE);
149
150 if (use_caustics) {
152 }
153 else if (use_raytrace_kernel) {
156 }
157 else {
159 }
160}
161
162/* Schedule next kernel to be executed after updating volume stack for shadow catcher. */
163template<DeviceKernel current_kernel>
164ccl_device_forceinline void integrator_intersect_next_kernel_after_shadow_catcher_volume(
166{
167 /* Continue with shading shadow catcher surface. Same as integrator_split_shadow_catcher, but
168 * using NEXT instead of INIT. */
171
172 const int shader = intersection_get_shader(kg, &isect);
173 const int flags = kernel_data_fetch(shaders, shader).flags;
174 const int object_flags = intersection_get_object_flags(kg, &isect);
175 const bool use_caustics = kernel_data.integrator.use_caustics &&
176 (object_flags & SD_OBJECT_CAUSTICS);
177 const bool use_raytrace_kernel = (flags & SD_HAS_RAYTRACE);
178
179 if (use_caustics) {
181 kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE, shader);
182 }
183 else if (use_raytrace_kernel) {
185 kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader);
186 }
187 else {
189 kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader);
190 }
191}
192
193/* Schedule next kernel to be executed after executing background shader for shadow catcher. */
194template<DeviceKernel current_kernel>
195ccl_device_forceinline void integrator_intersect_next_kernel_after_shadow_catcher_background(
197{
198# ifdef __VOLUME__
199 /* Same logic as integrator_split_shadow_catcher, but using NEXT instead of INIT. */
200 if (!integrator_state_volume_stack_is_empty(kg, state)) {
201 /* Volume stack is not empty. Re-init the volume stack to exclude any non-shadow catcher
202 * objects from it, and then continue shading volume and shadow catcher surface after. */
205 return;
206 }
207# endif
208
209 /* Continue with shading shadow catcher surface. */
210 integrator_intersect_next_kernel_after_shadow_catcher_volume<current_kernel>(kg, state);
211}
212#endif
213
214/* Schedule next kernel to be executed after intersect closest.
215 *
216 * Note that current_kernel is a template value since making this a variable
217 * leads to poor performance with CUDA atomics. */
218template<DeviceKernel current_kernel>
220 KernelGlobals kg,
224 const bool hit)
225{
226 /* Continue with volume kernel if we are inside a volume, regardless if we hit anything. */
227#ifdef __VOLUME__
228 if (!integrator_state_volume_stack_is_empty(kg, state)) {
229 const bool hit_surface = hit && !(isect->type & PRIMITIVE_LAMP);
230 const int shader = (hit_surface) ? intersection_get_shader(kg, isect) : SHADER_NONE;
231 const int flags = (hit_surface) ? kernel_data_fetch(shaders, shader).flags : 0;
232
233 if (!integrator_intersect_terminate(kg, state, flags)) {
235 }
236 else {
237 integrator_path_terminate(kg, state, current_kernel);
238 }
239 return;
240 }
241#endif
242
243 if (hit) {
244 /* Hit a surface, continue with light or surface kernel. */
245 if (isect->type & PRIMITIVE_LAMP) {
247 }
248 else {
249 /* Hit a surface, continue with surface kernel unless terminated. */
250 const int shader = intersection_get_shader(kg, isect);
251 const int flags = kernel_data_fetch(shaders, shader).flags;
252
253 if (!integrator_intersect_terminate(kg, state, flags)) {
254 const int object_flags = intersection_get_object_flags(kg, isect);
255 const bool use_caustics = kernel_data.integrator.use_caustics &&
256 (object_flags & SD_OBJECT_CAUSTICS);
257 const bool use_raytrace_kernel = (flags & SD_HAS_RAYTRACE);
258 if (use_caustics) {
260 kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE, shader);
261 }
262 else if (use_raytrace_kernel) {
264 kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader);
265 }
266 else {
268 kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader);
269 }
270
271#ifdef __SHADOW_CATCHER__
272 /* Handle shadow catcher. */
273 integrator_split_shadow_catcher(kg, state, isect, render_buffer);
274#endif
275 }
276 else {
277 integrator_path_terminate(kg, state, current_kernel);
278 }
279 }
280 }
281 else {
282 /* Nothing hit, continue with background kernel. */
284 integrator_path_terminate(kg, state, current_kernel);
285 }
286 else {
288 }
289 }
290}
291
292/* Schedule next kernel to be executed after shade volume.
293 *
294 * The logic here matches integrator_intersect_next_kernel, except that
295 * volume shading and termination testing have already been done. */
296template<DeviceKernel current_kernel>
298 KernelGlobals kg,
302{
303 if (isect->prim != PRIM_NONE) {
304 /* Hit a surface, continue with light or surface kernel. */
305 if (isect->type & PRIMITIVE_LAMP) {
307 return;
308 }
309 else {
310 /* Hit a surface, continue with surface kernel unless terminated. */
311 const int shader = intersection_get_shader(kg, isect);
312 const int flags = kernel_data_fetch(shaders, shader).flags;
313 const int object_flags = intersection_get_object_flags(kg, isect);
314 const bool use_caustics = kernel_data.integrator.use_caustics &&
315 (object_flags & SD_OBJECT_CAUSTICS);
316 const bool use_raytrace_kernel = (flags & SD_HAS_RAYTRACE);
317
318 if (use_caustics) {
320 kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE, shader);
321 }
322 else if (use_raytrace_kernel) {
324 kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE, shader);
325 }
326 else {
328 kg, state, current_kernel, DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE, shader);
329 }
330
331#ifdef __SHADOW_CATCHER__
332 /* Handle shadow catcher. */
333 integrator_split_shadow_catcher(kg, state, isect, render_buffer);
334#endif
335 return;
336 }
337 }
338 else {
339 /* Nothing hit, continue with background kernel. */
341 integrator_path_terminate(kg, state, current_kernel);
342 }
343 else {
345 }
346 }
347}
348
352{
354
355 /* Read ray from integrator state into local memory. */
358 kernel_assert(ray.tmax != 0.0f);
359
360 const uint visibility = path_state_ray_visibility(state);
361 const int last_isect_prim = INTEGRATOR_STATE(state, isect, prim);
362 const int last_isect_object = INTEGRATOR_STATE(state, isect, object);
363
364 /* Trick to use short AO rays to approximate indirect light at the end of the path. */
365 if (path_state_ao_bounce(kg, state)) {
366 ray.tmax = kernel_data.integrator.ao_bounces_distance;
367
368 if (last_isect_object != OBJECT_NONE) {
369 const float object_ao_distance = kernel_data_fetch(objects, last_isect_object).ao_distance;
370 if (object_ao_distance != 0.0f) {
371 ray.tmax = object_ao_distance;
372 }
373 }
374 }
375
376 /* Scene Intersection. */
378 isect.object = OBJECT_NONE;
379 isect.prim = PRIM_NONE;
380 ray.self.object = last_isect_object;
381 ray.self.prim = last_isect_prim;
382 ray.self.light_object = OBJECT_NONE;
383 ray.self.light_prim = PRIM_NONE;
384 ray.self.light = LAMP_NONE;
385 bool hit = scene_intersect(kg, &ray, visibility, &isect);
386
387 /* TODO: remove this and do it in the various intersection functions instead. */
388 if (!hit) {
389 isect.prim = PRIM_NONE;
390 }
391
392 /* Setup mnee flag to signal last intersection with a caster */
393 const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
394
395#ifdef __MNEE__
396 /* Path culling logic for MNEE (removes fireflies at the cost of bias) */
397 if (kernel_data.integrator.use_caustics) {
398 /* The following firefly removal mechanism works by culling light connections when
399 * a ray comes from a caustic caster directly after bouncing off a different caustic
400 * receiver */
401 bool from_caustic_caster = false;
402 bool from_caustic_receiver = false;
403 if (!(path_flag & PATH_RAY_CAMERA) && last_isect_object != OBJECT_NONE) {
404 const int object_flags = kernel_data_fetch(object_flag, last_isect_object);
405 from_caustic_receiver = (object_flags & SD_OBJECT_CAUSTICS_RECEIVER);
406 from_caustic_caster = (object_flags & SD_OBJECT_CAUSTICS_CASTER);
407 }
408
409 bool has_receiver_ancestor = INTEGRATOR_STATE(state, path, mnee) & PATH_MNEE_RECEIVER_ANCESTOR;
410 INTEGRATOR_STATE_WRITE(state, path, mnee) &= ~PATH_MNEE_CULL_LIGHT_CONNECTION;
411 if (from_caustic_caster && has_receiver_ancestor) {
413 }
414 if (from_caustic_receiver) {
416 }
417 }
418#endif /* __MNEE__ */
419
420 /* Light intersection for MIS. */
421 if (kernel_data.integrator.use_light_mis && !integrator_intersect_skip_lights(kg, state)) {
422 /* NOTE: if we make lights visible to camera rays, we'll need to initialize
423 * these in the path_state_init. */
424 const int last_type = INTEGRATOR_STATE(state, isect, type);
425 hit = lights_intersect(
426 kg, state, &ray, &isect, last_isect_prim, last_isect_object, last_type, path_flag) ||
427 hit;
428 }
429
430 /* Write intersection result into global integrator state memory. */
432
433 /* Setup up next kernel to be executed. */
435 kg, state, &isect, render_buffer, hit);
436}
437
unsigned int uint
ccl_device_forceinline int intersection_get_object_flags(KernelGlobals kg, ccl_private const Intersection *ccl_restrict isect)
ccl_device_forceinline int intersection_get_shader(KernelGlobals kg, ccl_private const Intersection *ccl_restrict isect)
#define kernel_assert(cond)
#define kernel_data
const KernelGlobalsCPU *ccl_restrict KernelGlobals
#define kernel_data_fetch(name, index)
#define ccl_restrict
#define ccl_device_forceinline
#define ccl_optional_struct_init
#define ccl_device
#define ccl_private
#define ccl_global
#define CCL_NAMESPACE_END
ccl_device_forceinline void integrator_intersect_next_kernel_after_volume(KernelGlobals kg, IntegratorState state, ccl_private const Intersection *ccl_restrict isect, ccl_global float *ccl_restrict render_buffer)
CCL_NAMESPACE_BEGIN ccl_device_forceinline bool integrator_intersect_skip_lights(KernelGlobals kg, IntegratorState state)
ccl_device_forceinline void integrator_intersect_next_kernel(KernelGlobals kg, IntegratorState state, ccl_private const Intersection *ccl_restrict isect, ccl_global float *ccl_restrict render_buffer, const bool hit)
ccl_device void integrator_intersect_closest(KernelGlobals kg, IntegratorState state, ccl_global float *ccl_restrict render_buffer)
ccl_device_forceinline bool integrator_intersect_terminate(KernelGlobals kg, IntegratorState state, const int shader_flags)
ccl_device_intersect bool scene_intersect(KernelGlobals kg, ccl_private const Ray *ray, const uint visibility, ccl_private Intersection *isect)
ccl_gpu_kernel_postfix ccl_global KernelWorkTile const int ccl_global float * render_buffer
ccl_device_forceinline void guiding_record_continuation_probability(KernelGlobals kg, IntegratorState state, const float continuation_probability)
ccl_device bool lights_intersect(KernelGlobals kg, IntegratorState state, ccl_private const Ray *ccl_restrict ray, ccl_private Intersection *ccl_restrict isect, const int last_prim, const int last_object, const int last_type, const uint32_t path_flag)
@ PATH_MNEE_RECEIVER_ANCESTOR
@ PATH_MNEE_CULL_LIGHT_CONNECTION
@ FILTER_CLOSURE_DIRECT_LIGHT
@ SD_HAS_TRANSPARENT_SHADOW
@ SD_HAS_EMISSION
@ SD_HAS_RAYTRACE
#define PASS_UNUSED
@ PRIMITIVE_LAMP
#define SHADER_NONE
@ PRNG_TERMINATE
#define PRIM_NONE
@ PATH_RAY_SHADOW_CATCHER_HIT
@ PATH_RAY_TERMINATE_AFTER_TRANSPARENT
@ PATH_RAY_TERMINATE_AFTER_VOLUME
@ PATH_RAY_SHADOW_CATCHER_PASS
@ PATH_RAY_TERMINATE_IN_NEXT_VOLUME
@ PATH_RAY_SHADOW_CATCHER_BACKGROUND
@ PATH_RAY_CAMERA
@ PATH_RAY_TERMINATE_ON_NEXT_SURFACE
#define OBJECT_NONE
@ SD_OBJECT_CAUSTICS
@ SD_OBJECT_CAUSTICS_RECEIVER
@ SD_OBJECT_CAUSTICS_CASTER
#define LAMP_NONE
@ DEVICE_KERNEL_INTEGRATOR_SHADE_LIGHT
@ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE
@ DEVICE_KERNEL_INTEGRATOR_INTERSECT_VOLUME_STACK
@ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_RAYTRACE
@ DEVICE_KERNEL_INTEGRATOR_SHADE_SURFACE_MNEE
@ DEVICE_KERNEL_INTEGRATOR_SHADE_VOLUME
@ DEVICE_KERNEL_INTEGRATOR_SHADE_BACKGROUND
#define PROFILING_INIT(kg, event)
static ulong state[N]
ccl_device_inline float path_state_continuation_probability(KernelGlobals kg, ConstIntegratorState state, const uint32_t path_flag)
Definition path_state.h:259
ccl_device_inline bool path_state_ao_bounce(KernelGlobals kg, ConstIntegratorState state)
Definition path_state.h:287
ccl_device_inline float path_state_rng_1D(KernelGlobals kg, ccl_private const RNGState *rng_state, const int dimension)
Definition path_state.h:339
ccl_device_inline void path_state_rng_load(ConstIntegratorState state, ccl_private RNGState *rng_state)
Definition path_state.h:315
ccl_device_inline uint path_state_ray_visibility(ConstIntegratorState state)
Definition path_state.h:238
CCL_NAMESPACE_BEGIN ccl_device_inline bool kernel_shadow_catcher_is_path_split_bounce(KernelGlobals kg, IntegratorState state, const int object_flag)
IntegratorStateCPU *ccl_restrict IntegratorState
Definition state.h:228
#define INTEGRATOR_STATE_WRITE(state, nested_struct, member)
Definition state.h:236
#define INTEGRATOR_STATE(state, nested_struct, member)
Definition state.h:235
ccl_device_forceinline void integrator_path_next_sorted(KernelGlobals kg, IntegratorState state, const DeviceKernel current_kernel, const DeviceKernel next_kernel, const uint32_t key)
Definition state_flow.h:186
ccl_device_forceinline void integrator_path_terminate(KernelGlobals kg, IntegratorState state, const DeviceKernel current_kernel)
Definition state_flow.h:178
ccl_device_forceinline void integrator_path_next(KernelGlobals kg, IntegratorState state, const DeviceKernel current_kernel, const DeviceKernel next_kernel)
Definition state_flow.h:169
ccl_device_forceinline void integrator_path_init_sorted(KernelGlobals kg, IntegratorState state, const DeviceKernel next_kernel, const uint32_t key)
Definition state_flow.h:160
ccl_device_forceinline void integrator_path_init(KernelGlobals kg, IntegratorState state, const DeviceKernel next_kernel)
Definition state_flow.h:153
ccl_device_forceinline void integrator_state_read_ray(ConstIntegratorState state, ccl_private Ray *ccl_restrict ray)
Definition state_util.h:53
ccl_device_inline IntegratorState integrator_state_shadow_catcher_split(KernelGlobals kg, IntegratorState state)
Definition state_util.h:430
ccl_device_forceinline void integrator_state_read_isect(ConstIntegratorState state, ccl_private Intersection *ccl_restrict isect)
Definition state_util.h:158
ccl_device_forceinline void integrator_state_write_isect(IntegratorState state, ccl_private const Intersection *ccl_restrict isect)
Definition state_util.h:128
unsigned int uint32_t
Definition stdint.h:80
@ PROFILING_INTERSECT_CLOSEST
uint8_t flag
Definition wm_window.cc:138