minitracing/src/bin/envmap/perlin.wgsl
2024-12-23 22:35:31 +03:00

91 lines
1.8 KiB
WebGPU Shading Language

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<uniform> 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<function, u32>) -> u32 {
*state = hash(*state);
return *state;
}
fn rand_float(state: ptr<function, u32>) -> f32 {
return f32(rand(state)) / 0x1p32;
}
fn rand_sphere(state: ptr<function, u32>) -> 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
}