Blender V5.0
intersect_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
7#include "kernel/bvh/bvh.h"
8
12
13#include "kernel/light/light.h"
14
15#include "kernel/sample/lcg.h"
16
18
19#ifdef __SHADOW_LINKING__
20
21# define SHADOW_LINK_MAX_INTERSECTION_COUNT 1024
22
23/* Intersect mesh objects.
24 *
25 * Returns the total number of emissive surfaces hit, and the intersection contains a random
26 * intersected emitter to which the dedicated shadow ray is to eb traced.
27 *
28 * NOTE: Sets the ray tmax to the maximum intersection distance (past which no lights are to be
29 * considered for shadow linking). */
30ccl_device int shadow_linking_pick_mesh_intersection(KernelGlobals kg,
33 const int object_receiver,
35 linked_isect,
36 ccl_private uint *lcg_state,
37 int num_hits)
38{
39 /* The tmin will be offset, so store its current value and restore later on, allowing a separate
40 * light intersection loop starting from the actual ray origin. */
41 const float old_tmin = ray->tmin;
42
43 const uint visibility = path_state_ray_visibility(state);
44
45 int transparent_bounce = INTEGRATOR_STATE(state, path, transparent_bounce);
46 int volume_bounds_bounce = INTEGRATOR_STATE(state, path, volume_bounds_bounce);
47
48 /* TODO: Replace the look with sequential calls to the kernel, similar to the transparent shadow
49 * intersection kernel. */
50 for (int i = 0; i < SHADOW_LINK_MAX_INTERSECTION_COUNT; i++) {
52 current_isect.object = OBJECT_NONE;
53 current_isect.prim = PRIM_NONE;
54
55 const bool hit = scene_intersect(kg, ray, visibility, &current_isect);
56 if (!hit) {
57 break;
58 }
59
60 /* Only record primitives that potentially have emission.
61 * TODO: optimize with a dedicated ray visibility flag, which could then also be
62 * used once lights are in the BVH as geometry? */
63 const int shader = intersection_get_shader(kg, &current_isect);
64 const int shader_flags = kernel_data_fetch(shaders, shader).flags;
65 if (light_link_object_match(kg, object_receiver, current_isect.object) &&
66 (shader_flags & SD_HAS_EMISSION))
67 {
68 const uint64_t set_membership =
69 kernel_data_fetch(objects, current_isect.object).shadow_set_membership;
70 if (set_membership != LIGHT_LINK_MASK_ALL) {
71 ++num_hits;
72
73 if ((linked_isect->prim == PRIM_NONE) || (lcg_step_float(lcg_state) < 1.0f / num_hits)) {
74 *linked_isect = current_isect;
75 }
76 }
77 }
78
79 /* Contribution from the lights past the default opaque blocker is accumulated
80 * using the main path. */
81 if (!(shader_flags & (SD_HAS_ONLY_VOLUME | SD_HAS_TRANSPARENT_SHADOW))) {
82 const uint blocker_set = kernel_data_fetch(objects, current_isect.object).blocker_shadow_set;
83 if (blocker_set == 0) {
84 ray->tmax = current_isect.t;
85 break;
86 }
87 }
88 else {
89 /* Lights past the maximum allowed transparency bounce do not contribute any light, so
90 * consider them as fully blocked and only consider lights prior to this intersection. */
91 if (shader_flags & SD_HAS_ONLY_VOLUME) {
92 ++volume_bounds_bounce;
93 if (volume_bounds_bounce >= VOLUME_BOUNDS_MAX) {
94 ray->tmax = current_isect.t;
95 break;
96 }
97 }
98 else {
100 ++transparent_bounce;
101 if (transparent_bounce >= kernel_data.integrator.transparent_max_bounce) {
102 ray->tmax = current_isect.t;
103 break;
104 }
105 }
106 }
107
108 /* Move the ray forward. */
109 ray->tmin = intersection_t_offset(current_isect.t);
110 }
111
112 ray->tmin = old_tmin;
113
114 return num_hits;
115}
116
117/* Pick a light for tracing a shadow ray for the shadow linking.
118 * Picks a random light which is intersected by the given ray, and stores the intersection result.
119 * If no lights were hit false is returned.
120 *
121 * NOTE: Sets the ray tmax to the maximum intersection distance (past which no lights are to be
122 * considered for shadow linking). */
123ccl_device bool shadow_linking_pick_light_intersection(KernelGlobals kg,
127 linked_isect)
128{
129 const uint32_t path_flag = INTEGRATOR_STATE(state, path, flag);
130
131 const int last_type = INTEGRATOR_STATE(state, isect, type);
132
133 const int object_receiver = light_link_receiver_forward(kg, state);
134
135 uint lcg_state = lcg_state_init(INTEGRATOR_STATE(state, path, rng_pixel),
136 INTEGRATOR_STATE(state, path, rng_offset),
138 0x68bc21eb);
139
140 /* Indicate that no intersection has been picked yet. */
141 linked_isect->prim = PRIM_NONE;
142
143 int num_hits = 0;
144
145 // TODO: Only if there are emissive meshes in the scene?
146
147 // TODO: Only if the ray hits any light? As in, check that there is a light first, before
148 // tracing potentially expensive ray.
149
150 num_hits = shadow_linking_pick_mesh_intersection(
151 kg, state, ray, object_receiver, linked_isect, &lcg_state, num_hits);
152
153 num_hits = lights_intersect_shadow_linked(kg,
154 ray,
155 linked_isect,
156 ray->self.prim,
157 ray->self.object,
158 last_type,
159 path_flag,
160 object_receiver,
161 &lcg_state,
162 num_hits);
163
164 if (num_hits == 0) {
165 return false;
166 }
167
168 INTEGRATOR_STATE_WRITE(state, shadow_link, dedicated_light_weight) = num_hits;
169
170 return true;
171}
172
173/* Check whether a special shadow ray is needed to calculate direct light contribution which comes
174 * from emitters which are behind objects which are blocking light for the main path, but are
175 * excluded from blocking light via shadow linking.
176 *
177 * If a special ray is needed a blocked light kernel is scheduled and true is returned, otherwise
178 * false is returned. */
179ccl_device bool shadow_linking_intersect(KernelGlobals kg, IntegratorState state)
180{
181 /* Verify that the kernel is only scheduled if it is actually needed. */
182 kernel_assert(shadow_linking_scene_need_shadow_ray(kg));
183
184 /* Read ray from integrator state into local memory. */
187
188 ray.self.prim = INTEGRATOR_STATE(state, isect, prim);
189 ray.self.object = INTEGRATOR_STATE(state, isect, object);
190 ray.self.light_object = OBJECT_NONE;
191 ray.self.light_prim = PRIM_NONE;
192
194 if (!shadow_linking_pick_light_intersection(kg, state, &ray, &isect)) {
195 /* No light is hit, no need in the extra shadow ray for the direct light. */
196 return false;
197 }
198
199 /* Make a copy of primitives needed by the main path self-intersection check before writing the
200 * new intersection. Those primitives will be restored before the main path is returned to the
201 * intersect_closest state. */
202 shadow_linking_store_last_primitives(state);
203
204 /* Write intersection result into global integrator state memory, so that the
205 * shade_dedicated_light kernel can use it for calculation of the light sample. */
207
211
212 return true;
213}
214
215#endif /* __SHADOW_LINKING__ */
216
218{
220
221#ifdef __SHADOW_LINKING__
222 if (shadow_linking_intersect(kg, state)) {
223 return;
224 }
225#else
226 kernel_assert(!"integrator_intersect_dedicated_light is not supposed to be scheduled");
227#endif
228
230}
231
unsigned int uint
unsigned long long int uint64_t
ccl_device_forceinline float intersection_t_offset(const float t)
ccl_device_forceinline int intersection_get_shader(KernelGlobals kg, const ccl_private Intersection *ccl_restrict isect)
#define kernel_assert(cond)
#define kernel_data
#define ccl_restrict
#define VOLUME_BOUNDS_MAX
#define ccl_optional_struct_init
#define kernel_data_fetch(name, index)
#define PRIM_NONE
#define OBJECT_NONE
#define ccl_private
const ThreadKernelGlobalsCPU * KernelGlobals
#define LIGHT_LINK_MASK_ALL
#define CCL_NAMESPACE_END
CCL_NAMESPACE_BEGIN ccl_device void integrator_intersect_dedicated_light(KernelGlobals kg, IntegratorState state)
ccl_device_intersect bool scene_intersect(KernelGlobals kg, const ccl_private Ray *ray, const uint visibility, ccl_private Intersection *isect)
ccl_device_inline bool light_link_object_match(KernelGlobals kg, const int object_receiver, const int object_emitter)
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 int light_link_receiver_forward(KernelGlobals kg, IntegratorState state)
@ SD_HAS_TRANSPARENT_SHADOW
@ SD_HAS_EMISSION
@ SD_HAS_ONLY_VOLUME
@ DEVICE_KERNEL_INTEGRATOR_SHADE_DEDICATED_LIGHT
@ DEVICE_KERNEL_INTEGRATOR_INTERSECT_DEDICATED_LIGHT
ccl_device_inline uint lcg_state_init(const uint rng_hash, const uint rng_offset, const uint sample, const uint scramble)
Definition lcg.h:45
ccl_device float lcg_step_float(T rng)
Definition lcg.h:22
static ulong state[N]
#define PROFILING_INIT(kg, event)
ccl_device_inline uint path_state_ray_visibility(ConstIntegratorState state)
Definition path_state.h:255
@ PROFILING_INTERSECT_DEDICATED_LIGHT
Definition profiling.h:23
#define ccl_device
ccl_device_forceinline void integrator_shade_surface_next_kernel(IntegratorState state)
#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_path_next(IntegratorState state, const DeviceKernel current_kernel, const DeviceKernel next_kernel)
Definition state_flow.h:195
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_write_isect(IntegratorState state, const ccl_private Intersection *ccl_restrict isect)
Definition state_util.h:149
i
Definition text_draw.cc:230
uint8_t flag
Definition wm_window.cc:145