Blender V4.3
spot.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
8
10
11/* Transform vector to spot light's local coordinate system. */
13{
14 const Transform itfm = klight->itfm;
15 float3 transformed_ray = safe_normalize(transform_direction(&itfm, ray));
16 transformed_ray.z = -transformed_ray.z;
17
18 return transformed_ray;
19}
20
21/* Compute spot light attenuation of a ray given in local coordinate system. */
23{
24 return smoothstepf((ray.z - spot->cos_half_spot_angle) * spot->spot_smooth);
25}
26
28 const float half_cot_half_spot_angle,
29 ccl_private float *u,
30 ccl_private float *v)
31{
32 /* Ensures that the spot light projects the full image regardless of the spot angle. */
33 const float factor = half_cot_half_spot_angle / ray.z;
34
35 /* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */
36 *u = ray.y * factor + 0.5f;
37 *v = -(ray.x + ray.y) * factor;
38}
39
40template<bool in_volume_segment>
42 const float2 rand,
43 const float3 P,
44 const float3 N,
45 const int shader_flags,
47{
48 const float r_sq = sqr(klight->spot.radius);
49
50 float3 lightN = P - klight->co;
51 const float d_sq = len_squared(lightN);
52 const float d = sqrtf(d_sq);
53 lightN /= d;
54
55 ls->eval_fac = klight->spot.eval_fac;
56
57 if (klight->spot.is_sphere) {
58 /* Spherical light geometry. */
59 float cos_theta;
60 ls->t = FLT_MAX;
61 if (d_sq > r_sq) {
62 /* Outside sphere. */
63 const float one_minus_cos_half_spot_spread = 1.0f - klight->spot.cos_half_larger_spread;
64 const float one_minus_cos_half_angle = sin_sqr_to_one_minus_cos(r_sq / d_sq);
65
66 if (in_volume_segment || one_minus_cos_half_angle < one_minus_cos_half_spot_spread) {
67 /* Sample visible part of the sphere. */
68 ls->D = sample_uniform_cone(-lightN, one_minus_cos_half_angle, rand, &cos_theta, &ls->pdf);
69 }
70 else {
71 /* Sample spread cone. */
72 ls->D = sample_uniform_cone(
73 -klight->spot.dir, one_minus_cos_half_spot_spread, rand, &cos_theta, &ls->pdf);
74
76 P, ls->D, 0.0f, FLT_MAX, klight->co, klight->spot.radius, &ls->P, &ls->t))
77 {
78 /* Sampled direction does not intersect with the light. */
79 return false;
80 }
81 }
82 }
83 else {
84 /* Inside sphere. */
85 const bool has_transmission = (shader_flags & SD_BSDF_HAS_TRANSMISSION);
86 if (has_transmission) {
87 ls->D = sample_uniform_sphere(rand);
88 ls->pdf = M_1_2PI_F * 0.5f;
89 }
90 else {
91 sample_cos_hemisphere(N, rand, &ls->D, &ls->pdf);
92 }
93 cos_theta = -dot(ls->D, lightN);
94 }
95
96 /* Attenuation. */
97 const float3 local_ray = spot_light_to_local(klight, -ls->D);
98 if (d_sq > r_sq) {
99 ls->eval_fac *= spot_light_attenuation(&klight->spot, local_ray);
100 }
101 if (!in_volume_segment && ls->eval_fac == 0.0f) {
102 return false;
103 }
104
105 if (ls->t == FLT_MAX) {
106 /* Law of cosines. */
107 ls->t = d * cos_theta -
108 copysignf(safe_sqrtf(r_sq - d_sq + d_sq * sqr(cos_theta)), d_sq - r_sq);
109 ls->P = P + ls->D * ls->t;
110 }
111 else {
112 /* Already computed when sampling the spread cone. */
113 }
114
115 /* Remap sampled point onto the sphere to prevent precision issues with small radius. */
116 ls->Ng = normalize(ls->P - klight->co);
117 ls->P = ls->Ng * klight->spot.radius + klight->co;
118
119 /* Texture coordinates. */
120 spot_light_uv(local_ray, klight->spot.half_cot_half_spot_angle, &ls->u, &ls->v);
121 }
122 else {
123 /* Point light with ad-hoc radius based on oriented disk. */
124 ls->P = klight->co;
125 if (r_sq > 0.0f) {
126 ls->P += disk_light_sample(lightN, rand) * klight->spot.radius;
127 }
128
129 ls->D = normalize_len(ls->P - P, &ls->t);
130 ls->Ng = -ls->D;
131
132 /* Attenuation. */
133 const float3 local_ray = spot_light_to_local(klight, -ls->D);
134 ls->eval_fac *= spot_light_attenuation(&klight->spot, local_ray);
135 if (!in_volume_segment && ls->eval_fac == 0.0f) {
136 return false;
137 }
138
139 /* PDF. */
140 const float invarea = (r_sq > 0.0f) ? 1.0f / (r_sq * M_PI_F) : 1.0f;
141 ls->pdf = invarea * light_pdf_area_to_solid_angle(lightN, -ls->D, ls->t);
142
143 /* Texture coordinates. */
144 spot_light_uv(local_ray, klight->spot.half_cot_half_spot_angle, &ls->u, &ls->v);
145 }
146
147 return true;
148}
149
151 const float d_sq,
152 const float r_sq,
153 const float3 N,
154 const float3 D,
155 const uint32_t path_flag)
156{
157 if (d_sq > r_sq) {
158 return M_1_2PI_F /
159 min(sin_sqr_to_one_minus_cos(r_sq / d_sq), 1.0f - spot->cos_half_larger_spread);
160 }
161
162 const bool has_transmission = (path_flag & PATH_RAY_MIS_HAD_TRANSMISSION);
163 return has_transmission ? M_1_2PI_F * 0.5f : pdf_cos_hemisphere(N, D);
164}
165
168 const float3 P,
169 const float3 N,
170 const uint32_t path_flag)
171{
172 ls->D = normalize_len(ls->P - P, &ls->t);
173
174 ls->eval_fac = klight->spot.eval_fac;
175
176 const float radius = klight->spot.radius;
177 bool use_attenuation = true;
178
179 if (klight->spot.is_sphere) {
180 const float d_sq = len_squared(P - klight->co);
181 const float r_sq = sqr(radius);
182 const float t_sq = sqr(ls->t);
183
184 /* NOTE : preserve pdf in area measure. */
185 const float jacobian_solid_angle_to_area = 0.5f * fabsf(d_sq - r_sq - t_sq) /
186 (radius * ls->t * t_sq);
187 ls->pdf = spot_light_pdf(&klight->spot, d_sq, r_sq, N, ls->D, path_flag) *
188 jacobian_solid_angle_to_area;
189
190 ls->Ng = normalize(ls->P - klight->co);
191
192 use_attenuation = (d_sq > r_sq);
193 }
194 else {
195 /* NOTE : preserve pdf in area measure. */
196 ls->pdf = ls->eval_fac * 4.0f * M_PI_F;
197
198 ls->Ng = -ls->D;
199 }
200
201 /* Attenuation. */
202 const float3 local_ray = spot_light_to_local(klight, -ls->D);
203 if (use_attenuation) {
204 ls->eval_fac *= spot_light_attenuation(&klight->spot, local_ray);
205 }
206
207 /* Texture coordinates. */
208 spot_light_uv(local_ray, klight->spot.half_cot_half_spot_angle, &ls->u, &ls->v);
209}
210
212 const ccl_private Ray *ccl_restrict ray,
213 ccl_private float *t)
214{
215 /* One sided. */
216 if (dot(ray->D, ray->P - klight->co) >= 0.0f) {
217 return false;
218 }
219
220 return point_light_intersect(klight, ray, t);
221}
222
224 const float3 ray_P,
225 const float3 ray_D,
226 const float3 N,
227 const uint32_t path_flag,
229 ls)
230{
231 const float r_sq = sqr(klight->spot.radius);
232 const float d_sq = len_squared(ray_P - klight->co);
233
234 ls->eval_fac = klight->spot.eval_fac;
235
236 if (klight->spot.is_sphere) {
237 ls->pdf = spot_light_pdf(&klight->spot, d_sq, r_sq, N, ray_D, path_flag);
238 ls->Ng = normalize(ls->P - klight->co);
239 }
240 else {
241 if (ls->t != FLT_MAX) {
242 const float3 lightN = normalize(ray_P - klight->co);
243 const float invarea = (r_sq > 0.0f) ? 1.0f / (r_sq * M_PI_F) : 1.0f;
244 ls->pdf = invarea * light_pdf_area_to_solid_angle(lightN, -ray_D, ls->t);
245 }
246 else {
247 ls->pdf = 0.0f;
248 }
249 ls->Ng = -ray_D;
250 }
251
252 /* Attenuation. */
253 const float3 local_ray = spot_light_to_local(klight, -ray_D);
254 if (!klight->spot.is_sphere || d_sq > r_sq) {
255 ls->eval_fac *= spot_light_attenuation(&klight->spot, local_ray);
256 }
257 if (ls->eval_fac == 0) {
258 return false;
259 }
260
261 /* Texture coordinates. */
262 spot_light_uv(local_ray, klight->spot.half_cot_half_spot_angle, &ls->u, &ls->v);
263
264 return true;
265}
266
267/* Find the ray segment lit by the spot light. */
269 const float3 P,
270 const float3 D,
271 ccl_private float2 *t_range)
272{
273 /* Convert to local space of the spot light. */
274 const Transform itfm = klight->itfm;
275 float3 local_P = P + klight->spot.dir * klight->spot.ray_segment_dp;
276 local_P = transform_point(&itfm, local_P);
277 const float3 local_D = transform_direction(&itfm, D);
278 const float3 axis = make_float3(0.0f, 0.0f, -1.0f);
279
280 /* Intersect the ray with the smallest enclosing cone of the light spread. */
281 return ray_cone_intersect(
282 axis, local_P, local_D, sqr(klight->spot.cos_half_spot_angle), t_range);
283}
284
285template<bool in_volume_segment>
287 const float3 centroid,
288 const float3 P,
289 const ccl_private BoundingCone &bcone,
290 ccl_private float &cos_theta_u,
291 ccl_private float2 &distance,
292 ccl_private float3 &point_to_centroid,
293 ccl_private float &energy)
294{
295 float min_distance;
296 point_to_centroid = safe_normalize_len(centroid - P, &min_distance);
297 distance = min_distance * one_float2();
298
299 const float radius = klight->spot.radius;
300
301 if (klight->spot.is_sphere) {
302 cos_theta_u = (min_distance > radius) ? cos_from_sin(radius / min_distance) : -1.0f;
303
304 if (in_volume_segment) {
305 return true;
306 }
307
308 distance = (min_distance > radius) ? min_distance * make_float2(1.0f / cos_theta_u, 1.0f) :
309 one_float2() * radius / M_SQRT2_F;
310 }
311 else {
312 const float hypotenus = sqrtf(sqr(radius) + sqr(min_distance));
313 cos_theta_u = min_distance / hypotenus;
314
315 if (in_volume_segment) {
316 return true;
317 }
318
319 distance.x = hypotenus;
320 }
321
322 /* Apply a similar scaling as in `spot_light_attenuation()` to account for spot blend. */
323 {
324 /* Minimum angle formed by the emitter axis and the direction to the shading point,
325 * cos(theta') in the paper. */
326 const float cos_min_outgoing_angle = cosf(
327 fmaxf(0.0f, fast_acosf(dot(bcone.axis, -point_to_centroid)) - fast_acosf(cos_theta_u)));
328 /* Use `cos(bcone.theta_e)` instead of `klight->spot.cos_half_spot_angle` to account for
329 * non-uniform scaling. */
330 energy *= smoothstepf((cos_min_outgoing_angle - cosf(bcone.theta_e)) *
331 klight->spot.spot_smooth);
332 }
333
334 return true;
335}
336
MINLINE float safe_sqrtf(float a)
ATTR_WARN_UNUSED_RESULT const BMVert * v
ccl_device_inline float cos_theta(const float3 w)
SIMD_FORCE_INLINE btVector3 & normalize()
Normalize this vector x^2 + y^2 + z^2 = 1.
Definition btVector3.h:303
additional_info("compositor_sum_squared_difference_float_shared") .push_constant(Type output_img float dot(value.rgb, luminance_coefficients)") .define("LOAD(value)"
#define ccl_restrict
#define ccl_device_forceinline
#define cosf(x)
#define ccl_device
#define ccl_private
#define ccl_device_inline
#define ccl_global
#define CCL_NAMESPACE_END
ccl_device_forceinline float3 make_float3(const float x, const float y, const float z)
#define fmaxf(x, y)
ccl_device_forceinline float2 make_float2(const float x, const float y)
#define copysignf(x, y)
#define fabsf(x)
#define sqrtf(x)
struct BoundingCone { packed_float3 axis; float theta_o; float theta_e;} BoundingCone
@ SD_BSDF_HAS_TRANSMISSION
@ PATH_RAY_MIS_HAD_TRANSMISSION
ccl_device float3 disk_light_sample(float3 n, float2 rand)
ccl_device float light_pdf_area_to_solid_angle(const float3 Ng, const float3 I, float t)
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 float fast_acosf(float x)
Definition math_fast.h:260
ccl_device_inline float2 one_float2()
Definition math_float2.h:19
ccl_device_inline float len_squared(const float2 a)
ccl_device_inline float2 safe_normalize(const float2 a)
ccl_device_inline float2 normalize_len(const float2 a, ccl_private float *t)
ccl_device_inline float3 safe_normalize_len(const float3 a, ccl_private float *t)
ccl_device_inline bool ray_cone_intersect(const float3 axis, const float3 P, float3 D, const float cos_angle_sq, ccl_private float2 *t_range)
CCL_NAMESPACE_BEGIN ccl_device bool ray_sphere_intersect(float3 ray_P, float3 ray_D, float ray_tmin, float ray_tmax, float3 sphere_P, float sphere_radius, ccl_private float3 *isect_P, ccl_private float *isect_t)
#define N
#define M_PI_F
Definition mikk_util.hh:15
ccl_device_inline void sample_cos_hemisphere(const float3 N, float2 rand_in, ccl_private float3 *wo, ccl_private float *pdf)
ccl_device float3 sample_uniform_sphere(const float2 rand)
ccl_device_inline float3 sample_uniform_cone(const float3 N, const float one_minus_cos_angle, const float2 rand, ccl_private float *cos_theta, ccl_private float *pdf)
ccl_device_inline float pdf_cos_hemisphere(const float3 N, const float3 D)
#define min(a, b)
Definition sort.c:32
CCL_NAMESPACE_BEGIN ccl_device float3 spot_light_to_local(const ccl_global KernelLight *klight, const float3 ray)
Definition spot.h:12
ccl_device void spot_light_uv(const float3 ray, const float half_cot_half_spot_angle, ccl_private float *u, ccl_private float *v)
Definition spot.h:27
ccl_device float spot_light_attenuation(const ccl_global KernelSpotLight *spot, const float3 ray)
Definition spot.h:22
ccl_device_inline bool spot_light_valid_ray_segment(const ccl_global KernelLight *klight, const float3 P, const float3 D, ccl_private float2 *t_range)
Definition spot.h:268
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_forceinline float spot_light_pdf(const ccl_global KernelSpotLight *spot, const float d_sq, const float r_sq, const float3 N, const float3 D, const uint32_t path_flag)
Definition spot.h:150
ccl_device_forceinline void spot_light_mnee_sample_update(const ccl_global KernelLight *klight, ccl_private LightSample *ls, const float3 P, const float3 N, const uint32_t path_flag)
Definition spot.h:166
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
ccl_device_forceinline bool spot_light_tree_parameters(const ccl_global KernelLight *klight, const float3 centroid, const float3 P, const ccl_private BoundingCone &bcone, ccl_private float &cos_theta_u, ccl_private float2 &distance, ccl_private float3 &point_to_centroid, ccl_private float &energy)
Definition spot.h:286
#define FLT_MAX
Definition stdcycles.h:14
unsigned int uint32_t
Definition stdint.h:80
float z
Definition sky_float3.h:27
ccl_device_inline float3 transform_direction(ccl_private const Transform *t, const float3 a)
Definition transform.h:94
CCL_NAMESPACE_END CCL_NAMESPACE_BEGIN ccl_device_inline float3 transform_point(ccl_private const Transform *t, const float3 a)
Definition transform.h:63
ccl_device_inline float sqr(float a)
Definition util/math.h:782
ccl_device_inline float sin_sqr_to_one_minus_cos(const float s_sq)
Definition util/math.h:797
ccl_device_inline float smoothstepf(float f)
Definition util/math.h:508
ccl_device_inline float cos_from_sin(const float s)
Definition util/math.h:792