diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/effects/shaders.cc | 1 | ||||
| -rw-r--r-- | src/shaders/math/normal.wgsl | 34 |
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)); +} |
