cyborg/shaders/oct_encoding.wgsl

53 lines
1.5 KiB
WebGPU Shading Language

struct TangentFrame {
normal: vec3<f32>,
tangent: vec3<f32>
};
// https://knarkowicz.wordpress.com/2014/04/16/octahedron-normal-vector-encoding/?like_comment=12
fn oct_norm_wrap(v: vec2<f32>) -> vec2<f32> {
return (1.0 - abs(v.yx)) * select(vec2<f32>(-1.0), vec2<f32>(1.0), v.xy >= vec2<f32>(0.0));
}
fn oct_norm_encode(n: vec3<f32>) -> vec2<f32> {
let ml = (abs(n.x) + abs(n.y) + abs(n.z)); // ml = manhattan length
let n = n / ml;
let v = select(oct_norm_wrap(n.xy), n.xy, n.z >= 0.0);
return fma(v, vec2<f32>(0.5), vec2<f32>(0.5));
}
fn oct_norm_decode(f: vec2<f32>) -> vec3<f32> {
let f = fma(f, vec2<f32>(2.0), vec2<f32>(-1.0));
let n = vec3<f32>(f.xy, 1.0 - abs(f.x) - abs(f.y));
let t = vec2<f32>(clamp(-n.z, 0.0, 1.0));
let nxy = n.xy + select(t, -t, n.xy >= vec2<f32>(0.0));
return normalize(vec3<f32>(nxy, n.z));
}
fn tan_frame_encode(tf: TangentFrame) -> u32 {
return u32(0); // TODO
}
fn tan_frame_decode(i: u32) -> TangentFrame {
let n = i & u32(0xffff);
let nx = n >> u32(8);
let ny = n & u32(0xff);
let n = vec2<f32>(f32(nx), f32(ny)) / 255.0;
let t = i >> u32(16);
let tx = t >> u32(8);
let ty = t & u32(0xff);
let t = vec2<f32>(f32(tx), f32(ty)) / 255.0;
var tf: TangentFrame;
tf.normal = oct_norm_decode(n);
tf.tangent = oct_norm_decode(n);
return tf;
}
fn tan_frame_transform(i: u32, transform: mat4x4<f32>) -> u32 {
var tf = tan_frame_decode(i);
tf.normal = (transform * vec4<f32>(tf.normal, 0.0)).xyz;
tf.tangent = (transform * vec4<f32>(tf.tangent, 0.0)).xyz;
return tan_frame_encode(tf);
}