summaryrefslogtreecommitdiff
path: root/src/shaders/math/normal.wgsl
blob: 5a9a1a95e412ebe2f0ea2354ff3ddb8cc1e01a2d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
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));
}