157 lines
4.0 KiB
WebGPU Shading Language
157 lines
4.0 KiB
WebGPU Shading Language
struct Params {
|
|
seed: u32,
|
|
layers: u32,
|
|
roughness: f32,
|
|
scale: f32,
|
|
}
|
|
|
|
struct LookParams {
|
|
origin: vec3f,
|
|
radius: f32,
|
|
}
|
|
|
|
struct Vertex {
|
|
@location(0) screen: vec2f,
|
|
@location(1) dir: vec3f,
|
|
}
|
|
|
|
struct Varying {
|
|
@location(0) dir: vec3f,
|
|
@builtin(position) screen: vec4f,
|
|
}
|
|
|
|
@group(0) @binding(0) var<uniform> params: LookParams;
|
|
|
|
@vertex
|
|
fn on_vertex(in: Vertex) -> Varying {
|
|
return Varying(in.dir, vec4(in.screen, 0.0, 1.0));
|
|
}
|
|
|
|
@fragment
|
|
fn on_fragment(in: Varying) -> @location(0) vec4f {
|
|
let point = params.origin + params.radius * normalize(in.dir);
|
|
let sharp_area = perlin_noise(Params(1, 3, 0.9, 2.0), 0.1 * point);
|
|
let sharp_base = perlin_noise(Params(1, 6, 0.9, 2.0), 0.1 * point);
|
|
let cloud_base = perlin_noise(Params(2, 8, 0.6, 2.0), 0.1 * point);
|
|
let sharp_detail = structured_noise(Params(11, 8, 3.0, 2.0), point);
|
|
let cloud_detail1 = perlin_noise(Params(12, 8, 0.7, 2.0), point);
|
|
let cloud_detail2 = perlin_noise(Params(13, 8, 0.7, 2.0), point);
|
|
let dust = sharp_noise(Params(21, 8, 0.9, 2.0), point);
|
|
let stars = sharp_noise(Params(22, 8, 2.7, 2.0), point);
|
|
|
|
let cloud = exp(5.0 * (cloud_base - 1.0));
|
|
let cloud1 = cloud * (2.0 + cloud_detail1);
|
|
let cloud2 = cloud * (2.0 + cloud_detail2);
|
|
let tint = clamp(sharp_area - 0.2, 0.0, 0.3) / 0.3 * max(0.0, sharp_base - 0.3) * max(0.0, cloud_base + 0.3) * max(0.0, sharp_detail);
|
|
return vec4(
|
|
// dust * vec3(0.0, 0.3, 0.0) +
|
|
// max(0.0, sin(stars - 1.5) * vec3(0.3, 0.2, 0.1) +
|
|
// max(0.0, stars - 2.0) * vec3(0.3, 0.5, 2.0) +
|
|
cloud1 * vec3(0.1, 0.2, 1.0) +
|
|
cloud2 * vec3(0.1, 0.3, 0.7) +
|
|
tint * vec3(4.0, 0.0, 0.4) +
|
|
max(0.0, tint - 0.1) * vec3(0.0, 4.0, 0.0),
|
|
1.0);
|
|
}
|
|
|
|
fn sharp_noise(params: Params, point: vec3f) -> f32 {
|
|
var result = 1.0;
|
|
var hscale = 1.0;
|
|
var seed = params.seed;
|
|
for (var layer = 0u; layer < params.layers; layer++) {
|
|
result *= pow(4.0 * abs(perlin_layer(seed, hscale * point)), params.roughness);
|
|
hscale *= params.scale;
|
|
seed = hash(seed);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
fn structured_noise(params: Params, point: vec3f) -> f32 {
|
|
var result = 1.0;
|
|
var hscale = 1.0;
|
|
var seed = params.seed;
|
|
for (var layer = 0u; layer < params.layers; layer++) {
|
|
result *= pow(clamp(1. + perlin_layer(seed, hscale * point), 0., 1.), params.roughness);
|
|
hscale *= params.scale;
|
|
seed = hash(seed);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
fn perlin_noise(params: Params, point: vec3f) -> f32 {
|
|
var result = 0.0;
|
|
var hscale = 1.0;
|
|
var vscale = 1.0;
|
|
var seed = params.seed;
|
|
for (var layer = 0u; layer < params.layers; layer++) {
|
|
result += vscale * perlin_layer(seed, hscale * point);
|
|
hscale *= params.scale;
|
|
vscale *= params.roughness;
|
|
seed = hash(seed);
|
|
}
|
|
return result;
|
|
}
|
|
|
|
fn perlin_layer(seed: u32, 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(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 {
|
|
for (var k = 0; k < 16; k++) {
|
|
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); // safeguard
|
|
}
|