Skip to content

Commit 59e090e

Browse files
record my discoveries
1 parent b609179 commit 59e090e

File tree

1 file changed

+15
-2
lines changed

1 file changed

+15
-2
lines changed

include/nbl/builtin/hlsl/shapes/spherical_triangle.hlsl

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ struct SphericalTriangle
4848
if (pyramidAngles())
4949
return 0.f;
5050

51-
// Both vertices and angles at the vertices are denoted by the same upper case letters A, B, and C. The angles A, B, C of the triangle are equal to the angles between the planes that intersect the surface of the sphere or, equivalently, the angles between the tangent vectors of the great circle arcs where they meet at the vertices. Angles are in radians. The angles of proper spherical triangles are (by convention) less than PI
51+
// Both vertices and angles at the vertices are denoted by the same upper case letters A, B, and C. The angles A, B, C of the triangle are equal to the angles between the planes that intersect the surface of the sphere or,
52+
// equivalently, the angles between the tangent vectors of the great circle arcs where they meet at the vertices. Angles are in radians. The angles of proper spherical triangles are (by convention) less than PI
5253
cos_vertices = hlsl::clamp((cos_sides - cos_sides.yzx * cos_sides.zxy) * csc_sides.yzx * csc_sides.zxy, hlsl::promote<vector3_type>(-1.0), hlsl::promote<vector3_type>(1.0)); // using Spherical Law of Cosines (TODO: do we need to clamp anymore? since the pyramid angles method introduction?)
5354
sin_vertices = hlsl::sqrt(hlsl::promote<vector3_type>(1.0) - cos_vertices * cos_vertices);
5455

@@ -75,10 +76,22 @@ struct SphericalTriangle
7576
awayFromEdgePlane[0] = hlsl::cross(vertices[1], vertices[2]) * csc_sides[0];
7677
awayFromEdgePlane[1] = hlsl::cross(vertices[2], vertices[0]) * csc_sides[1];
7778
awayFromEdgePlane[2] = hlsl::cross(vertices[0], vertices[1]) * csc_sides[2];
79+
// The ABS makes it so that the computation is correct for an `abs(cos(theta))` factor which is the projected solid angle used for a BSDF
80+
// Proof: Kelvin-Stokes theorem, if you split the set into two along the horizon with constant CCW winding, the `cross` along the shared edge goes in different directions and cancels out,
81+
// while `acos` of the clipped great arcs corresponding to polygon edges add up to the original sides again
7882
const vector3_type externalProducts = hlsl::abs(hlsl::mul(/* transposed already */awayFromEdgePlane, receiverNormal));
7983

84+
// Far TODO: `cross(A,B)*acos(dot(A,B))/sin(1-dot^2)` can be done with `cross*acos_csc_approx(dot(A,B))`
85+
// We could skip the `csc_sides` factor, and computing `pyramidAngles` and replace them with this approximation weighting before the dot product with the receiver notmal
86+
// The curve fit "revealed in a dream" to me is `exp2(F(log2(x+1)))` where `F(u)` is a polynomial, so far I've calculated `F = (1-u)0.635+(1-u^2)0.0118` which gives <5% error until 165 degrees
87+
// I have a feeling that a polynomial of ((Au+B)u+C)u+D could be sufficient if it has following properties:
88+
// `F(0) = 0` and
89+
// `F(u) <= log2(\frac{\cos^{-1}\left(2^{x}-1\right)}{\sqrt{1-\left(2^{x}-1\right)^{2}}})` because you want to consistently under-estimate the Projected Solid Angle to avoid creating energy
90+
// See https://www.desmos.com/calculator/sdptomhbju
91+
// Furthermore we could clip the polynomial calc to `Cu+D or `(Bu+C)u+D` for small arguments
8092
const vector3_type pyramidAngles = hlsl::acos<vector3_type>(cos_sides);
81-
return hlsl::dot(pyramidAngles, externalProducts) / (2.f * numbers::pi<scalar_type>);
93+
// So that riangle covering almost whole hemisphere sums to PI
94+
return hlsl::dot(pyramidAngles, externalProducts) * scalar_type(0.5);
8295
}
8396

8497
vector3_type vertices[3];

0 commit comments

Comments
 (0)