@ -76,35 +76,28 @@ float3x3 BuildViewAlignedOrthonormalBasis(in float3 normal, in float3 dirToView)
return float3x3(tangent, bitangent, normal);
}
// The following two edge integration functions are based on the work from:
// [HILL16] Real-Time Area Lighting: a Journey from Research to Production, SIGGRAPH 2016
// Ref: https://blog.selfshadow.com/publications/s2016-advances/
// Cosine integration of edge in a hemisphere. v1 and v2 should be normalized vertices above the
// xy plane in positive z space.
float IntegrateEdge(float3 v1, float3 v2)
{
// This alternate version may work better for platforms where acos() precision is low.
/*
float x = dot(v1, v2);
float y = abs(x);
float cosTheta = dot(v1, v2);
float absCosTheta = abs(cosTheta);
float a = 5.42031 + (3.12829 + 0.0902326 * y) * y;
float b = 3.45068 + (4.18814 + y) * y;
// Cubic rational fitting of x/sin(x)
float a = 5.42031 + (3.12829 + 0.0902326 * absCosTheta) * absCosTheta;
float b = 3.45068 + (4.18814 + absCosTheta) * absCosTheta;
float theta_sinTheta = a / b;
if (x < 0.0)
if (cosTheta < 0.0)
{
theta_sinTheta = PI * rsqrt(saturate(1.0 - x * x )) - theta_sinTheta;
theta_sinTheta = PI * rsqrt(clamp(1.0 - cosTheta * cosTheta, EPSILON, 1.0 )) - theta_sinTheta;
}
float3 u = cross(v1, v2);
return theta_sinTheta * u.z;
*/
float cosTheta = dot(v1, v2);
float theta = acos(cosTheta);
// calculate 1.0 / sin(theta)
float invSinTheta = rsqrt(saturate(1.0 - cosTheta * cosTheta));
return cross(v1, v2).z * ((theta > 0.001) ? theta * invSinTheta : 1.0);
return theta_sinTheta * cross(v1, v2).z;
}
// Cheaper version of above which is good enough for diffuse
@ -112,11 +105,14 @@ float IntegrateEdgeDiffuse(float3 v1, float3 v2)
{
float cosTheta = dot(v1, v2);
float absCosTheta = abs(cosTheta);
// Quadratic fitting of x/sin(x)
float theta_sinTheta = 1.5708 + (-0.879406 + 0.308609 * absCosTheta) * absCosTheta;
if (cosTheta < 0.0)
{
theta_sinTheta = PI * rsqrt(1.0 - cosTheta * cosTheta) - theta_sinTheta;
theta_sinTheta = PI * rsqrt(clamp( 1.0 - cosTheta * cosTheta, EPSILON, 1.0) ) - theta_sinTheta;
}
return theta_sinTheta * cross(v1, v2).z;
}
@ -447,7 +443,7 @@ void LtcQuadEvaluate(
// - Find the point along the edge that intersects the horizon.
// - Integrate from point 1 to the intersection point
// - Save the intersection point for later
// 3. The first point is blow the horizon, but the second point is above.
// 3. The first point is be low the horizon, but the second point is above.
// - Find the point along the edge that intersects the horizon.
// - Integate from the previous saved insection (see option 2 above) to this new insection
// - Integrate from the new insection to the second point.