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