33 const float3 dir = *light_p -
P;
34 float z0 =
dot(dir,
z);
40 const float xc =
dot(dir,
x);
41 const float yc =
dot(dir,
y);
42 const float x0 = xc - 0.5f * len_u;
43 const float x1 = xc + 0.5f * len_u;
44 const float y0 = yc - 0.5f * len_v;
45 const float y1 = yc + 0.5f * len_v;
48 nz /=
sqrt(nz * nz + z0 * z0);
57 const float S = -(g0 + g1 + g2 + g3);
61 const float b0 = nz.
x;
62 const float b1 = nz.
z;
63 const float b0sq = b0 * b0;
69 const float au = rand.
x * S + g2 + g3;
72 cu =
clamp(cu, -1.0f, 1.0f);
74 float xu = -(cu * z0) /
max(
sqrtf(1.0f - cu * cu), 1e-7f);
75 xu =
clamp(xu, x0, x1);
77 const float d2 =
sqr(xu) +
sqr(z0);
78 const float h0 = y0 /
sqrtf(d2 +
sqr(y0));
79 const float h1 = y1 /
sqrtf(d2 +
sqr(y1));
80 const float hv = h0 + rand.
y * (h1 - h0);
81 const float hv2 = hv * hv;
82 const float yv = (hv2 < 1.0f - 1e-6f) ? hv *
sqrtf(d2 / (1.0f - hv2)) : y1;
85 *light_p =
P + xu *
x + yv *
y + z0 *
z;
98 const float t =
len(dir);
99 return safe_divide(-t * t * t, (z0 * len_u * len_v));
108 const float tan_half_spread,
109 const float normalize_spread)
115 if (tan_half_spread == 0.0f) {
117 return (tan_a > 1e-5f) ? 0.0f :
M_PI_F;
120 return max((tan_half_spread - tan_a) * normalize_spread, 0.0f);
132 const float tan_half_spread,
136 const float t =
dot(lightNg,
P - *lightP);
137 const float3 closest_P =
P - t * lightNg;
140 const float r_spread = t * tan_half_spread;
143 const float spread_u =
dot(*axis_u, closest_P - *lightP);
144 const float spread_v =
dot(*axis_v, closest_P - *lightP);
146 const bool is_round = !(*sample_rectangle) && (*len_u == *len_v);
149 bool sample_spread = (r_spread == 0.0f);
150 if (is_round && !sample_spread) {
155 const float r = *len_u * 0.5f;
157 if (dist >= r + r_spread) {
162 sample_spread = (dist <=
fabsf(r - r_spread)) && (r_spread < r);
163 if (dist >
fabsf(r - r_spread)) {
165 const float len_u_ = r + r_spread - dist;
166 const float len_v_ = (
fabsf(
sqr(r) -
sqr(r_spread)) >=
sqr(dist)) ?
167 2.0f *
fminf(r, r_spread) :
169 sqr(dist + (
sqr(r_spread) -
sqr(r)) / dist));
171 const float rect_area = len_u_ * len_v_;
172 const float circle_area =
M_PI_F *
sqr(r);
173 const float spread_area =
M_PI_F *
sqr(r_spread);
176 if (rect_area <
fminf(circle_area, spread_area)) {
177 *sample_rectangle =
true;
178 *axis_u =
normalize(*lightP - closest_P);
182 *lightP = 0.5f * (*lightP + closest_P + *axis_u * (r_spread - r));
186 sample_spread = (spread_area < circle_area);
189 else if (!is_round && !sample_spread) {
192 const float min_u =
max(spread_u - r_spread, -*len_u * 0.5f);
193 const float max_u =
min(spread_u + r_spread, *len_u * 0.5f);
194 const float min_v =
max(spread_v - r_spread, -*len_v * 0.5f);
195 const float max_v =
min(spread_v + r_spread, *len_v * 0.5f);
198 if (min_u >= max_u || min_v >= max_v) {
202 const float rect_len_u = max_u - min_u;
203 const float rect_len_v = max_v - min_v;
205 const float rect_area = rect_len_u * rect_len_v;
206 const float ellipse_area = (*sample_rectangle) ?
FLT_MAX :
M_PI_4_F * (*len_u) * (*len_v);
207 const float spread_area =
M_PI_F *
sqr(r_spread);
213 if (*sample_rectangle || rect_area <
fminf(ellipse_area, spread_area)) {
214 *sample_rectangle =
true;
218 const float new_center_u = 0.5f * (min_u + max_u);
219 const float new_center_v = 0.5f * (min_v + max_v);
223 *lightP = *lightP + *axis_u * new_center_u + *axis_v * new_center_v;
226 *sample_rectangle =
false;
227 sample_spread = (spread_area < ellipse_area);
231 *sample_rectangle =
false;
232 *lightP = *lightP + *axis_u * spread_u + *axis_v * spread_v;
233 *len_u = r_spread * 2.0f;
234 *len_v = r_spread * 2.0f;
244 return light->invarea < 0.0f;
249template<
bool in_volume_segment>
257 float3 axis_u = klight->area.axis_u;
258 float3 axis_v = klight->area.axis_v;
259 float len_u = klight->area.len_u;
260 float len_v = klight->area.len_v;
262 const float3 Ng = klight->area.dir;
263 const float invarea =
fabsf(klight->area.invarea);
264 bool sample_rectangle = (klight->area.invarea > 0.0f);
266 float3 light_P_new = *light_P;
268 if (in_volume_segment) {
269 light_P_new += sample_rectangle ?
271 ellipse_sample(axis_u * len_u * 0.5f, axis_v * len_v * 0.5f, rand);
275 if (klight->area.normalize_spread > 0) {
283 klight->area.tan_half_spread,
290 if (sample_rectangle) {
292 ray_P, &light_P_new, axis_u, len_u, axis_v, len_v, rand, sample_coord);
295 if (klight->area.tan_half_spread == 0.0f) {
300 light_P_new +=
ellipse_sample(axis_u * len_u * 0.5f, axis_v * len_v * 0.5f, rand);
302 ls->pdf = 4.0f *
M_1_PI_F / (len_u * len_v);
308 *light_P = light_P_new;
315 if (klight->area.normalize_spread > 0) {
318 ls->D, Ng, klight->area.tan_half_spread, klight->area.normalize_spread);
321 if (in_volume_segment || (!sample_rectangle && klight->area.tan_half_spread > 0)) {
325 return in_volume_segment || ls->eval_fac > 0;
328template<
bool in_volume_segment>
335 ls->Ng = klight->area.dir;
337 if (!in_volume_segment) {
338 if (
dot(ls->P -
P, ls->Ng) > 0.0f) {
347 const float3 inplane = ls->P - klight->co;
348 float light_u =
dot(inplane, klight->area.axis_u);
349 float light_v =
dot(inplane, klight->area.axis_v);
351 if (!in_volume_segment && klight->area.normalize_spread > 0) {
358 const float len_u_epsilon = ((0.5f + 1e-7f) * klight->area.len_u + 1e-6f);
359 const float len_v_epsilon = ((0.5f + 1e-7f) * klight->area.len_v + 1e-6f);
360 if (is_ellipse && (
sqr(light_u / len_u_epsilon) +
sqr(light_v / len_v_epsilon) > 1.0f)) {
363 if (!is_ellipse && (
fabsf(light_u) > len_u_epsilon ||
fabsf(light_v) > len_v_epsilon)) {
368 light_u /= klight->area.len_u;
369 light_v /= klight->area.len_v;
372 ls->u = light_v + 0.5f;
373 ls->v = -light_u - light_v;
382 if (klight->area.tan_half_spread == 0) {
401 const float invarea =
fabsf(klight->area.invarea);
403 if (invarea == 0.0f) {
407 const float3 inv_extent_u = klight->area.axis_u / klight->area.len_u;
408 const float3 inv_extent_v = klight->area.axis_v / klight->area.len_v;
409 const float3 Ng = klight->area.dir;
412 if (
dot(ray->D, Ng) >= 0.0f) {
416 const float3 light_P = klight->co;
444 ls->Ng = klight->area.dir;
446 float3 light_P = klight->co;
464 const float tan_half_spread = light->tan_half_spread;
467 const bool angle_almost_zero = (tan_half_spread < 1e-5f);
468 if (angle_almost_zero) {
476 const float half_len_u = 0.5f * light->len_u;
477 const float half_len_v = 0.5f * light->len_v;
490 const float cos_angle_sq = 1.0f / (1.0f +
sqr(tan_half_spread));
499template<
bool in_volume_segment>
517 const float3 extentu = klight->area.axis_u * klight->area.len_u;
518 const float3 extentv = klight->area.axis_v * klight->area.len_v;
519 for (
int i = 0;
i < 4;
i++) {
520 const float3 corner = ((
i & 1) - 0.5f) * extentu + 0.5f * ((
i & 2) - 1) * extentv + centroid;
521 float distance_point_to_corner;
523 cos_theta_u =
fminf(cos_theta_u,
dot(point_to_centroid, point_to_corner));
524 if (!in_volume_segment) {
529 const bool front_facing =
dot(bcone_axis, point_to_centroid) < 0;
530 const bool shape_above_surface =
dot(
N, centroid -
P) +
fabsf(
dot(
N, extentu)) +
534 return front_facing && shape_above_surface;
MINLINE float safe_divide(float a, float b)
MINLINE float safe_asinf(float a)
ccl_device bool area_light_spread_clamp_light(const float3 P, const float3 lightNg, ccl_private float3 *lightP, ccl_private float3 *axis_u, ccl_private float *len_u, ccl_private float3 *axis_v, ccl_private float *len_v, const float tan_half_spread, ccl_private bool *sample_rectangle)
ccl_device_forceinline bool area_light_is_ellipse(const ccl_global KernelAreaLight *light)
ccl_device_inline bool area_light_sample(const ccl_global KernelLight *klight, const float2 rand, const float3 P, ccl_private LightSample *ls)
CCL_NAMESPACE_BEGIN ccl_device_inline float area_light_rect_sample(const float3 P, ccl_private float3 *light_p, const float3 axis_u, const float len_u, const float3 axis_v, const float len_v, const float2 rand, bool sample_coord)
ccl_device_inline bool area_light_sample_from_intersection(const ccl_global KernelLight *klight, const ccl_private Intersection *ccl_restrict isect, const float3 ray_P, const float3 ray_D, ccl_private LightSample *ccl_restrict ls)
ccl_device_inline bool area_light_intersect(const ccl_global KernelLight *klight, const ccl_private Ray *ccl_restrict ray, ccl_private float *t, ccl_private float *u, ccl_private float *v)
ccl_device float area_light_spread_attenuation(const float3 D, const float3 lightNg, const float tan_half_spread, const float normalize_spread)
ccl_device_inline bool area_light_valid_ray_segment(const ccl_global KernelAreaLight *light, float3 P, float3 D, ccl_private Interval< float > *t_range)
ccl_device_inline bool area_light_eval(const ccl_global KernelLight *klight, const float3 ray_P, ccl_private float3 *light_P, ccl_private LightSample *ccl_restrict ls, const float2 rand, bool sample_coord)
ccl_device_forceinline void area_light_mnee_sample_update(const ccl_global KernelLight *klight, ccl_private LightSample *ls, const float3 P)
ccl_device_forceinline float area_light_max_extent(const ccl_global KernelAreaLight *light)
ccl_device_forceinline bool area_light_tree_parameters(const ccl_global KernelLight *klight, const float3 centroid, const float3 P, const float3 N, const float3 bcone_axis, ccl_private float &cos_theta_u, ccl_private float2 &distance, ccl_private float3 &point_to_centroid)
ATTR_WARN_UNUSED_RESULT const BMVert * v
SIMD_FORCE_INLINE const btScalar & z() const
Return the z value.
dot(value.rgb, luminance_coefficients)") DEFINE_VALUE("REDUCE(lhs
#define ccl_device_forceinline
#define ccl_device_inline
#define CCL_NAMESPACE_END
VecBase< float, D > normalize(VecOp< float, D >) RET
VecBase< float, 3 > cross(VecOp< float, 3 >, VecOp< float, 3 >) RET
constexpr T clamp(T, U, U) RET
float distance(VecOp< float, D >, VecOp< float, D >) RET
ccl_device_inline float3 ellipse_sample(const float3 ru, const float3 rv, const float2 rand)
ccl_device float light_pdf_area_to_solid_angle(const float3 Ng, const float3 I, const float t)
ccl_device_inline float3 rectangle_sample(const float3 ru, const float3 rv, const float2 rand)
CCL_NAMESPACE_BEGIN ccl_device_inline float2 zero_float2()
ccl_device_inline float reduce_min(const float2 a)
ccl_device_inline float3 rotate_around_axis(const float3 p, const float3 axis, const float angle)
ccl_device_inline float3 safe_normalize_len(const float3 a, ccl_private float *t)
ccl_device_inline float tan_angle(const float3 a, const float3 b)
ccl_device_inline bool ray_cone_intersect(const float3 axis, const float3 P, float3 D, const float cos_angle_sq, ccl_private Interval< float > *t_range)
ccl_device bool ray_aabb_intersect(const float3 bbox_min, const float3 bbox_max, const float3 ray_P, const float3 ray_D, ccl_private Interval< float > *t_range)
ccl_device_inline bool ray_infinite_cylinder_intersect(const float3 P, const float3 D, const float len_u, const float len_v, ccl_private Interval< float > *t_range)
ccl_device bool ray_plane_intersect(const float3 N, const float3 P, const float3 ray_D, ccl_private Interval< float > *t_range)
ccl_device bool ray_quad_intersect(const float3 ray_P, const float3 ray_D, const float ray_tmin, const float ray_tmax, const float3 quad_P, const float3 inv_quad_u, const float3 inv_quad_v, const float3 quad_n, ccl_private float3 *isect_P, ccl_private float *isect_t, ccl_private float *isect_u, ccl_private float *isect_v, bool ellipse)