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