Files
workinf_Blender_Wasm/blender-5.2.0/intern/cycles/kernel/light/sun.h
2026-08-12 04:47:48 -04:00

123 lines
3.7 KiB
C++

/* SPDX-FileCopyrightText: 2011-2022 Blender Foundation
*
* SPDX-License-Identifier: Apache-2.0 */
#pragma once
#include "kernel/geom/object.h"
#include "kernel/light/common.h"
#include "util/math_fast.h"
CCL_NAMESPACE_BEGIN
ccl_device_inline float2 sun_light_uv(KernelGlobals kg,
const ccl_global KernelLight *klight,
const float3 D)
{
/* Map direction (x, y, z) to disk [-0.5, 0.5]^2:
* r^2 = (1 - z) / (1 - cos(klight->sun.angle))
* u_ = 0.5 * x * r / sin_angle(D, -klight->co)
* v_ = 0.5 * y * r / sin_angle(D, -klight->co) */
const float fac = klight->sun.half_inv_sin_half_angle / len(D - klight->co);
/* Get u axis and v axis. */
const Transform itfm = lamp_get_inverse_transform(kg, klight);
const float u_ = dot(D, make_float3(itfm.x)) * fac;
const float v_ = dot(D, make_float3(itfm.y)) * fac;
/* NOTE: Return barycentric coordinates in the same notation as Embree and OptiX. */
return make_float2(v_ + 0.5f, -u_ - v_);
}
ccl_device_inline bool sun_light_sample(const ccl_global KernelLight *klight,
const float2 rand,
ccl_private LightSample *ls)
{
float unused;
ls->Ng = sample_uniform_cone(
klight->co, klight->sun.one_minus_cosangle, rand, &unused, &ls->pdf);
ls->P = ls->Ng;
ls->D = -ls->Ng;
ls->t = FLT_MAX;
ls->eval_fac = klight->sun.eval_fac;
return true;
}
/* Special intersection check.
* Returns true if the sun_light_eval_from_intersection() for this light would return true.
*
* The intersection parameters t, u, v are optimized for the shadow ray towards a dedicated light:
* u = v = 0, t = FLT_MAX.
*/
ccl_device bool sun_light_intersect(const ccl_global KernelLight *klight,
const ccl_private Ray *ccl_restrict ray,
ccl_private float *t)
{
kernel_assert(klight->type == LIGHT_SUN);
if (klight->sun.angle == 0.0f) {
return false;
}
if (vector_angle(-klight->co, ray->D) > klight->sun.angle) {
return false;
}
*t = FLT_MAX;
return true;
}
ccl_device LightEval sun_light_eval_from_intersection(const ccl_global KernelLight *klight,
const float3 ray_D)
{
if (klight->sun.angle == 0.0f) {
return LightEval{};
}
if (vector_angle(-klight->co, ray_D) > klight->sun.angle) {
return LightEval{};
}
return LightEval{klight->sun.eval_fac, klight->sun.pdf};
}
template<bool in_volume_segment>
ccl_device_forceinline bool sun_light_tree_parameters(const float3 centroid,
const float theta_e,
const float t,
ccl_private float &cos_theta_u,
ccl_private float2 &distance,
ccl_private float3 &point_to_centroid,
ccl_private float &theta_d)
{
if (in_volume_segment) {
if (t == FLT_MAX) {
/* In world volumes, distant lights can contribute to the lighting of the volume with
* specific configurations of procedurally generated volumes. Use a ray length of 1.0 in this
* case to give the distant light some weight, but one that isn't too high for a typical
* world volume use case. */
theta_d = 1.0f;
}
else {
theta_d = t;
}
}
/* Treating it as a disk light 1 unit away */
cos_theta_u = fast_cosf(theta_e);
distance = make_float2(1.0f / cos_theta_u, 1.0f);
point_to_centroid = -centroid;
return true;
}
CCL_NAMESPACE_END