Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: port water example #3

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions deps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ export * as gmath from "https://deno.land/x/[email protected]/mod.ts";
export * as png from "https://deno.land/x/[email protected]/mod.ts";
export * as obj from "https://crux.land/[email protected]";
export { Dds } from "https://crux.land/[email protected]";
export { slidingWindows } from "https://deno.land/[email protected]/collections/mod.ts";
export { makeNoise2D } from "https://deno.land/x/[email protected]/mod.ts";
Binary file added water/deno_trace/data1.bin
Binary file not shown.
Binary file added water/deno_trace/data2.bin
Binary file not shown.
Binary file added water/deno_trace/data3.bin
Binary file not shown.
Binary file added water/deno_trace/data4.bin
Binary file not shown.
Binary file added water/deno_trace/data5.bin
Binary file not shown.
48 changes: 48 additions & 0 deletions water/deno_trace/data6.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
struct Uniforms {
projection_view: mat4x4<f32>;
clipping_plane: vec4<f32>;
};

[[group(0), binding(0)]]
var<uniform> uniforms: Uniforms;

let light: vec3<f32> = vec3<f32>(150.0, 70.0, 0.0);
let light_colour: vec3<f32> = vec3<f32>(1.0, 0.98, 0.82);
let ambient: f32 = 0.2;

struct VertexOutput {
[[builtin(position)]] position: vec4<f32>;
[[location(0)]] colour: vec4<f32>;
// Comment this out if using user-clipping planes:
[[location(1)]] clip_dist: f32;
};

[[stage(vertex)]]
fn vs_main(
[[location(0)]] position: vec3<f32>,
[[location(1)]] normal: vec3<f32>,
[[location(2)]] colour: vec4<f32>,
) -> VertexOutput {
var out: VertexOutput;
out.position = uniforms.projection_view * vec4<f32>(position, 1.0);

// https://www.desmos.com/calculator/nqgyaf8uvo
let normalized_light_direction = normalize(position - light);
let brightness_diffuse = clamp(dot(normalized_light_direction, normal), 0.2, 1.0);

out.colour = vec4<f32>(max((brightness_diffuse + ambient) * light_colour * colour.rgb, vec3<f32>(0.0, 0.0, 0.0)), colour.a);
out.clip_dist = dot(vec4<f32>(position, 1.0), uniforms.clipping_plane);
return out;
}

[[stage(fragment), early_depth_test]]
fn fs_main(
in: VertexOutput,
) -> [[location(0)]] vec4<f32> {
// Comment this out if using user-clipping planes:
if(in.clip_dist < 0.0) {
discard;
}

return vec4<f32>(in.colour.xyz, 1.0);
}
251 changes: 251 additions & 0 deletions water/deno_trace/data7.wgsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
struct Uniforms {
view: mat4x4<f32>;
projection: mat4x4<f32>;
time_size_width: vec4<f32>;
viewport_height: f32;
};
[[group(0), binding(0)]] var<uniform> uniforms: Uniforms;

let light_point: vec3<f32> = vec3<f32>(150.0, 70.0, 0.0);
let light_colour: vec3<f32> = vec3<f32>(1.0, 0.98, 0.82);
let one: vec4<f32> = vec4<f32>(1.0, 1.0, 1.0, 1.0);

let Y_SCL: f32 = 0.86602540378443864676372317075294;
let CURVE_BIAS: f32 = -0.1;
let INV_1_CURVE_BIAS: f32 = 1.11111111111; //1.0 / (1.0 + CURVE_BIAS);

//
// The following code to calculate simplex 3D
// is from https://github.com/ashima/webgl-noise
//
// Simplex 3D Noise
// by Ian McEwan, Ashima Arts.
//
fn permute(x: vec4<f32>) -> vec4<f32> {
var temp: vec4<f32> = 289.0 * one;
return modf(((x*34.0) + one) * x, &temp);
}

fn taylorInvSqrt(r: vec4<f32>) -> vec4<f32> {
return 1.79284291400159 * one - 0.85373472095314 * r;
}

fn snoise(v: vec3<f32>) -> f32 {
let C = vec2<f32>(1.0/6.0, 1.0/3.0);
let D = vec4<f32>(0.0, 0.5, 1.0, 2.0);

// First corner
//TODO: use the splat operations when available
let vCy = dot(v, C.yyy);
var i: vec3<f32> = floor(v + vec3<f32>(vCy, vCy, vCy));
let iCx = dot(i, C.xxx);
let x0 = v - i + vec3<f32>(iCx, iCx, iCx);

// Other corners
let g = step(x0.yzx, x0.xyz);
let l = (vec3<f32>(1.0, 1.0, 1.0) - g).zxy;
let i1 = min(g, l);
let i2 = max(g, l);

// x0 = x0 - 0.0 + 0.0 * C.xxx;
// x1 = x0 - i1 + 1.0 * C.xxx;
// x2 = x0 - i2 + 2.0 * C.xxx;
// x3 = x0 - 1.0 + 3.0 * C.xxx;
let x1 = x0 - i1 + C.xxx;
let x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
let x3 = x0 - D.yyy; // -1.0+3.0*C.x = -0.5 = -D.y

// Permutations
var temp: vec3<f32> = 289.0 * one.xyz;
i = modf(i, &temp);
let p = permute(
permute(
permute(i.zzzz + vec4<f32>(0.0, i1.z, i2.z, 1.0))
+ i.yyyy + vec4<f32>(0.0, i1.y, i2.y, 1.0))
+ i.xxxx + vec4<f32>(0.0, i1.x, i2.x, 1.0));

// Gradients: 7x7 points over a square, mapped onto an octahedron.
// The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
let n_ = 0.142857142857;// 1.0/7.0
let ns = n_ * D.wyz - D.xzx;

let j = p - 49.0 * floor(p * ns.z * ns.z);// mod(p,7*7)

let x_ = floor(j * ns.z);
let y_ = floor(j - 7.0 * x_);// mod(j,N)

var x: vec4<f32> = x_ *ns.x + ns.yyyy;
var y: vec4<f32> = y_ *ns.x + ns.yyyy;
let h = one - abs(x) - abs(y);

let b0 = vec4<f32>(x.xy, y.xy);
let b1 = vec4<f32>(x.zw, y.zw);

//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - one;
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - one;
let s0 = floor(b0)*2.0 + one;
let s1 = floor(b1)*2.0 + one;
let sh = -step(h, 0.0 * one);

let a0 = b0.xzyw + s0.xzyw*sh.xxyy;
let a1 = b1.xzyw + s1.xzyw*sh.zzww;

var p0: vec3<f32> = vec3<f32>(a0.xy, h.x);
var p1: vec3<f32> = vec3<f32>(a0.zw, h.y);
var p2: vec3<f32> = vec3<f32>(a1.xy, h.z);
var p3: vec3<f32> = vec3<f32>(a1.zw, h.w);

//Normalise gradients
let norm = taylorInvSqrt(vec4<f32>(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));
p0 = p0 * norm.x;
p1 = p1 * norm.y;
p2 = p2 * norm.z;
p3 = p3 * norm.w;

// Mix final noise value
var m: vec4<f32> = max(0.6 * one - vec4<f32>(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0 * one);
m = m * m;
return 9.0 * dot(m*m, vec4<f32>(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3)));
}

// End of 3D simplex code.

fn apply_distortion(pos: vec3<f32>) -> vec3<f32> {
var perlin_pos: vec3<f32> = pos;

//Do noise transformation to permit for smooth,
//continuous movement.

//TODO: we should be able to name them `sin` and `cos`.
let sn = uniforms.time_size_width.x;
let cs = uniforms.time_size_width.y;
let size = uniforms.time_size_width.z;

// Rotate 90 Z, Move Left Size / 2
perlin_pos = vec3<f32>(perlin_pos.y - perlin_pos.x - size, perlin_pos.x, perlin_pos.z);

let xcos = perlin_pos.x * cs;
let xsin = perlin_pos.x * sn;
let ycos = perlin_pos.y * cs;
let ysin = perlin_pos.y * sn;
let zcos = perlin_pos.z * cs;
let zsin = perlin_pos.z * sn;

// Rotate Time Y
let perlin_pos_y = vec3<f32>(xcos + zsin, perlin_pos.y, -xsin + xcos);

// Rotate Time Z
let perlin_pos_z = vec3<f32>(xcos - ysin, xsin + ycos, perlin_pos.x);

// Rotate 90 Y
perlin_pos = vec3<f32>(perlin_pos.z - perlin_pos.x, perlin_pos.y, perlin_pos.x);

// Rotate Time X
let perlin_pos_x = vec3<f32>(perlin_pos.x, ycos - zsin, ysin + zcos);

// Sample at different places for x/y/z to get random-looking water.
return vec3<f32>(
//TODO: use splats
pos.x + snoise(perlin_pos_x + 2.0*one.xxx) * 0.4,
pos.y + snoise(perlin_pos_y - 2.0*one.xxx) * 1.8,
pos.z + snoise(perlin_pos_z) * 0.4
);
}

// Multiply the input by the scale values.
fn make_position(original: vec2<f32>) -> vec4<f32> {
let interpreted = vec3<f32>(original.x * 0.5, 0.0, original.y * Y_SCL);
return vec4<f32>(apply_distortion(interpreted), 1.0);
}

// Create the normal, and apply the curve. Change the Curve Bias above.
fn make_normal(a: vec3<f32>, b: vec3<f32>, c: vec3<f32>) -> vec3<f32> {
let norm = normalize(cross(b - c, a - c));
let center = (a + b + c) * (1.0 / 3.0); //TODO: use splat
return (normalize(a - center) * CURVE_BIAS + norm) * INV_1_CURVE_BIAS;
}

// Calculate the fresnel effect.
fn calc_fresnel(view: vec3<f32>, normal: vec3<f32>) -> f32 {
var refractive: f32 = abs(dot(view, normal));
refractive = pow(refractive, 1.33333333333);
return refractive;
}

// Calculate the specular lighting.
fn calc_specular(eye: vec3<f32>, normal: vec3<f32>, light: vec3<f32>) -> f32 {
let light_reflected = reflect(light, normal);
var specular: f32 = max(dot(eye, light_reflected), 0.0);
specular = pow(specular, 10.0);
return specular;
}

struct VertexOutput {
[[builtin(position)]] position: vec4<f32>;
[[location(0)]] f_WaterScreenPos: vec2<f32>;
[[location(1)]] f_Fresnel: f32;
[[location(2)]] f_Light: vec3<f32>;
};

[[stage(vertex)]]
fn vs_main(
[[location(0)]] position: vec2<i32>,
[[location(1)]] offsets: vec4<i32>,
) -> VertexOutput {
let p_pos = vec2<f32>(position);
let b_pos = make_position(p_pos + vec2<f32>(offsets.xy));
let c_pos = make_position(p_pos + vec2<f32>(offsets.zw));
let a_pos = make_position(p_pos);
let original_pos = vec4<f32>(p_pos.x * 0.5, 0.0, p_pos.y * Y_SCL, 1.0);

let vm = uniforms.view;
let transformed_pos = vm * a_pos;
//TODO: use vector splats for division
let water_pos = transformed_pos.xyz * (1.0 / transformed_pos.w);
let normal = make_normal((vm * a_pos).xyz, (vm * b_pos).xyz, (vm * c_pos).xyz);
let eye = normalize(-water_pos);
let transformed_light = vm * vec4<f32>(light_point, 1.0);

var out: VertexOutput;
out.f_Light = light_colour * calc_specular(eye, normal, normalize(water_pos.xyz - (transformed_light.xyz * (1.0 / transformed_light.w))));
out.f_Fresnel = calc_fresnel(eye, normal);

let gridpos = uniforms.projection * vm * original_pos;
out.f_WaterScreenPos = (0.5 * gridpos.xy * (1.0 / gridpos.w)) + vec2<f32>(0.5, 0.5);

out.position = uniforms.projection * transformed_pos;
return out;
}


let water_colour: vec3<f32> = vec3<f32>(0.0, 0.46, 0.95);
let zNear: f32 = 10.0;
let zFar: f32 = 400.0;

[[group(0), binding(1)]] var reflection: texture_2d<f32>;
[[group(0), binding(2)]] var terrain_depth_tex: texture_2d<f32>;
[[group(0), binding(3)]] var colour_sampler: sampler;

fn to_linear_depth(depth: f32) -> f32 {
let z_n: f32 = 2.0 * depth - 1.0;
let z_e: f32 = 2.0 * zNear * zFar / (zFar + zNear - z_n * (zFar - zNear));
return z_e;
}

[[stage(fragment)]]
fn fs_main(in: VertexOutput) -> [[location(0)]] vec4<f32> {
let reflection_colour = textureSample(reflection, colour_sampler, in.f_WaterScreenPos.xy).xyz;

let pixel_depth = to_linear_depth(in.position.z);
let normalized_coords = in.position.xy / vec2<f32>(uniforms.time_size_width.w, uniforms.viewport_height);
let terrain_depth = to_linear_depth(textureSample(terrain_depth_tex, colour_sampler, normalized_coords).r);

let dist = terrain_depth - pixel_depth;
let clamped = pow(smoothStep(0.0, 1.5, dist), 4.8);

let final_colour = in.f_Light + reflection_colour;
let t = smoothStep(1.0, 5.0, dist) * 0.2; //TODO: splat for mix()?
let depth_colour = mix(final_colour, water_colour, vec3<f32>(t, t, t));

return vec4<f32>(depth_colour, clamped * (1.0 - in.f_Fresnel));
}
Binary file added water/deno_trace/data8.bin
Binary file not shown.
Loading