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