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