Blender V5.0
shade_dedicated_light.h
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2011-2023 Blender Foundation
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#pragma once
6
10
12
14
15#ifdef __SHADOW_LINKING__
16
17ccl_device_inline bool shadow_linking_light_sample_from_intersection(
20 const ccl_private Ray &ccl_restrict ray,
21 const float3 N,
22 const uint32_t path_flag,
24{
25 const int lamp = isect.prim;
26
27 const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp);
28 const LightType type = LightType(klight->type);
29
30 if (type == LIGHT_DISTANT) {
31 return distant_light_sample_from_intersection(kg, ray.D, lamp, ls);
32 }
33
34 return light_sample_from_intersection(kg, &isect, ray.P, ray.D, N, path_flag, ls);
35}
36
37ccl_device_inline float shadow_linking_light_sample_mis_weight(KernelGlobals kg,
39 const uint32_t path_flag,
40 const ccl_private LightSample *ls,
41 const float3 P)
42{
43 if (ls->type == LIGHT_DISTANT) {
44 return light_sample_mis_weight_forward_distant(kg, state, path_flag, ls);
45 }
46
47 return light_sample_mis_weight_forward_lamp(kg, state, path_flag, ls, P);
48}
49
50/* Setup ray for the shadow path.
51 * Expects that the current state of the ray is the one calculated by the surface bounce, and the
52 * intersection corresponds to a point on an emitter. */
53ccl_device void shadow_linking_setup_ray_from_intersection(
57{
58 /* The ray->tmin follows the value configured at the surface bounce.
59 * it is the same for the continued main path and for this shadow ray. There is no need to push
60 * it forward here. */
61
62 ray->tmax = isect->t;
63
64 /* Use the same self intersection primitives as the main path.
65 * Those are copied to the dedicated storage from the main intersection after the surface bounce,
66 * but before the main intersection is re-used to find light to trace a ray to. */
67 ray->self.object = INTEGRATOR_STATE(state, shadow_link, last_isect_object);
68 ray->self.prim = INTEGRATOR_STATE(state, shadow_link, last_isect_prim);
69
70 ray->self.light_object = isect->object;
71 ray->self.light_prim = isect->prim;
72}
73
74ccl_device bool shadow_linking_shade_light(KernelGlobals kg,
78 ccl_private ShaderData *emission_sd,
79 ccl_private Spectrum &ccl_restrict bsdf_spectrum,
80 ccl_private float &mis_weight,
81 ccl_private int &ccl_restrict light_group)
82{
83 const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
84 const float3 N = INTEGRATOR_STATE(state, path, mis_origin_n);
86 const bool use_light_sample = shadow_linking_light_sample_from_intersection(
87 kg, isect, ray, N, path_flag, &ls);
88 if (!use_light_sample) {
89 /* No light to be sampled, so no direct light contribution either. */
90 return false;
91 }
92
93 const Spectrum light_eval = light_sample_shader_eval(kg, state, emission_sd, &ls, ray.time);
94 if (is_zero(light_eval)) {
95 return false;
96 }
97
98 if (!is_light_shader_visible_to_path(ls.shader, path_flag)) {
99 return false;
100 }
101
102 /* MIS weighting. */
103 mis_weight = shadow_linking_light_sample_mis_weight(kg, state, path_flag, &ls, ray.P);
104
105 bsdf_spectrum = light_eval * mis_weight *
106 INTEGRATOR_STATE(state, shadow_link, dedicated_light_weight);
107 light_group = ls.group;
108
109 return true;
110}
111
112ccl_device bool shadow_linking_shade_surface_emission(KernelGlobals kg,
114 ccl_private ShaderData *emission_sd,
117 bsdf_spectrum,
118 ccl_private float &mis_weight,
119 ccl_private int &ccl_restrict light_group)
120{
121 const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
122
123 integrate_surface_shader_setup(kg, state, emission_sd);
124
125# ifdef __VOLUME__
126 if (emission_sd->flag & SD_HAS_ONLY_VOLUME) {
127 return false;
128 }
129# endif
130
132 kg, state, emission_sd, render_buffer, path_flag | PATH_RAY_EMISSION);
133
134 if ((emission_sd->flag & SD_EMISSION) == 0) {
135 return false;
136 }
137
138 const Spectrum L = surface_shader_emission(emission_sd);
139
140 mis_weight = light_sample_mis_weight_forward_surface(kg, state, path_flag, emission_sd);
141
142 bsdf_spectrum = L * mis_weight * INTEGRATOR_STATE(state, shadow_link, dedicated_light_weight);
143 light_group = object_lightgroup(kg, emission_sd->object);
144
145 return true;
146}
147
148ccl_device void shadow_linking_shade(KernelGlobals kg,
151{
152 /* Read intersection from integrator state into local memory. */
155
156 /* Read ray from integrator state into local memory. */
159
160 ShaderDataTinyStorage emission_sd_storage;
161 ccl_private ShaderData *emission_sd = AS_SHADER_DATA(&emission_sd_storage);
162
163 Spectrum bsdf_spectrum;
164 float mis_weight = 1.0f;
165 int light_group = LIGHTGROUP_NONE;
166
167 if (isect.type == PRIMITIVE_LAMP) {
168 if (!shadow_linking_shade_light(
169 kg, state, ray, isect, emission_sd, bsdf_spectrum, mis_weight, light_group))
170 {
171 return;
172 }
173 }
174 else {
175 if (!shadow_linking_shade_surface_emission(
176 kg, state, emission_sd, render_buffer, bsdf_spectrum, mis_weight, light_group))
177 {
178 return;
179 }
180 }
181
182 if (is_zero(bsdf_spectrum)) {
183 return;
184 }
185
186 shadow_linking_setup_ray_from_intersection(state, &ray, &isect);
187
188 /* Branch off shadow kernel. */
190 kg, state, &ray, bsdf_spectrum, light_group, 0);
191
192 /* The light is accumulated from the shade_surface kernel, which will make the clamping decision
193 * based on the actual value of the bounce. For the dedicated shadow ray we want to follow the
194 * main path clamping rules, which subtracts one from the bounds before accumulation. */
196 shadow_state, shadow_path, bounce) = INTEGRATOR_STATE(shadow_state, shadow_path, bounce) - 1;
197
198 /* No need to update the volume stack as the surface bounce already performed enter-exit check.
199 */
200
201 const uint32_t shadow_flag = INTEGRATOR_STATE(state, path, flag);
202
203 if (kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_PASSES) {
204 /* The diffuse and glossy pass weights are written into the main path as part of the path
205 * configuration at a surface bounce. */
206 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, pass_diffuse_weight) = INTEGRATOR_STATE(
207 state, path, pass_diffuse_weight);
208 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, pass_glossy_weight) = INTEGRATOR_STATE(
209 state, path, pass_glossy_weight);
210 }
211
212 INTEGRATOR_STATE_WRITE(shadow_state, shadow_path, flag) = shadow_flag;
213
214# if defined(__PATH_GUIDING__)
215 if (kernel_data.integrator.train_guiding) {
217 INTEGRATOR_STATE(shadow_state, shadow_path, guiding_mis_weight) = mis_weight;
218 }
219# endif
220}
221
222#endif /* __SHADOW_LINKING__ */
223
227{
229
230#ifdef __SHADOW_LINKING__
231 shadow_linking_shade(kg, state, render_buffer);
232
233 /* Restore self-intersection check primitives in the main state before returning to the
234 * intersect_closest() state. */
235 shadow_linking_restore_last_primitives(state);
236#else
237 kernel_assert(!"integrator_intersect_dedicated_light is not supposed to be scheduled");
238#endif
239
241}
242
CCL_NAMESPACE_BEGIN ccl_device_noinline_cpu Spectrum light_sample_shader_eval(KernelGlobals kg, IntegratorState state, ccl_private ShaderData *ccl_restrict emission_sd, ccl_private LightSample *ccl_restrict ls, const float time)
ccl_device_inline float light_sample_mis_weight_forward_distant(KernelGlobals kg, IntegratorState state, const uint32_t path_flag, const ccl_private LightSample *ls)
ccl_device_inline float light_sample_mis_weight_forward_lamp(KernelGlobals kg, IntegratorState state, const uint32_t path_flag, const ccl_private LightSample *ls, const float3 P)
ccl_device_inline float light_sample_mis_weight_forward_surface(KernelGlobals kg, IntegratorState state, const uint32_t path_flag, const ccl_private ShaderData *sd)
#define kernel_assert(cond)
#define kernel_data
#define ccl_restrict
#define ccl_optional_struct_init
#define kernel_data_fetch(name, index)
#define AS_SHADER_DATA(shader_data_tiny_storage)
#define ccl_private
const ThreadKernelGlobalsCPU * KernelGlobals
#define ccl_device_inline
#define KERNEL_FEATURE_LIGHT_PASSES
#define LIGHTGROUP_NONE
#define ccl_global
#define CCL_NAMESPACE_END
ccl_device bool distant_light_sample_from_intersection(KernelGlobals kg, const float3 ray_D, const int lamp, ccl_private LightSample *ccl_restrict ls)
Definition distant.h:86
ccl_gpu_kernel_postfix ccl_global KernelWorkTile const int ccl_global float * render_buffer
ccl_device_inline int object_lightgroup(KernelGlobals kg, const int object)
ccl_device_forceinline void guiding_record_light_surface_segment(KernelGlobals kg, IntegratorState state, const ccl_private Intersection *ccl_restrict isect)
ccl_device bool light_sample_from_intersection(KernelGlobals kg, const ccl_private Intersection *ccl_restrict isect, const float3 ray_P, const float3 ray_D, const float3 N, const uint32_t path_flag, ccl_private LightSample *ccl_restrict ls)
@ SD_HAS_ONLY_VOLUME
@ SD_EMISSION
@ PRIMITIVE_LAMP
ShaderData ShaderDataTinyStorage
@ PATH_RAY_EMISSION
LightType
@ LIGHT_DISTANT
ccl_device_inline bool is_light_shader_visible_to_path(const int shader, const uint32_t path_flag)
ccl_device_inline bool is_zero(const float2 a)
static ulong state[N]
#define N
#define L
#define PROFILING_INIT(kg, event)
@ PROFILING_SHADE_DEDICATED_LIGHT
Definition profiling.h:31
#define ccl_device
CCL_NAMESPACE_BEGIN ccl_device void integrator_shade_dedicated_light(KernelGlobals kg, IntegratorState state, ccl_global float *ccl_restrict render_buffer)
ccl_device_inline IntegratorShadowState integrate_direct_light_shadow_init_common(KernelGlobals kg, IntegratorState state, const ccl_private Ray *ccl_restrict ray, const Spectrum bsdf_spectrum, const int light_group, const int mnee_vertex_count)
ccl_device_forceinline void integrator_shade_surface_next_kernel(IntegratorState state)
CCL_NAMESPACE_BEGIN ccl_device_forceinline void integrate_surface_shader_setup(KernelGlobals kg, ConstIntegratorState state, ccl_private ShaderData *sd)
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
IntegratorStateCPU * IntegratorState
Definition state.h:228
ccl_device_forceinline void integrator_state_read_ray(ConstIntegratorState state, ccl_private Ray *ccl_restrict ray)
Definition state_util.h:55
ccl_device_forceinline void integrator_state_read_isect(ConstIntegratorState state, ccl_private Intersection *ccl_restrict isect)
Definition state_util.h:179
ccl_device void surface_shader_eval(KernelGlobals kg, ConstIntegratorGenericState state, ccl_private ShaderData *ccl_restrict sd, ccl_global float *ccl_restrict buffer, const uint32_t path_flag, bool use_caustics_storage=false)
ccl_device Spectrum surface_shader_emission(const ccl_private ShaderData *sd)
float3 Spectrum
uint8_t flag
Definition wm_window.cc:145