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