summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-03-22 20:10:53 +0100
committerskal <pascal.massimino@gmail.com>2026-03-22 20:10:53 +0100
commitaa5c8e6730b03ea901ead59bc7cb1c31dac62012 (patch)
tree989378b4eeeaa568e437b9f5cc0b7c5a96e23e79 /src
parent9bf9b0aa0573f77bd667e6976a8bb413153daa1d (diff)
refactor(shaders): extract oct-normal encode/decode into math/normal snippet
New src/shaders/math/normal.wgsl: oct_encode, oct_decode, oct_encode_unorm, oct_decode_unorm. Registered in InitShaderComposer as "math/normal". Removed inline copies from gbuf_raster.wgsl and gbuf_pack.wgsl. 18/18 tests passing.
Diffstat (limited to 'src')
-rw-r--r--src/effects/shaders.cc1
-rw-r--r--src/shaders/math/normal.wgsl34
2 files changed, 35 insertions, 0 deletions
diff --git a/src/effects/shaders.cc b/src/effects/shaders.cc
index 7a68e5f..a6c1b64 100644
--- a/src/effects/shaders.cc
+++ b/src/effects/shaders.cc
@@ -35,6 +35,7 @@ void InitShaderComposer() {
register_if_exists("math/common_utils",
AssetId::ASSET_SHADER_MATH_COMMON_UTILS);
register_if_exists("math/noise", AssetId::ASSET_SHADER_MATH_NOISE);
+ register_if_exists("math/normal", AssetId::ASSET_SHADER_MATH_NORMAL);
register_if_exists("render/shadows", AssetId::ASSET_SHADER_RENDER_SHADOWS);
register_if_exists("render/scene_query_bvh",
AssetId::ASSET_SHADER_RENDER_SCENE_QUERY_BVH);
diff --git a/src/shaders/math/normal.wgsl b/src/shaders/math/normal.wgsl
new file mode 100644
index 0000000..5a9a1a9
--- /dev/null
+++ b/src/shaders/math/normal.wgsl
@@ -0,0 +1,34 @@
+// Normal encoding/decoding utilities.
+// Octahedral encoding: losslessly maps unit normals ↔ vec2f in [-1,1]².
+// Storage convention: remap to [0,1] before writing to u8/f16 textures.
+
+// Encode a unit normal to octahedral XY in [-1, 1].
+fn oct_encode(n: vec3f) -> vec2f {
+ let inv_l1 = 1.0 / (abs(n.x) + abs(n.y) + abs(n.z));
+ var p = n.xy * inv_l1;
+ if (n.z < 0.0) {
+ let s = vec2f(select(-1.0, 1.0, p.x >= 0.0),
+ select(-1.0, 1.0, p.y >= 0.0));
+ p = (1.0 - abs(p.yx)) * s;
+ }
+ return p; // [-1, 1]
+}
+
+// Decode octahedral XY in [-1, 1] back to a unit normal.
+fn oct_decode(f: vec2f) -> vec3f {
+ var n = vec3f(f.x, f.y, 1.0 - abs(f.x) - abs(f.y));
+ let t = max(-n.z, 0.0);
+ n.x += select(t, -t, n.x >= 0.0);
+ n.y += select(t, -t, n.y >= 0.0);
+ return normalize(n);
+}
+
+// Convenience: encode + remap to [0, 1] for texture storage.
+fn oct_encode_unorm(n: vec3f) -> vec2f {
+ return oct_encode(n) * 0.5 + vec2f(0.5);
+}
+
+// Convenience: undo [0, 1] remap then decode.
+fn oct_decode_unorm(rg: vec2f) -> vec3f {
+ return oct_decode(rg * 2.0 - vec2f(1.0));
+}