Refactor: Cycles: add helper struct Interval
To improve readability Pull Request: https://projects.blender.org/blender/blender/pulls/130156
This commit is contained in:
committed by
Weizhen Huang
parent
675e8173fa
commit
93a34b1077
@@ -66,7 +66,7 @@ typedef struct VolumeShaderCoefficients {
|
||||
|
||||
typedef struct EquiangularCoefficients {
|
||||
float3 P;
|
||||
float2 t_range;
|
||||
Interval<float> t_range;
|
||||
} EquiangularCoefficients;
|
||||
|
||||
/* Evaluate shader to get extinction coefficient at P. */
|
||||
@@ -273,8 +273,8 @@ ccl_device float volume_equiangular_sample(ccl_private const Ray *ccl_restrict r
|
||||
*pdf = 0.0f;
|
||||
return 0.0f;
|
||||
}
|
||||
const float tmin = coeffs.t_range.x;
|
||||
const float tmax = coeffs.t_range.y;
|
||||
const float tmin = coeffs.t_range.min;
|
||||
const float tmax = coeffs.t_range.max;
|
||||
const float theta_a = atan2f(tmin - delta, D);
|
||||
const float theta_b = atan2f(tmax - delta, D);
|
||||
const float t_ = D * tanf((xi * theta_b) + (1 - xi) * theta_a);
|
||||
@@ -297,8 +297,8 @@ ccl_device float volume_equiangular_pdf(ccl_private const Ray *ccl_restrict ray,
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
const float tmin = coeffs.t_range.x;
|
||||
const float tmax = coeffs.t_range.y;
|
||||
const float tmin = coeffs.t_range.min;
|
||||
const float tmax = coeffs.t_range.max;
|
||||
const float t_ = sample_t - delta;
|
||||
|
||||
const float theta_a = atan2f(tmin - delta, D);
|
||||
@@ -315,7 +315,7 @@ ccl_device float volume_equiangular_pdf(ccl_private const Ray *ccl_restrict ray,
|
||||
ccl_device_inline bool volume_equiangular_valid_ray_segment(KernelGlobals kg,
|
||||
const float3 ray_P,
|
||||
const float3 ray_D,
|
||||
ccl_private float2 *t_range,
|
||||
ccl_private Interval<float> *t_range,
|
||||
const ccl_private LightSample *ls)
|
||||
{
|
||||
if (ls->type == LIGHT_SPOT) {
|
||||
@@ -368,9 +368,8 @@ ccl_device Spectrum volume_emission_integrate(ccl_private VolumeShaderCoefficien
|
||||
/* Volume Integration */
|
||||
|
||||
typedef struct VolumeIntegrateState {
|
||||
/* Volume segment extents. */
|
||||
float tmin;
|
||||
float tmax;
|
||||
/* Current active segment. */
|
||||
Interval<float> t;
|
||||
|
||||
/* If volume is absorption-only up to this point, and no probabilistic
|
||||
* scattering or termination has been used yet. */
|
||||
@@ -405,10 +404,8 @@ ccl_device_forceinline void volume_integrate_step_scattering(
|
||||
|
||||
/* Equiangular sampling for direct lighting. */
|
||||
if (vstate.direct_sample_method == VOLUME_SAMPLE_EQUIANGULAR && !result.direct_scatter) {
|
||||
if (result.direct_t >= vstate.tmin && result.direct_t <= vstate.tmax &&
|
||||
vstate.equiangular_pdf > VOLUME_SAMPLE_PDF_CUTOFF)
|
||||
{
|
||||
const float new_dt = result.direct_t - vstate.tmin;
|
||||
if (vstate.t.contains(result.direct_t) && vstate.equiangular_pdf > VOLUME_SAMPLE_PDF_CUTOFF) {
|
||||
const float new_dt = result.direct_t - vstate.t.min;
|
||||
const Spectrum new_transmittance = volume_color_transmittance(coeff.sigma_t, new_dt);
|
||||
|
||||
result.direct_scatter = true;
|
||||
@@ -438,7 +435,7 @@ ccl_device_forceinline void volume_integrate_step_scattering(
|
||||
/* compute sampling distance */
|
||||
const float sample_sigma_t = volume_channel_get(coeff.sigma_t, channel);
|
||||
const float new_dt = -logf(1.0f - vstate.rscatter) / sample_sigma_t;
|
||||
const float new_t = vstate.tmin + new_dt;
|
||||
const float new_t = vstate.t.min + new_dt;
|
||||
|
||||
/* transmittance and pdf */
|
||||
const Spectrum new_transmittance = volume_color_transmittance(coeff.sigma_t, new_dt);
|
||||
@@ -517,8 +514,8 @@ ccl_device_forceinline void volume_integrate_heterogeneous(
|
||||
|
||||
/* Initialize volume integration state. */
|
||||
VolumeIntegrateState vstate ccl_optional_struct_init;
|
||||
vstate.tmin = ray->tmin;
|
||||
vstate.tmax = ray->tmin;
|
||||
vstate.t.min = ray->tmin;
|
||||
vstate.t.max = ray->tmin;
|
||||
vstate.absorption_only = true;
|
||||
vstate.rscatter = path_state_rng_1D(kg, rng_state, PRNG_VOLUME_SCATTER_DISTANCE);
|
||||
vstate.rchannel = path_state_rng_1D(kg, rng_state, PRNG_VOLUME_COLOR_CHANNEL);
|
||||
@@ -562,8 +559,8 @@ ccl_device_forceinline void volume_integrate_heterogeneous(
|
||||
|
||||
for (int i = 0; i < max_steps; i++) {
|
||||
/* Advance to new position */
|
||||
vstate.tmax = min(ray->tmax, ray->tmin + (i + steps_offset) * step_size);
|
||||
const float shade_t = vstate.tmin + (vstate.tmax - vstate.tmin) * step_shade_offset;
|
||||
vstate.t.max = min(ray->tmax, ray->tmin + (i + steps_offset) * step_size);
|
||||
const float shade_t = vstate.t.min + (vstate.t.max - vstate.t.min) * step_shade_offset;
|
||||
sd->P = ray->P + ray->D * shade_t;
|
||||
|
||||
/* compute segment */
|
||||
@@ -572,7 +569,7 @@ ccl_device_forceinline void volume_integrate_heterogeneous(
|
||||
const int closure_flag = sd->flag;
|
||||
|
||||
/* Evaluate transmittance over segment. */
|
||||
const float dt = (vstate.tmax - vstate.tmin);
|
||||
const float dt = (vstate.t.max - vstate.t.min);
|
||||
const Spectrum transmittance = (closure_flag & SD_EXTINCTION) ?
|
||||
volume_color_transmittance(coeff.sigma_t, dt) :
|
||||
one_spectrum();
|
||||
@@ -630,8 +627,8 @@ ccl_device_forceinline void volume_integrate_heterogeneous(
|
||||
}
|
||||
|
||||
/* Stop if at the end of the volume. */
|
||||
vstate.tmin = vstate.tmax;
|
||||
if (vstate.tmin == ray->tmax) {
|
||||
vstate.t.min = vstate.t.max;
|
||||
if (vstate.t.min == ray->tmax) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -970,7 +967,7 @@ ccl_device VolumeIntegrateEvent volume_integrate(KernelGlobals kg,
|
||||
LightSample ls ccl_optional_struct_init;
|
||||
const bool need_light_sample = !(INTEGRATOR_STATE(state, path, flag) & PATH_RAY_TERMINATE);
|
||||
|
||||
EquiangularCoefficients equiangular_coeffs = {zero_float3(), make_float2(ray->tmin, ray->tmax)};
|
||||
EquiangularCoefficients equiangular_coeffs = {zero_float3(), {ray->tmin, ray->tmax}};
|
||||
|
||||
const bool have_equiangular_sample =
|
||||
need_light_sample && integrate_volume_equiangular_sample_light(
|
||||
|
||||
@@ -454,7 +454,7 @@ ccl_device_forceinline float area_light_max_extent(const ccl_global KernelAreaLi
|
||||
ccl_device_inline bool area_light_valid_ray_segment(const ccl_global KernelAreaLight *light,
|
||||
float3 P,
|
||||
float3 D,
|
||||
ccl_private float2 *t_range)
|
||||
ccl_private Interval<float> *t_range)
|
||||
{
|
||||
bool valid;
|
||||
const float tan_half_spread = light->tan_half_spread;
|
||||
|
||||
@@ -268,7 +268,7 @@ ccl_device_inline bool spot_light_sample_from_intersection(const ccl_global Kern
|
||||
ccl_device_inline bool spot_light_valid_ray_segment(const ccl_global KernelLight *klight,
|
||||
const float3 P,
|
||||
const float3 D,
|
||||
ccl_private float2 *t_range)
|
||||
ccl_private Interval<float> *t_range)
|
||||
{
|
||||
/* Convert to local space of the spot light. */
|
||||
const Transform itfm = klight->itfm;
|
||||
|
||||
@@ -273,7 +273,7 @@ ccl_device_forceinline bool triangle_light_sample(KernelGlobals kg,
|
||||
ccl_device_inline bool triangle_light_valid_ray_segment(KernelGlobals kg,
|
||||
const float3 P,
|
||||
const float3 D,
|
||||
ccl_private float2 *t_range,
|
||||
ccl_private Interval<float> *t_range,
|
||||
const ccl_private LightSample *ls)
|
||||
{
|
||||
const int shader_flag = kernel_data_fetch(shaders, ls->shader & SHADER_MASK).flags;
|
||||
|
||||
@@ -1055,16 +1055,6 @@ ccl_device_inline uint32_t reverse_integer_bits(uint32_t x)
|
||||
#endif
|
||||
}
|
||||
|
||||
/* Check if intervals (first->x, first->y) and (second.x, second.y) intersect, and replace the
|
||||
* first interval with their intersection. */
|
||||
ccl_device_inline bool intervals_intersect(ccl_private float2 *first, const float2 second)
|
||||
{
|
||||
first->x = fmaxf(first->x, second.x);
|
||||
first->y = fminf(first->y, second.y);
|
||||
|
||||
return first->x < first->y;
|
||||
}
|
||||
|
||||
/* Solve quadratic equation a*x^2 + b*x + c = 0, adapted from Mitsuba 3
|
||||
* The solution is ordered so that x1 <= x2.
|
||||
* Returns true if at least one solution is found. */
|
||||
@@ -1095,6 +1085,30 @@ ccl_device_inline bool solve_quadratic(
|
||||
return (valid_linear || valid_quadratic);
|
||||
}
|
||||
|
||||
/* Defines a closed interval [min, max]. */
|
||||
template<typename T> struct Interval {
|
||||
T min;
|
||||
T max;
|
||||
|
||||
bool is_empty() const
|
||||
{
|
||||
return min >= max;
|
||||
}
|
||||
|
||||
bool contains(T value) const
|
||||
{
|
||||
return value >= min && value <= max;
|
||||
}
|
||||
};
|
||||
|
||||
/* Computes the intersection of two intervals. */
|
||||
template<typename T>
|
||||
ccl_device_inline Interval<T> intervals_intersection(ccl_private const Interval<T> &first,
|
||||
ccl_private const Interval<T> &second)
|
||||
{
|
||||
return {max(first.min, second.min), min(first.max, second.max)};
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
#endif /* __UTIL_MATH_H__ */
|
||||
|
||||
@@ -307,7 +307,7 @@ ccl_device bool ray_quad_intersect(float3 ray_P,
|
||||
ccl_device bool ray_plane_intersect(const float3 N,
|
||||
const float3 P,
|
||||
const float3 ray_D,
|
||||
ccl_private float2 *t_range)
|
||||
ccl_private Interval<float> *t_range)
|
||||
{
|
||||
const float DN = dot(ray_D, N);
|
||||
|
||||
@@ -316,13 +316,13 @@ ccl_device bool ray_plane_intersect(const float3 N,
|
||||
|
||||
/* Limit the range to the positive side. */
|
||||
if (DN > 0.0f) {
|
||||
t_range->x = fmaxf(t_range->x, t);
|
||||
t_range->min = fmaxf(t_range->min, t);
|
||||
}
|
||||
else {
|
||||
t_range->y = fminf(t_range->y, t);
|
||||
t_range->max = fminf(t_range->max, t);
|
||||
}
|
||||
|
||||
return t_range->x < t_range->y;
|
||||
return !t_range->is_empty();
|
||||
}
|
||||
|
||||
/* Find the ray segment inside an axis-aligned bounding box. */
|
||||
@@ -330,7 +330,7 @@ ccl_device bool ray_aabb_intersect(const float3 bbox_min,
|
||||
const float3 bbox_max,
|
||||
const float3 ray_P,
|
||||
const float3 ray_D,
|
||||
ccl_private float2 *t_range)
|
||||
ccl_private Interval<float> *t_range)
|
||||
{
|
||||
const float3 inv_ray_D = rcp(ray_D);
|
||||
|
||||
@@ -339,16 +339,16 @@ ccl_device bool ray_aabb_intersect(const float3 bbox_min,
|
||||
const float3 t_upper = (bbox_max - ray_P) * inv_ray_D;
|
||||
|
||||
/* The four t-intervals (for x-/y-/z-slabs, and ray p(t)). */
|
||||
const float4 tmins = float3_to_float4(min(t_lower, t_upper), t_range->x);
|
||||
const float4 tmaxes = float3_to_float4(max(t_lower, t_upper), t_range->y);
|
||||
const float4 tmins = float3_to_float4(min(t_lower, t_upper), t_range->min);
|
||||
const float4 tmaxes = float3_to_float4(max(t_lower, t_upper), t_range->max);
|
||||
|
||||
/* Max of mins and min of maxes. */
|
||||
const float tmin = reduce_max(tmins);
|
||||
const float tmax = reduce_min(tmaxes);
|
||||
|
||||
*t_range = make_float2(tmin, tmax);
|
||||
*t_range = {tmin, tmax};
|
||||
|
||||
return tmin < tmax;
|
||||
return !t_range->is_empty();
|
||||
}
|
||||
|
||||
/* Find the segment of a ray defined by P + D * t that lies inside a cylinder defined by
|
||||
@@ -357,7 +357,7 @@ ccl_device_inline bool ray_infinite_cylinder_intersect(const float3 P,
|
||||
const float3 D,
|
||||
const float len_u,
|
||||
const float len_v,
|
||||
ccl_private float2 *t_range)
|
||||
ccl_private Interval<float> *t_range)
|
||||
{
|
||||
/* Convert to a 2D problem. */
|
||||
const float2 inv_len = 1.0f / make_float2(len_u, len_v);
|
||||
@@ -379,7 +379,9 @@ ccl_device_inline bool ray_infinite_cylinder_intersect(const float3 P,
|
||||
float tmin, tmax;
|
||||
const bool valid = solve_quadratic(a, 2.0f * b, c, tmin, tmax);
|
||||
|
||||
return valid && intervals_intersect(t_range, make_float2(tmin, tmax) + t_mid);
|
||||
*t_range = intervals_intersection(*t_range, {tmin + t_mid, tmax + t_mid});
|
||||
|
||||
return valid && !t_range->is_empty();
|
||||
}
|
||||
|
||||
/* *
|
||||
@@ -389,7 +391,7 @@ ccl_device_inline bool ray_infinite_cylinder_intersect(const float3 P,
|
||||
* \param P: the vector pointing from the cone apex to the ray origin
|
||||
* \param D: the direction of the ray, does not need to have unit-length
|
||||
* \param cos_angle_sq: `sqr(cos(half_aperture_of_the_cone))`
|
||||
* \param t_range: the lower and upper bounds between which the ray lies inside the cone
|
||||
* \param t_range: the ray segment that lies inside the cone
|
||||
* \return whether the intersection exists and is in the provided range
|
||||
*
|
||||
* See https://www.geometrictools.com/Documentation/IntersectionLineCone.pdf for illustration
|
||||
@@ -398,7 +400,7 @@ ccl_device_inline bool ray_cone_intersect(const float3 axis,
|
||||
const float3 P,
|
||||
float3 D,
|
||||
const float cos_angle_sq,
|
||||
ccl_private float2 *t_range)
|
||||
ccl_private Interval<float> *t_range)
|
||||
{
|
||||
if (cos_angle_sq < 1e-4f) {
|
||||
/* The cone is nearly a plane. */
|
||||
@@ -433,7 +435,9 @@ ccl_device_inline bool ray_cone_intersect(const float3 axis,
|
||||
tmax = FLT_MAX;
|
||||
}
|
||||
|
||||
return valid && intervals_intersect(t_range, make_float2(tmin, tmax) * inv_len);
|
||||
*t_range = intervals_intersection(*t_range, {tmin * inv_len, tmax * inv_len});
|
||||
|
||||
return valid && !t_range->is_empty();
|
||||
}
|
||||
|
||||
CCL_NAMESPACE_END
|
||||
|
||||
Reference in New Issue
Block a user