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