Blender V4.3
kernel/light/light.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/light/area.h"
10#include "kernel/light/point.h"
11#include "kernel/light/spot.h"
13#include "kernel/sample/lcg.h"
14
16
18
19/* Light info. */
20
22{
23 return (bounce > kernel_data_fetch(lights, index).max_bounces);
24}
25
26/* Light linking. */
27
29{
30#ifdef __LIGHT_LINKING__
31 if (!(kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_LINKING)) {
32 return OBJECT_NONE;
33 }
34
35 return sd->object;
36#else
37 return OBJECT_NONE;
38#endif
39}
40
42{
43#ifdef __LIGHT_LINKING__
44 if (!(kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_LINKING)) {
45 return OBJECT_NONE;
46 }
47
48 return INTEGRATOR_STATE(state, path, mis_ray_object);
49#else
50 return OBJECT_NONE;
51#endif
52}
53
55 const int object_receiver,
56 const int light_emitter)
57{
58#ifdef __LIGHT_LINKING__
59 if (!(kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_LINKING)) {
60 return true;
61 }
62
63 const uint64_t set_membership = kernel_data_fetch(lights, light_emitter).light_set_membership;
64 const uint receiver_set = (object_receiver != OBJECT_NONE) ?
65 kernel_data_fetch(objects, object_receiver).receiver_light_set :
66 0;
67 return ((uint64_t(1) << uint64_t(receiver_set)) & set_membership) != 0;
68#else
69 return true;
70#endif
71}
72
74 const int object_receiver,
75 const int object_emitter)
76{
77#ifdef __LIGHT_LINKING__
78 if (!(kernel_data.kernel_features & KERNEL_FEATURE_LIGHT_LINKING)) {
79 return true;
80 }
81
82 /* Emitter is OBJECT_NONE when the emitter is a world volume.
83 * It is not explicitly linkable to any object, so assume it is coming from the default light
84 * set which affects all objects in the scene. */
85 if (object_emitter == OBJECT_NONE) {
86 return true;
87 }
88
89 const uint64_t set_membership = kernel_data_fetch(objects, object_emitter).light_set_membership;
90 const uint receiver_set = (object_receiver != OBJECT_NONE) ?
91 kernel_data_fetch(objects, object_receiver).receiver_light_set :
92 0;
93 return ((uint64_t(1) << uint64_t(receiver_set)) & set_membership) != 0;
94#else
95 return true;
96#endif
97}
98
99/* Sample point on an individual light. */
100
101template<bool in_volume_segment>
103 const int lamp,
104 const float2 rand,
105 const float3 P,
106 const float3 N,
107 const int shader_flags,
108 const uint32_t path_flag,
110{
111 const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp);
112 if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) {
113 if (klight->shader_id & SHADER_EXCLUDE_SHADOW_CATCHER) {
114 return false;
115 }
116 }
117
118 LightType type = (LightType)klight->type;
119 ls->type = type;
120 ls->shader = klight->shader_id;
121 ls->object = PRIM_NONE;
122 ls->prim = PRIM_NONE;
123 ls->lamp = lamp;
124 ls->u = rand.x;
125 ls->v = rand.y;
126 ls->group = lamp_lightgroup(kg, lamp);
127
128 if (in_volume_segment && (type == LIGHT_DISTANT || type == LIGHT_BACKGROUND)) {
129 /* Distant lights in a volume get a dummy sample, position will not actually
130 * be used in that case. Only when sampling from a specific scatter position
131 * do we actually need to evaluate these. */
132 ls->P = zero_float3();
133 ls->Ng = zero_float3();
134 ls->D = zero_float3();
135 ls->pdf = 1.0f;
136 ls->eval_fac = 0.0f;
137 ls->t = FLT_MAX;
138 return true;
139 }
140
141 if (type == LIGHT_DISTANT) {
142 if (!distant_light_sample(klight, rand, ls)) {
143 return false;
144 }
145 }
146 else if (type == LIGHT_BACKGROUND) {
147 /* infinite area light (e.g. light dome or env light) */
148 float3 D = -background_light_sample(kg, P, rand, &ls->pdf);
149
150 ls->P = D;
151 ls->Ng = D;
152 ls->D = -D;
153 ls->t = FLT_MAX;
154 ls->eval_fac = 1.0f;
155 }
156 else if (type == LIGHT_SPOT) {
157 if (!spot_light_sample<in_volume_segment>(klight, rand, P, N, shader_flags, ls)) {
158 return false;
159 }
160 }
161 else if (type == LIGHT_POINT) {
162 if (!point_light_sample(klight, rand, P, N, shader_flags, ls)) {
163 return false;
164 }
165 }
166 else {
167 /* area light */
168 if (!area_light_sample<in_volume_segment>(klight, rand, P, ls)) {
169 return false;
170 }
171 }
172
173 return in_volume_segment || (ls->pdf > 0.0f);
174}
175
176/* Sample a point on the chosen emitter. */
177
178template<bool in_volume_segment>
180 const float3 rand_light,
181 const float time,
182 const float3 P,
183 const float3 N,
184 const int object_receiver,
185 const int shader_flags,
186 const int bounce,
187 const uint32_t path_flag,
189{
190 /* The first two dimensions of the Sobol sequence have better stratification, use them to sample
191 * position on the light. */
192 const float2 rand = float3_to_float2(rand_light);
193
194 int prim;
195 MeshLight mesh_light;
196#ifdef __LIGHT_TREE__
197 if (kernel_data.integrator.use_light_tree) {
198 ccl_global const KernelLightTreeEmitter *kemitter = &kernel_data_fetch(light_tree_emitters,
199 ls->emitter_id);
200 prim = kemitter->light.id;
201 mesh_light.shader_flag = kemitter->mesh_light.shader_flag;
202 mesh_light.object_id = ls->object;
203 }
204 else
205#endif
206 {
208 light_distribution, ls->emitter_id);
209 prim = kdistribution->prim;
210 mesh_light = kdistribution->mesh_light;
211 }
212
213 if (prim >= 0) {
214 /* Mesh light. */
215 const int object = mesh_light.object_id;
216
217 if (!light_link_object_match(kg, object_receiver, object)) {
218 return false;
219 }
220
221 /* Exclude synthetic meshes from shadow catcher pass. */
222 if ((path_flag & PATH_RAY_SHADOW_CATCHER_PASS) &&
223 !(kernel_data_fetch(object_flag, object) & SD_OBJECT_SHADOW_CATCHER))
224 {
225 return false;
226 }
227
228 const int shader_flag = mesh_light.shader_flag;
229 if (!triangle_light_sample<in_volume_segment>(kg, prim, object, rand, time, ls, P)) {
230 return false;
231 }
232 ls->shader |= shader_flag;
233 }
234 else {
235 const int light = ~prim;
236
237 if (!light_link_light_match(kg, object_receiver, light)) {
238 return false;
239 }
240
241 if (UNLIKELY(light_select_reached_max_bounces(kg, light, bounce))) {
242 return false;
243 }
244
245 if (!light_sample<in_volume_segment>(kg, light, rand, P, N, shader_flags, path_flag, ls)) {
246 return false;
247 }
248 }
249
250 ls->pdf *= ls->pdf_selection;
251 return in_volume_segment || (ls->pdf > 0.0f);
252}
253
254/* Intersect ray with individual light. */
255
256/* Returns the total number of hits (the input num_hits plus the number of the new intersections).
257 */
258template<bool is_main_path>
260 ccl_private const Ray *ccl_restrict ray,
262 const int last_prim,
263 const int last_object,
264 const int last_type,
265 const uint32_t path_flag,
266 const uint8_t path_mnee,
267 const int receiver_forward,
268 ccl_private uint *lcg_state,
269 int num_hits)
270{
271#ifdef __SHADOW_LINKING__
272 const bool is_indirect_ray = !(path_flag & PATH_RAY_CAMERA);
273#endif
274
275 for (int lamp = 0; lamp < kernel_data.integrator.num_lights; lamp++) {
276 const ccl_global KernelLight *klight = &kernel_data_fetch(lights, lamp);
277
278 if (path_flag & PATH_RAY_CAMERA) {
279 if (klight->shader_id & SHADER_EXCLUDE_CAMERA) {
280 continue;
281 }
282 }
283 else {
284 if (!(klight->shader_id & SHADER_USE_MIS)) {
285 continue;
286 }
287
288#ifdef __MNEE__
289 /* This path should have been resolved with mnee, it will
290 * generate a firefly for small lights since it is improbable. */
291 if ((path_mnee & PATH_MNEE_CULL_LIGHT_CONNECTION) && klight->use_caustics) {
292 continue;
293 }
294#endif
295 }
296
297 if (path_flag & PATH_RAY_SHADOW_CATCHER_PASS) {
298 if (klight->shader_id & SHADER_EXCLUDE_SHADOW_CATCHER) {
299 continue;
300 }
301 }
302
303#ifdef __SHADOW_LINKING__
304 /* For the main path exclude shadow-linked lights if intersecting with an indirect light ray.
305 * Those lights are handled via dedicated light intersect and shade kernels.
306 * For the shadow path used for the dedicated light shading ignore all non-shadow-linked
307 * lights. */
308 if (kernel_data.kernel_features & KERNEL_FEATURE_SHADOW_LINKING) {
309 if (is_main_path) {
310 if (is_indirect_ray &&
311 kernel_data_fetch(lights, lamp).shadow_set_membership != LIGHT_LINK_MASK_ALL)
312 {
313 continue;
314 }
315 }
316 else if (kernel_data_fetch(lights, lamp).shadow_set_membership == LIGHT_LINK_MASK_ALL) {
317 continue;
318 }
319 }
320#endif
321
322#ifdef __LIGHT_LINKING__
323 /* Light linking. */
324 if (!light_link_light_match(kg, receiver_forward, lamp) && !(path_flag & PATH_RAY_CAMERA)) {
325 continue;
326 }
327#endif
328
329 LightType type = (LightType)klight->type;
330 float t = 0.0f, u = 0.0f, v = 0.0f;
331
332 if (type == LIGHT_SPOT) {
333 if (!spot_light_intersect(klight, ray, &t)) {
334 continue;
335 }
336 }
337 else if (type == LIGHT_POINT) {
338 if (!point_light_intersect(klight, ray, &t)) {
339 continue;
340 }
341 }
342 else if (type == LIGHT_AREA) {
343 if (!area_light_intersect(klight, ray, &t, &u, &v)) {
344 continue;
345 }
346 }
347 else if (type == LIGHT_DISTANT) {
348 if (is_main_path || ray->tmax != FLT_MAX) {
349 continue;
350 }
351 if (!distant_light_intersect(klight, ray, &t, &u, &v)) {
352 continue;
353 }
354 }
355 else {
356 continue;
357 }
358
359 /* Avoid self-intersections. */
360 if (last_prim == lamp && last_object == OBJECT_NONE && last_type == PRIMITIVE_LAMP) {
361 continue;
362 }
363
364 ++num_hits;
365
366#ifdef __SHADOW_LINKING__
367 if (!is_main_path) {
368 /* The non-main rays are only raced by the dedicated light kernel, after the shadow linking
369 * feature check. */
371
372 if ((isect->prim != PRIM_NONE) && (lcg_step_float(lcg_state) > 1.0f / num_hits)) {
373 continue;
374 }
375 }
376 else
377#endif
378 if (t >= isect->t)
379 {
380 continue;
381 }
382
383 isect->t = t;
384 isect->u = u;
385 isect->v = v;
386 isect->type = PRIMITIVE_LAMP;
387 isect->prim = lamp;
388 isect->object = OBJECT_NONE;
389 }
390
391 return num_hits;
392}
393
394/* Lights intersection for the main path.
395 * Intersects spot, point, and area lights. */
398 ccl_private const Ray *ccl_restrict ray,
400 const int last_prim,
401 const int last_object,
402 const int last_type,
403 const uint32_t path_flag)
404{
405 const uint8_t path_mnee = INTEGRATOR_STATE(state, path, mnee);
406 const int receiver_forward = light_link_receiver_forward(kg, state);
407
409 ray,
410 isect,
411 last_prim,
412 last_object,
413 last_type,
414 path_flag,
415 path_mnee,
416 receiver_forward,
417 nullptr,
418 0);
419
420 return isect->prim != PRIM_NONE;
421}
422
423/* Lights intersection for the shadow linking.
424 * Intersects spot, point, area, and distant lights.
425 *
426 * Returns the total number of hits (the input num_hits plus the number of the new intersections).
427 */
429 ccl_private const Ray *ccl_restrict ray,
431 const int last_prim,
432 const int last_object,
433 const int last_type,
434 const uint32_t path_flag,
435 const int receiver_forward,
436 ccl_private uint *lcg_state,
437 const int num_hits)
438{
440 ray,
441 isect,
442 last_prim,
443 last_object,
444 last_type,
445 path_flag,
447 receiver_forward,
448 lcg_state,
449 num_hits);
450}
451
452/* Setup light sample from intersection. */
453
456 const float3 ray_P,
457 const float3 ray_D,
458 const float3 N,
459 const uint32_t path_flag,
461{
462 const int lamp = isect->prim;
463 ccl_global const KernelLight *klight = &kernel_data_fetch(lights, lamp);
464 LightType type = (LightType)klight->type;
465 ls->type = type;
466 ls->shader = klight->shader_id;
467 ls->object = isect->object;
468 ls->prim = isect->prim;
469 ls->lamp = lamp;
470 ls->t = isect->t;
471 ls->P = ray_P + ray_D * ls->t;
472 ls->D = ray_D;
473 ls->group = lamp_lightgroup(kg, lamp);
474
475 if (type == LIGHT_SPOT) {
476 if (!spot_light_sample_from_intersection(klight, ray_P, ray_D, N, path_flag, ls)) {
477 return false;
478 }
479 }
480 else if (type == LIGHT_POINT) {
481 if (!point_light_sample_from_intersection(klight, ray_P, ray_D, N, path_flag, ls)) {
482 return false;
483 }
484 }
485 else if (type == LIGHT_AREA) {
486 if (!area_light_sample_from_intersection(klight, isect, ray_P, ray_D, ls)) {
487 return false;
488 }
489 }
490 else {
491 kernel_assert(!"Invalid lamp type in light_sample_from_intersection");
492 return false;
493 }
494
495 return true;
496}
497
#define D
unsigned int uint
#define UNLIKELY(x)
ccl_device_inline bool area_light_sample(const ccl_global KernelLight *klight, const float2 rand, const float3 P, ccl_private LightSample *ls)
Definition area.h:325
ccl_device_inline bool area_light_intersect(const ccl_global KernelLight *klight, const ccl_private Ray *ccl_restrict ray, ccl_private float *t, ccl_private float *u, ccl_private float *v)
Definition area.h:390
ccl_device_inline bool area_light_sample_from_intersection(const ccl_global KernelLight *klight, ccl_private const Intersection *ccl_restrict isect, const float3 ray_P, const float3 ray_D, ccl_private LightSample *ccl_restrict ls)
Definition area.h:430
ATTR_WARN_UNUSED_RESULT const BMVert * v
#define kernel_assert(cond)
#define kernel_data
const KernelGlobalsCPU *ccl_restrict KernelGlobals
#define kernel_data_fetch(name, index)
#define ccl_restrict
#define ccl_device_forceinline
#define ccl_device
#define ccl_private
#define ccl_device_inline
#define ccl_global
#define ccl_device_noinline
#define CCL_NAMESPACE_END
ccl_device_inline bool distant_light_sample(const ccl_global KernelLight *klight, const float2 rand, ccl_private LightSample *ls)
Definition distant.h:34
ccl_device bool distant_light_intersect(const ccl_global KernelLight *klight, const ccl_private Ray *ccl_restrict ray, ccl_private float *t, ccl_private float *u, ccl_private float *v)
Definition distant.h:59
ccl_device_inline int lamp_lightgroup(KernelGlobals kg, int lamp)
ccl_device_inline float3 background_light_sample(KernelGlobals kg, float3 P, float2 rand, ccl_private float *pdf)
ccl_device int lights_intersect_shadow_linked(KernelGlobals kg, ccl_private const 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, const int receiver_forward, ccl_private uint *lcg_state, const int num_hits)
CCL_NAMESPACE_BEGIN ccl_device_inline bool light_select_reached_max_bounces(KernelGlobals kg, int index, int bounce)
ccl_device_inline bool light_link_object_match(KernelGlobals kg, const int object_receiver, const int object_emitter)
ccl_device bool lights_intersect(KernelGlobals kg, IntegratorState state, ccl_private const 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)
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)
ccl_device_inline bool light_link_light_match(KernelGlobals kg, const int object_receiver, const int light_emitter)
ccl_device_forceinline int lights_intersect_impl(KernelGlobals kg, ccl_private const 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, const uint8_t path_mnee, const int receiver_forward, ccl_private uint *lcg_state, int num_hits)
ccl_device_inline bool light_sample(KernelGlobals kg, const int lamp, const float2 rand, const float3 P, const float3 N, const int shader_flags, const uint32_t path_flag, ccl_private LightSample *ls)
ccl_device_inline int light_link_receiver_nee(KernelGlobals kg, const ccl_private ShaderData *sd)
ccl_device_inline int light_link_receiver_forward(KernelGlobals kg, IntegratorState state)
@ PATH_MNEE_NONE
@ PATH_MNEE_CULL_LIGHT_CONNECTION
@ PRIMITIVE_LAMP
#define PRIM_NONE
@ PATH_RAY_SHADOW_CATCHER_PASS
@ PATH_RAY_CAMERA
#define OBJECT_NONE
ShaderData
@ SHADER_EXCLUDE_SHADOW_CATCHER
@ SHADER_EXCLUDE_CAMERA
@ SHADER_USE_MIS
@ SD_OBJECT_SHADOW_CATCHER
struct MeshLight { int shader_flag; int object_id;} MeshLight
#define KERNEL_FEATURE_SHADOW_LINKING
#define LIGHT_LINK_MASK_ALL
#define KERNEL_FEATURE_LIGHT_LINKING
LightType
@ LIGHT_AREA
@ LIGHT_DISTANT
@ LIGHT_SPOT
@ LIGHT_BACKGROUND
@ LIGHT_POINT
ccl_device float lcg_step_float(T rng)
Definition lcg.h:22
ccl_device_inline bool point_light_intersect(const ccl_global KernelLight *klight, const ccl_private Ray *ccl_restrict ray, ccl_private float *t)
CCL_NAMESPACE_BEGIN ccl_device_inline bool point_light_sample(const ccl_global KernelLight *klight, const float2 rand, const float3 P, const float3 N, const int shader_flags, ccl_private LightSample *ls)
Definition light/point.h:11
ccl_device_inline bool point_light_sample_from_intersection(const ccl_global KernelLight *klight, const float3 ray_P, const float3 ray_D, const float3 N, const uint32_t path_flag, ccl_private LightSample *ccl_restrict ls)
ccl_device_forceinline bool triangle_light_sample(KernelGlobals kg, int prim, int object, const float2 rand, float time, ccl_private LightSample *ls, const float3 P)
CCL_NAMESPACE_BEGIN ccl_device_inline float3 zero_float3()
Definition math_float3.h:15
static ulong state[N]
#define N
ccl_device_inline bool spot_light_sample(const ccl_global KernelLight *klight, const float2 rand, const float3 P, const float3 N, const int shader_flags, ccl_private LightSample *ls)
Definition spot.h:41
ccl_device_inline bool spot_light_intersect(const ccl_global KernelLight *klight, const ccl_private Ray *ccl_restrict ray, ccl_private float *t)
Definition spot.h:211
ccl_device_inline bool spot_light_sample_from_intersection(const ccl_global KernelLight *klight, const float3 ray_P, const float3 ray_D, const float3 N, const uint32_t path_flag, ccl_private LightSample *ccl_restrict ls)
Definition spot.h:223
IntegratorStateCPU *ccl_restrict IntegratorState
Definition state.h:228
#define INTEGRATOR_STATE(state, nested_struct, member)
Definition state.h:235
#define FLT_MAX
Definition stdcycles.h:14
unsigned int uint32_t
Definition stdint.h:80
unsigned char uint8_t
Definition stdint.h:78
unsigned __int64 uint64_t
Definition stdint.h:90
float x
float y
ccl_device_inline float2 float3_to_float2(const float3 a)
Definition util/math.h:530