Blender V4.3
light/point.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
12 const float2 rand,
13 const float3 P,
14 const float3 N,
15 const int shader_flags,
17{
18 const float r_sq = sqr(klight->spot.radius);
19
20 float3 lightN = P - klight->co;
21 const float d_sq = len_squared(lightN);
22 const float d = sqrtf(d_sq);
23 lightN /= d;
24
25 ls->eval_fac = klight->spot.eval_fac;
26
27 if (klight->spot.is_sphere) {
28 /* Spherical light geometry. */
29 float cos_theta;
30 if (d_sq > r_sq) {
31 /* Outside sphere. */
32 const float one_minus_cos = sin_sqr_to_one_minus_cos(r_sq / d_sq);
33 ls->D = sample_uniform_cone(-lightN, one_minus_cos, rand, &cos_theta, &ls->pdf);
34 }
35 else {
36 /* Inside sphere. */
37 const bool has_transmission = (shader_flags & SD_BSDF_HAS_TRANSMISSION);
38 if (has_transmission) {
39 ls->D = sample_uniform_sphere(rand);
40 ls->pdf = M_1_2PI_F * 0.5f;
41 }
42 else {
43 sample_cos_hemisphere(N, rand, &ls->D, &ls->pdf);
44 }
45 cos_theta = -dot(ls->D, lightN);
46 }
47
48 /* Law of cosines. */
49 ls->t = d * cos_theta -
50 copysignf(safe_sqrtf(r_sq - d_sq + d_sq * sqr(cos_theta)), d_sq - r_sq);
51
52 /* Remap sampled point onto the sphere to prevent precision issues with small radius. */
53 ls->P = P + ls->D * ls->t;
54 ls->Ng = normalize(ls->P - klight->co);
55 ls->P = ls->Ng * klight->spot.radius + klight->co;
56 }
57 else {
58 /* Point light with ad-hoc radius based on oriented disk. */
59 ls->P = klight->co;
60 if (r_sq > 0.0f) {
61 ls->P += disk_light_sample(lightN, rand) * klight->spot.radius;
62 }
63
64 ls->D = normalize_len(ls->P - P, &ls->t);
65 ls->Ng = -ls->D;
66
67 /* PDF. */
68 const float invarea = (r_sq > 0.0f) ? 1.0f / (r_sq * M_PI_F) : 1.0f;
69 ls->pdf = invarea * light_pdf_area_to_solid_angle(lightN, -ls->D, ls->t);
70 }
71
72 /* Texture coordinates. */
73 const Transform itfm = klight->itfm;
74 const float2 uv = map_to_sphere(transform_direction(&itfm, ls->Ng));
75 /* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */
76 ls->u = uv.y;
77 ls->v = 1.0f - uv.x - uv.y;
78
79 return true;
80}
81
83 const float d_sq, const float r_sq, const float3 N, const float3 D, const uint32_t path_flag)
84{
85 if (d_sq > r_sq) {
86 return M_1_2PI_F / sin_sqr_to_one_minus_cos(r_sq / d_sq);
87 }
88
89 const bool has_transmission = (path_flag & PATH_RAY_MIS_HAD_TRANSMISSION);
90 return has_transmission ? M_1_2PI_F * 0.5f : pdf_cos_hemisphere(N, D);
91}
92
95 const float3 P,
96 const float3 N,
97 const uint32_t path_flag)
98{
99 ls->D = normalize_len(ls->P - P, &ls->t);
100
101 const float radius = klight->spot.radius;
102
103 if (klight->spot.is_sphere) {
104 const float d_sq = len_squared(P - klight->co);
105 const float r_sq = sqr(radius);
106 const float t_sq = sqr(ls->t);
107
108 /* NOTE : preserve pdf in area measure. */
109 const float jacobian_solid_angle_to_area = 0.5f * fabsf(d_sq - r_sq - t_sq) /
110 (radius * ls->t * t_sq);
111 ls->pdf = sphere_light_pdf(d_sq, r_sq, N, ls->D, path_flag) * jacobian_solid_angle_to_area;
112
113 ls->Ng = normalize(ls->P - klight->co);
114 }
115 else {
116 /* NOTE : preserve pdf in area measure. */
117 ls->pdf = ls->eval_fac * 4.0f * M_PI_F;
118
119 ls->Ng = -ls->D;
120 }
121
122 /* Texture coordinates. */
123 const Transform itfm = klight->itfm;
124 const float2 uv = map_to_sphere(transform_direction(&itfm, ls->Ng));
125 /* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */
126 ls->u = uv.y;
127 ls->v = 1.0f - uv.x - uv.y;
128}
129
131 const ccl_private Ray *ccl_restrict ray,
132 ccl_private float *t)
133{
134 const float radius = klight->spot.radius;
135 if (radius == 0.0f) {
136 return false;
137 }
138
139 if (klight->spot.is_sphere) {
140 float3 P;
141 return ray_sphere_intersect(ray->P, ray->D, ray->tmin, ray->tmax, klight->co, radius, &P, t);
142 }
143 else {
144 float3 P;
145 const float3 diskN = normalize(ray->P - klight->co);
146 return ray_disk_intersect(
147 ray->P, ray->D, ray->tmin, ray->tmax, klight->co, diskN, radius, &P, t);
148 }
149}
150
152 const float3 ray_P,
153 const float3 ray_D,
154 const float3 N,
155 const uint32_t path_flag,
157 ls)
158{
159 const float r_sq = sqr(klight->spot.radius);
160
161 ls->eval_fac = klight->spot.eval_fac;
162
163 if (klight->spot.is_sphere) {
164 const float d_sq = len_squared(ray_P - klight->co);
165 ls->pdf = sphere_light_pdf(d_sq, r_sq, N, ray_D, path_flag);
166 ls->Ng = normalize(ls->P - klight->co);
167 }
168 else {
169 if (ls->t != FLT_MAX) {
170 const float3 lightN = normalize(ray_P - klight->co);
171 const float invarea = (r_sq > 0.0f) ? 1.0f / (r_sq * M_PI_F) : 1.0f;
172 ls->pdf = invarea * light_pdf_area_to_solid_angle(lightN, -ray_D, ls->t);
173 }
174 else {
175 ls->pdf = 0.0f;
176 }
177 ls->Ng = -ray_D;
178 }
179
180 /* Texture coordinates. */
181 const Transform itfm = klight->itfm;
182 const float2 uv = map_to_sphere(transform_direction(&itfm, ls->Ng));
183 /* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */
184 ls->u = uv.y;
185 ls->v = 1.0f - uv.x - uv.y;
186
187 return true;
188}
189
190template<bool in_volume_segment>
192 const float3 centroid,
193 const float3 P,
194 ccl_private float &cos_theta_u,
195 ccl_private float2 &distance,
196 ccl_private float3 &point_to_centroid)
197{
198 float min_distance;
199 point_to_centroid = safe_normalize_len(centroid - P, &min_distance);
200 distance = min_distance * one_float2();
201
202 if (in_volume_segment) {
203 cos_theta_u = 1.0f; /* Any value in [-1, 1], irrelevant since theta = 0 */
204 return true;
205 }
206
207 const float radius = klight->spot.radius;
208
209 if (klight->spot.is_sphere) {
210 if (min_distance > radius) {
211 /* Equivalent to a disk light with the same angular span. */
212 cos_theta_u = cos_from_sin(radius / min_distance);
213 distance.x = min_distance / cos_theta_u;
214 }
215 else {
216 /* Similar to background light. */
217 cos_theta_u = -1.0f;
218 /* HACK: pack radiance scaling in the distance. */
219 distance = one_float2() * radius / M_SQRT2_F;
220 }
221 }
222 else {
223 const float hypotenus = sqrtf(sqr(radius) + sqr(min_distance));
224 cos_theta_u = min_distance / hypotenus;
225
226 distance.x = hypotenus;
227 }
228
229 return true;
230}
231
MINLINE float safe_sqrtf(float a)
bool map_to_sphere(float *r_u, float *r_v, float x, float y, float z)
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 ccl_private
#define ccl_device_inline
#define ccl_global
#define CCL_NAMESPACE_END
#define copysignf(x, y)
#define fabsf(x)
#define sqrtf(x)
@ 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_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_forceinline bool point_light_tree_parameters(const ccl_global KernelLight *klight, const float3 centroid, const float3 P, ccl_private float &cos_theta_u, ccl_private float2 &distance, ccl_private float3 &point_to_centroid)
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 float sphere_light_pdf(const float d_sq, const float r_sq, const float3 N, const float3 D, const uint32_t path_flag)
Definition light/point.h:82
ccl_device_forceinline void point_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 light/point.h:93
ccl_device_inline float2 one_float2()
Definition math_float2.h:19
ccl_device_inline float len_squared(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 bool ray_disk_intersect(float3 ray_P, float3 ray_D, float ray_tmin, float ray_tmax, float3 disk_P, float3 disk_N, float disk_radius, ccl_private float3 *isect_P, ccl_private float *isect_t)
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 FLT_MAX
Definition stdcycles.h:14
unsigned int uint32_t
Definition stdint.h:80
float x
float y
ccl_device_inline float3 transform_direction(ccl_private const Transform *t, const float3 a)
Definition transform.h:94
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 one_minus_cos(const float angle)
Definition util/math.h:803
ccl_device_inline float cos_from_sin(const float s)
Definition util/math.h:792