summaryrefslogtreecommitdiffstats
path: root/vertex_deformation.slang
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2026-01-12 20:55:18 -0800
committeryum <yum.food.vr@gmail.com>2026-01-12 20:55:18 -0800
commitbd4d3aa6537cb3121cd1eca4a8ea4eb65eb28522 (patch)
tree021f4296a91ba890a45b7d9cd920bf473c7bb216 /vertex_deformation.slang
parent6d86c9663bab3ec1ef95ba455dfa7281415b7f44 (diff)
Fold: update UI, add plane -> hemioctahedron
Diffstat (limited to 'vertex_deformation.slang')
-rw-r--r--vertex_deformation.slang71
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