Blender V5.0
intersect_shadow.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
7#include "kernel/globals.h"
8#include "kernel/types.h"
9
10#include "kernel/bvh/bvh.h"
11
15
17
18/* Visibility for the shadow ray. */
20{
21 uint visibility = PATH_RAY_SHADOW;
22
23#ifdef __SHADOW_CATCHER__
24 const uint32_t path_flag = INTEGRATOR_STATE(state, shadow_path, flag);
25 visibility = SHADOW_CATCHER_PATH_VISIBILITY(path_flag, visibility);
26#endif
27
28 return visibility;
29}
30
33 const ccl_private Ray *ray,
34 const uint visibility)
35{
36 /* Mask which will pick only opaque visibility bits from the `visibility`.
37 * Calculate the mask at compile time: the visibility will either be a high bits for the shadow
38 * catcher objects, or lower bits for the regular objects (there is no need to check the path
39 * state here again). */
40 constexpr const uint opaque_mask = SHADOW_CATCHER_VISIBILITY_SHIFT(PATH_RAY_SHADOW_OPAQUE) |
42
43 const bool opaque_hit = scene_intersect_shadow(kg, ray, visibility & opaque_mask);
44
45 /* Only record the number of hits if nothing was hit, so that the shadow shading kernel does not
46 * consider any intersections. There is no need to write anything to the state if the hit is
47 * opaque because in this case the path is terminated. */
48 if (!opaque_hit) {
49 INTEGRATOR_STATE_WRITE(state, shadow_path, num_hits) = 0;
50 }
51
52 return opaque_hit;
53}
54
57{
58 const int transparent_max_bounce = kernel_data.integrator.transparent_max_bounce;
59 const int transparent_bounce = INTEGRATOR_STATE(state, shadow_path, transparent_bounce);
60
61 return max(transparent_max_bounce - transparent_bounce, 0);
62}
63
64#ifdef __TRANSPARENT_SHADOWS__
65# ifndef __KERNEL_GPU__
66ccl_device int shadow_intersections_compare(const void *a, const void *b)
67{
68 const Intersection *isect_a = (const Intersection *)a;
69 const Intersection *isect_b = (const Intersection *)b;
70
71 if (isect_a->t < isect_b->t) {
72 return -1;
73 }
74 if (isect_a->t > isect_b->t) {
75 return 1;
76 }
77 return 0;
78}
79# endif
80
81ccl_device_inline void sort_shadow_intersections(IntegratorShadowState state, uint num_hits)
82{
83 kernel_assert(num_hits > 0);
84
85# ifdef __KERNEL_GPU__
86 /* Use bubble sort which has more friendly memory pattern on GPU. */
87 bool swapped;
88 do {
89 swapped = false;
90 for (int j = 0; j < num_hits - 1; ++j) {
91 if (INTEGRATOR_STATE_ARRAY(state, shadow_isect, j, t) >
92 INTEGRATOR_STATE_ARRAY(state, shadow_isect, j + 1, t))
93 {
100 swapped = true;
101 }
102 }
103 --num_hits;
104 } while (swapped);
105# else
106 Intersection *isect_array = (Intersection *)state->shadow_isect;
107 qsort(isect_array, num_hits, sizeof(Intersection), shadow_intersections_compare);
108# endif
109}
110
111ccl_device bool integrate_intersect_shadow_transparent(KernelGlobals kg,
113 const ccl_private Ray *ray,
114 const uint visibility)
115{
116 /* Limit the number hits to the max transparent bounces allowed and the size that we
117 * have available in the integrator state. */
118 const uint max_transparent_hits = integrate_shadow_max_transparent_hits(kg, state);
119 uint num_hits = 0;
120 float throughput = 1.0f;
121 bool opaque_hit = scene_intersect_shadow_all(
122 kg, state, ray, visibility, max_transparent_hits, &num_hits, &throughput);
123
124 /* Computed throughput from baked shadow transparency, where we can bypass recording
125 * intersections and shader evaluation. */
126 if (throughput != 1.0f) {
127 INTEGRATOR_STATE_WRITE(state, shadow_path, throughput) *= throughput;
128 }
129
130 if (!opaque_hit) {
131 const uint num_recorded_hits = min(num_hits, (uint)INTEGRATOR_SHADOW_ISECT_SIZE);
132
133 if (num_recorded_hits > 0) {
134 sort_shadow_intersections(state, num_recorded_hits);
135 }
136
137 INTEGRATOR_STATE_WRITE(state, shadow_path, num_hits) = num_hits;
138 }
139 else {
140 INTEGRATOR_STATE_WRITE(state, shadow_path, num_hits) = 0;
141 }
142
143 return opaque_hit;
144}
145#endif
146
148{
150
151 /* Read ray from integrator state into local memory. */
155 /* Compute visibility. */
157
158#ifdef __TRANSPARENT_SHADOWS__
159 /* TODO: compile different kernels depending on this? Especially for OptiX
160 * conditional trace calls are bad. */
161 const bool opaque_hit = (kernel_data.integrator.transparent_shadows) ?
162 integrate_intersect_shadow_transparent(kg, state, &ray, visibility) :
163 integrate_intersect_shadow_opaque(kg, state, &ray, visibility);
164#else
165 const bool opaque_hit = integrate_intersect_shadow_opaque(kg, state, &ray, visibility);
166#endif
167
168 if (opaque_hit) {
169 /* Hit an opaque surface, shadow path ends here. */
171 return;
172 }
173
174 /* Hit nothing or transparent surfaces, continue to shadow kernel
175 * for shading and render buffer output.
176 *
177 * TODO: could also write to render buffer directly if no transparent shadows?
178 * Could save a kernel execution for the common case. */
181}
182
unsigned int uint
#define kernel_assert(cond)
#define kernel_data
#define ccl_device_forceinline
#define ccl_optional_struct_init
#define SHADOW_CATCHER_VISIBILITY_SHIFT(visibility)
#define INTEGRATOR_SHADOW_ISECT_SIZE
#define ccl_private
const ThreadKernelGlobalsCPU * KernelGlobals
#define ccl_device_inline
#define SHADOW_CATCHER_PATH_VISIBILITY(path_flag, visibility)
#define CCL_NAMESPACE_END
ccl_device_forceinline int integrate_shadow_max_transparent_hits(KernelGlobals kg, ConstIntegratorShadowState state)
CCL_NAMESPACE_BEGIN ccl_device_forceinline uint integrate_intersect_shadow_visibility(ConstIntegratorShadowState state)
ccl_device void integrator_intersect_shadow(KernelGlobals kg, IntegratorShadowState state)
ccl_device bool integrate_intersect_shadow_opaque(KernelGlobals kg, IntegratorShadowState state, const ccl_private Ray *ray, const uint visibility)
ccl_device_intersect bool scene_intersect_shadow(KernelGlobals kg, const ccl_private Ray *ray, const uint visibility)
@ PATH_RAY_SHADOW
@ PATH_RAY_SHADOW_OPAQUE
@ DEVICE_KERNEL_INTEGRATOR_SHADE_SHADOW
@ DEVICE_KERNEL_INTEGRATOR_INTERSECT_SHADOW
static ulong state[N]
#define PROFILING_INIT(kg, event)
@ PROFILING_INTERSECT_SHADOW
Definition profiling.h:21
#define ccl_device
#define min(a, b)
Definition sort.cc:36
IntegratorShadowStateCPU * IntegratorShadowState
Definition state.h:230
#define INTEGRATOR_STATE_WRITE(state, nested_struct, member)
Definition state.h:236
#define INTEGRATOR_STATE(state, nested_struct, member)
Definition state.h:235
const IntegratorShadowStateCPU * ConstIntegratorShadowState
Definition state.h:231
#define INTEGRATOR_STATE_ARRAY(state, nested_struct, array_index, member)
Definition state.h:238
ccl_device_forceinline void integrator_shadow_path_terminate(IntegratorShadowState state, const DeviceKernel current_kernel)
Definition state_flow.h:246
ccl_device_forceinline void integrator_shadow_path_next(IntegratorShadowState state, const DeviceKernel current_kernel, const DeviceKernel next_kernel)
Definition state_flow.h:238
ccl_device_forceinline void integrator_state_read_shadow_ray(ConstIntegratorShadowState state, ccl_private Ray *ccl_restrict ray)
Definition state_util.h:86
ccl_device_forceinline void integrator_state_write_shadow_isect(IntegratorShadowState state, const ccl_private Intersection *ccl_restrict isect, const int index)
Definition state_util.h:284
ccl_device_forceinline void integrator_state_read_shadow_isect(ConstIntegratorShadowState state, ccl_private Intersection *ccl_restrict isect, const int index)
Definition state_util.h:297
ccl_device_forceinline void integrator_state_read_shadow_ray_self(ConstIntegratorShadowState state, ccl_private Ray *ccl_restrict ray)
Definition state_util.h:136
max
Definition text_draw.cc:251
uint8_t flag
Definition wm_window.cc:145