Particles ocean
A deep-water surface driven by a real inverse FFT. A Phillips spectrum evolves in frequency space, Stockham passes produce a displacement field, and half a million particles ride the waves through an HDR bloom chain.
import { PI, cmul, fullscreenPosition, wrapLoad } from "./ocean-common.wgsl";
struct IfftStageUniforms {
resolution: f32,
subtransformSize: f32,
horizontal: f32,
};
@group(0) @binding(0) var<uniform> u: IfftStageUniforms;
@group(0) @binding(1) var u_input: texture_2d<f32>;
struct VSOut { @builtin(position) pos: vec4f };
@vertex fn vs_main(@builtin(vertex_index) vi: u32) -> VSOut {
var out: VSOut;
out.pos = fullscreenPosition(vi);
return out;
}
@fragment fn fs_main(in: VSOut) -> @location(0) vec4f {
let N = i32(u.resolution);
let horizontal = u.horizontal > 0.5;
let index = select(in.pos.y - 0.5, in.pos.x - 0.5, horizontal);
let evenIndex = floor(index / u.subtransformSize) * (u.subtransformSize * 0.5)
+ (index % (u.subtransformSize * 0.5));
let evenCoord = select(
vec2i(i32(in.pos.x - 0.5), i32(evenIndex)),
vec2i(i32(evenIndex), i32(in.pos.y - 0.5)),
horizontal,
);
let oddCoord = select(
vec2i(i32(in.pos.x - 0.5), i32(evenIndex + u.resolution * 0.5)),
vec2i(i32(evenIndex + u.resolution * 0.5), i32(in.pos.y - 0.5)),
horizontal,
);
let even = wrapLoad(u_input, evenCoord, N);
let odd = wrapLoad(u_input, oddCoord, N);
let twiddleArg = 2.0 * PI * (index / u.subtransformSize);
let twiddle = vec2f(cos(twiddleArg), sin(twiddleArg));
let outA = even.xy + cmul(twiddle, odd.xy);
let outB = even.zw + cmul(twiddle, odd.zw);
return vec4f(outA, outB);
}