struct Params { seed: u32, layers: u32, persistence: f32, } struct Vertex { @location(0) screen: vec2f, @location(1) world: vec3f, } struct Varying { @location(0) world: vec3f, @builtin(position) screen: vec4f, } @group(0) @binding(0) var params: Params; @vertex fn on_vertex(in: Vertex) -> Varying { return Varying(in.world, vec4(in.screen, 0.0, 1.0)); } @fragment fn on_fragment(in: Varying) -> @location(0) vec4f { return vec4(0.5 + 0.5 * noise(in.world)); } fn noise(coords: vec3f) -> f32 { let s = split(coords); var ret = 0.0; for (var i = 0u; i < 2; i++) { for (var j = 0u; j < 2; j++) { for (var k = 0u; k < 2; k++) { ret += part(params.seed, s, vec3u(i, j, k)); } } } return ret; } fn part(seed: u32, pos: Split, off: vec3u) -> f32 { let base_vec = base(seed, pos.int + off); let to_node = vec3f(off) - pos.frac; let base_val = dot(base_vec, to_node); let scale = smoothstep(vec3(0.0), vec3(1.0), 1.0 - abs(to_node)); return scale.x * scale.y * scale.z * base_val; } fn base(base_seed: u32, key: vec3u) -> vec3f { var seed = hash(hash(hash(hash(base_seed) ^ key.x) ^ key.y) ^ key.z); return rand_sphere(&seed); } struct Split { int: vec3u, frac: vec3f, } fn split(val: vec3f) -> Split { let int = floor(val); return Split(vec3u(vec3i(int)), val - int); } fn hash(key : u32) -> u32 { var v = key; v *= 0xb384af1bu; v ^= v >> 15u; return v; } fn rand(state: ptr) -> u32 { *state = hash(*state); return *state; } fn rand_float(state: ptr) -> f32 { return f32(rand(state)) / 0x1p32; } fn rand_sphere(state: ptr) -> vec3f { loop { let v = vec3f(rand_float(state), rand_float(state), rand_float(state)) - 0.5; let l = length(v); if (length(v) <= 0.5) { return v / l; } } return vec3f(0.0); // unreachable }