diff options
Diffstat (limited to 'vertex_deformation.slang')
| -rw-r--r-- | vertex_deformation.slang | 71 |
1 files changed, 69 insertions, 2 deletions
diff --git a/vertex_deformation.slang b/vertex_deformation.slang index ed514fc..50c252e 100644 --- a/vertex_deformation.slang +++ b/vertex_deformation.slang @@ -3,6 +3,8 @@ #define PI 3.14159265f #define PI_RCP 0.31830988f +#define SQRT_2 1.41421356f +#define RCP_SQRT_2 0.70710678f #define TAU (2.0f * PI) #define HALF_PI (0.5f * PI) #define RCP_PI (1.0f / PI) @@ -11,8 +13,10 @@ #define glsl_mod(x,y) (((x)-(y)*floor((x)/(y)))) // Differentiable versions of common operators. -#define dabs(x) sqrt((x) * (x) + 1e-6) -#define dlerp(x, y, t) ((x) * (1-t) + (y) * t) +#define dabs(x) sqrt((x) * (x) + 1e-6f) +#define dmin(a, b) (0.5f * ((a) + (b) - dabs((a) - (b)))) +#define dmax(a, b) (0.5f * ((a) + (b) + dabs((a) - (b)))) +#define dlerp(x, y, t) ((x) * (1.0f-t) + (y) * t) // This was derived using fourier analysis. See Scripts/approximate.py. #define dfrac(x) \ 4.997559e-01 - \ @@ -558,4 +562,67 @@ public void fbm_undeform_normal(float3 xyz, float t, tangent = mul(inv_jac, tangent); } +// Maps a plane to a hemi-octahedron (half octahedron). +// Uses octahedral parameterization consistent with pbrt's OctahedralVector. +// Input: plane on [-1,1]² in the (r, rxs) plane +// Output: unit hemisphere with pole at +s direction +[Differentiable] +public float3 plane_to_hemi_octahedron(float3 xyz, + no_diff float3 p, no_diff float3 r_cart, no_diff float3 s_cart, + no_diff float t) { + // Convert from cartesian to (r, s, r x s) space. + r_cart = normalize(r_cart); + s_cart = normalize(s_cart); + float3 rxs_cart = cross(s_cart, r_cart); + float3x3 to_rsrxs = float3x3(r_cart, s_cart, rxs_cart); + float3x3 to_cart = transpose(to_rsrxs); + + // Translate origin to `p` then change into (r, s, r x s) basis. + xyz = mul(to_rsrxs, xyz - p); + + float3 xyz0 = xyz; + + // Extract planar coordinates: x and z form the 2D plane + float x = xyz.x; + float z = xyz.z; + + // Rotate 45° and scale to fit square into diamond + float x_rot = (x + z) * 0.5; + float z_rot = (z - x) * 0.5; + + // Octahedral decode: y = 1 - |x| - |z|, clamped to hemisphere + // Use differentiable abs and max for smooth autodiff + float y = dmax(0.0f, 1.0f - dabs(x_rot) - dabs(z_rot)); + + // Normalize to unit sphere (differentiable safe normalize) + float3 oct_pos = float3(x_rot, y, z_rot); + float len = dot(oct_pos, oct_pos); + oct_pos = oct_pos / sqrt(len); + + // Rotate back by -45° around y to undo input rotation + float x_unrot = (oct_pos.x - oct_pos.z) * RCP_SQRT_2; + float z_unrot = (oct_pos.x + oct_pos.z) * RCP_SQRT_2; + oct_pos = float3(x_unrot, oct_pos.y, z_unrot); + + // Interpolate between original position and sphere position + float3 result = dlerp(xyz0, oct_pos, dmin(t, 1.0f)); + + // Map back to cartesian basis + xyz = mul(to_cart, result) + p; + + return xyz; +} + +public void plane_to_hemi_octahedron_normal(inout float3 xyz, inout float3 normal, + inout float3 tangent, float3 p, float3 r, float3 s, float t) { + R3R3_NORMALS(xyz, normal, tangent, plane_to_hemi_octahedron, p, r, s, t); +} + +public void plane_to_hemi_octahedron_undeform_normal(float3 xyz, inout float3 normal, + inout float3 tangent, float3 p, float3 r, float3 s, float t) { + R3R3_DECLARE_BASIS_VECTORS(xyz); + R3R3_AUTODIFF_BASIS_VECTORS(plane_to_hemi_octahedron, p, r, s, t); + R3R3_UNDEFORM_NORMAL_AND_TANGENT(normal, tangent); +} + #endif // __CUSTOM31_INC |
