mirror of
https://github.com/gfx-rs/wgpu.git
synced 2026-04-22 03:02:01 -04:00
[rs] Merge #763
763: Port the water example shaders to WGSL r=cwfitzgerald a=kvark Co-authored-by: Dzmitry Malyshau <kvarkus@gmail.com>
This commit is contained in:
@@ -28,20 +28,20 @@ cross = ["wgc/cross"]
|
||||
[target.'cfg(not(target_arch = "wasm32"))'.dependencies.wgc]
|
||||
package = "wgpu-core"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "b7ba481a9170e5b9c6364b2eb16080e527462039"
|
||||
rev = "41f106d7fc8e2ca49b21aed0919fa6cc67317f7f"
|
||||
features = ["raw-window-handle"]
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies.wgc]
|
||||
package = "wgpu-core"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "b7ba481a9170e5b9c6364b2eb16080e527462039"
|
||||
rev = "41f106d7fc8e2ca49b21aed0919fa6cc67317f7f"
|
||||
features = ["raw-window-handle"]
|
||||
optional = true
|
||||
|
||||
[dependencies.wgt]
|
||||
package = "wgpu-types"
|
||||
git = "https://github.com/gfx-rs/wgpu"
|
||||
rev = "b7ba481a9170e5b9c6364b2eb16080e527462039"
|
||||
rev = "41f106d7fc8e2ca49b21aed0919fa6cc67317f7f"
|
||||
|
||||
[dependencies]
|
||||
arrayvec = "0.5"
|
||||
@@ -70,13 +70,13 @@ env_logger = "0.8"
|
||||
# used to test all the example shaders
|
||||
[dev-dependencies.naga]
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
tag = "gfx-18"
|
||||
tag = "gfx-19"
|
||||
features = ["wgsl-in"]
|
||||
|
||||
# used to generate SPIR-V for the Web target
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies.naga]
|
||||
git = "https://github.com/gfx-rs/naga"
|
||||
tag = "gfx-18"
|
||||
tag = "gfx-19"
|
||||
features = ["wgsl-in", "spv-out"]
|
||||
|
||||
[[example]]
|
||||
|
||||
@@ -12,7 +12,7 @@ All framework-based examples render to the window.
|
||||
## Feature matrix
|
||||
| Feature | boids | cube | mipmap | msaa-line | shadow | skybox | texture-arrays | water | conservative-raster |
|
||||
| ---------------------------- | ------ | ------ | ------ | --------- | ------ | ------ | -------------- | ------ | ------------------- |
|
||||
| WGSL shaders | :star: | :star: | :star: | :star: | :star: | :star: | | | :star: |
|
||||
| WGSL shaders | :star: | :star: | :star: | :star: | :star: | :star: | | :star: | :star: |
|
||||
| vertex attributes | :star: | :star: | | :star: | :star: | :star: | :star: | :star: | |
|
||||
| instancing | :star: | | | | | | | | |
|
||||
| lines and points | | | | :star: | | | | | :star: |
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
// This should match `NUM_PARTICLES` on the Rust side.
|
||||
const NUM_PARTICLES: u32 = 1500u;
|
||||
|
||||
[[block]]
|
||||
struct Particle {
|
||||
pos : vec2<f32>;
|
||||
vel : vec2<f32>;
|
||||
|
||||
@@ -43,7 +43,6 @@ fn vs_main(
|
||||
|
||||
// fragment shader
|
||||
|
||||
[[block]]
|
||||
struct Light {
|
||||
proj: mat4x4<f32>;
|
||||
pos: vec4<f32>;
|
||||
|
||||
@@ -5,7 +5,7 @@ mod point_gen;
|
||||
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use cgmath::Point3;
|
||||
use std::{iter, mem};
|
||||
use std::{borrow::Cow, iter, mem};
|
||||
use wgpu::util::DeviceExt;
|
||||
|
||||
///
|
||||
@@ -263,7 +263,7 @@ impl Example {
|
||||
impl framework::Example for Example {
|
||||
fn init(
|
||||
sc_desc: &wgpu::SwapChainDescriptor,
|
||||
_adapter: &wgpu::Adapter,
|
||||
adapter: &wgpu::Adapter,
|
||||
device: &wgpu::Device,
|
||||
queue: &wgpu::Queue,
|
||||
) -> Self {
|
||||
@@ -486,14 +486,23 @@ impl framework::Example for Example {
|
||||
});
|
||||
|
||||
// Upload/compile them to GPU code.
|
||||
let water_vs_module =
|
||||
device.create_shader_module(&wgpu::include_spirv!("water_shader.vert.spv"));
|
||||
let water_fs_module =
|
||||
device.create_shader_module(&wgpu::include_spirv!("water_shader.frag.spv"));
|
||||
let terrain_vs_module =
|
||||
device.create_shader_module(&wgpu::include_spirv!("terrain_shader.vert.spv"));
|
||||
let terrain_fs_module =
|
||||
device.create_shader_module(&wgpu::include_spirv!("terrain_shader.frag.spv"));
|
||||
let mut flags = wgpu::ShaderFlags::VALIDATION;
|
||||
match adapter.get_info().backend {
|
||||
wgpu::Backend::Metal | wgpu::Backend::Vulkan => {
|
||||
flags |= wgpu::ShaderFlags::EXPERIMENTAL_TRANSLATION
|
||||
}
|
||||
_ => (), //TODO
|
||||
}
|
||||
let terrain_module = device.create_shader_module(&wgpu::ShaderModuleDescriptor {
|
||||
label: Some("terrain"),
|
||||
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("terrain.wgsl"))),
|
||||
flags,
|
||||
});
|
||||
let water_module = device.create_shader_module(&wgpu::ShaderModuleDescriptor {
|
||||
label: Some("water"),
|
||||
source: wgpu::ShaderSource::Wgsl(Cow::Borrowed(include_str!("water.wgsl"))),
|
||||
flags,
|
||||
});
|
||||
|
||||
// Create the render pipelines. These describe how the data will flow through the GPU, and what
|
||||
// constraints and modifiers it will have.
|
||||
@@ -503,8 +512,8 @@ impl framework::Example for Example {
|
||||
layout: Some(&water_pipeline_layout),
|
||||
// Vertex shader and input buffers
|
||||
vertex: wgpu::VertexState {
|
||||
module: &water_vs_module,
|
||||
entry_point: "main",
|
||||
module: &water_module,
|
||||
entry_point: "vs_main",
|
||||
// Layout of our vertices. This should match the structs
|
||||
// which are uploaded to the GPU. This should also be
|
||||
// ensured by tagging on either a `#[repr(C)]` onto a
|
||||
@@ -518,8 +527,8 @@ impl framework::Example for Example {
|
||||
},
|
||||
// Fragment shader and output targets
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &water_fs_module,
|
||||
entry_point: "main",
|
||||
module: &water_module,
|
||||
entry_point: "fs_main",
|
||||
// Describes how the colour will be interpolated
|
||||
// and assigned to the output attachment.
|
||||
targets: &[wgpu::ColorTargetState {
|
||||
@@ -572,8 +581,8 @@ impl framework::Example for Example {
|
||||
label: Some("terrain"),
|
||||
layout: Some(&terrain_pipeline_layout),
|
||||
vertex: wgpu::VertexState {
|
||||
module: &terrain_vs_module,
|
||||
entry_point: "main",
|
||||
module: &terrain_module,
|
||||
entry_point: "vs_main",
|
||||
buffers: &[wgpu::VertexBufferLayout {
|
||||
array_stride: terrain_vertex_size as wgpu::BufferAddress,
|
||||
step_mode: wgpu::InputStepMode::Vertex,
|
||||
@@ -581,8 +590,8 @@ impl framework::Example for Example {
|
||||
}],
|
||||
},
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module: &terrain_fs_module,
|
||||
entry_point: "main",
|
||||
module: &terrain_module,
|
||||
entry_point: "fs_main",
|
||||
targets: &[sc_desc.format.into()],
|
||||
}),
|
||||
primitive: wgpu::PrimitiveState {
|
||||
|
||||
49
wgpu/examples/water/terrain.wgsl
Normal file
49
wgpu/examples/water/terrain.wgsl
Normal file
@@ -0,0 +1,49 @@
|
||||
[[block]]
|
||||
struct Uniforms {
|
||||
projection_view: mat4x4<f32>;
|
||||
clipping_plane: vec4<f32>;
|
||||
};
|
||||
|
||||
[[group(0), binding(0)]]
|
||||
var<uniform> uniforms: Uniforms;
|
||||
|
||||
const light: vec3<f32> = vec3<f32>(150.0, 70.0, 0.0);
|
||||
const light_colour: vec3<f32> = vec3<f32>(1.0, 0.98, 0.82);
|
||||
const 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
|
||||
const normalized_light_direction = normalize(position - light);
|
||||
const 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);
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
#version 450
|
||||
|
||||
layout(early_fragment_tests) in;
|
||||
|
||||
layout(location = 0) in vec4 v_Colour;
|
||||
// Comment this out if using user-clipping planes:
|
||||
layout(location = 1) in float v_ClipDist;
|
||||
|
||||
layout(location = 0) out vec4 outColour;
|
||||
|
||||
void main() {
|
||||
// Comment this out if using user-clipping planes:
|
||||
if(v_ClipDist < 0.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
outColour = v_Colour;
|
||||
outColour.a = 1.0;
|
||||
}
|
||||
Binary file not shown.
@@ -1,38 +0,0 @@
|
||||
#version 450
|
||||
|
||||
layout(set = 0, binding = 0) uniform Uniforms {
|
||||
mat4x4 projection_view;
|
||||
vec4 clipping_plane;
|
||||
};
|
||||
|
||||
const vec3 light = vec3(150.0, 70.0, 0.0);
|
||||
const vec3 light_colour = vec3(1.0, 250.0 / 255.0, 209.0 / 255.0);
|
||||
|
||||
const float ambient = 0.2;
|
||||
|
||||
layout(location = 0) in vec3 position;
|
||||
layout(location = 1) in vec3 normal;
|
||||
layout(location = 2) in vec4 colour;
|
||||
|
||||
layout(location = 0) out vec4 v_Colour;
|
||||
// Comment this out if using user-clipping planes:
|
||||
layout(location = 1) out float v_ClipDist;
|
||||
|
||||
void main() {
|
||||
gl_Position = projection_view * vec4(position, 1.0);
|
||||
|
||||
// https://www.desmos.com/calculator/nqgyaf8uvo
|
||||
|
||||
vec3 normalized_light_direction = normalize(position - light);
|
||||
|
||||
float brightness_diffuse = clamp(dot(normalized_light_direction, normal), 0.2, 1.0);
|
||||
|
||||
v_Colour.rgb = max((brightness_diffuse + ambient) * light_colour * colour.rgb, 0.0);
|
||||
v_Colour.a = colour.a;
|
||||
|
||||
// Comment this out if using user-clipping planes:
|
||||
v_ClipDist = dot(vec4(position, 1.0), clipping_plane);
|
||||
|
||||
// Uncomment this if using user-clipping planes:
|
||||
// gl_ClipDistance[0] = dot(vec4(position, 1.0), clipping_plane);
|
||||
}
|
||||
Binary file not shown.
252
wgpu/examples/water/water.wgsl
Normal file
252
wgpu/examples/water/water.wgsl
Normal file
@@ -0,0 +1,252 @@
|
||||
[[block]]
|
||||
struct Uniforms {
|
||||
view: mat4x4<f32>;
|
||||
projection: mat4x4<f32>;
|
||||
time_size_width: vec4<f32>;
|
||||
viewport_height: f32;
|
||||
};
|
||||
[[group(0), binding(0)]] var<uniform> uniforms: Uniforms;
|
||||
|
||||
const light_point: vec3<f32> = vec3<f32>(150.0, 70.0, 0.0);
|
||||
const light_colour: vec3<f32> = vec3<f32>(1.0, 0.98, 0.82);
|
||||
const one: vec4<f32> = vec4<f32>(1.0, 1.0, 1.0, 1.0);
|
||||
|
||||
const Y_SCL: f32 = 0.86602540378443864676372317075294;
|
||||
const CURVE_BIAS: f32 = -0.1;
|
||||
const 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 {
|
||||
const C = vec2<f32>(1.0/6.0, 1.0/3.0);
|
||||
const D = vec4<f32>(0.0, 0.5, 1.0, 2.0);
|
||||
|
||||
// First corner
|
||||
//TODO: use the splat operations when available
|
||||
const vCy = dot(v, C.yyy);
|
||||
var i: vec3<f32> = floor(v + vec3<f32>(vCy, vCy, vCy));
|
||||
const iCx = dot(i, C.xxx);
|
||||
const x0 = v - i + vec3<f32>(iCx, iCx, iCx);
|
||||
|
||||
// Other corners
|
||||
const g = step(x0.yzx, x0.xyz);
|
||||
const l = (vec3<f32>(1.0, 1.0, 1.0) - g).zxy;
|
||||
const i1 = min(g, l);
|
||||
const 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;
|
||||
const x1 = x0 - i1 + C.xxx;
|
||||
const x2 = x0 - i2 + C.yyy; // 2.0*C.x = 1/3 = C.y
|
||||
const 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);
|
||||
const 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)
|
||||
const n_ = 0.142857142857;// 1.0/7.0
|
||||
const ns = n_ * D.wyz - D.xzx;
|
||||
|
||||
const j = p - 49.0 * floor(p * ns.z * ns.z);// mod(p,7*7)
|
||||
|
||||
const x_ = floor(j * ns.z);
|
||||
const 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;
|
||||
const h = one - abs(x) - abs(y);
|
||||
|
||||
const b0 = vec4<f32>(x.xy, y.xy);
|
||||
const 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;
|
||||
const s0 = floor(b0)*2.0 + one;
|
||||
const s1 = floor(b1)*2.0 + one;
|
||||
const sh = -step(h, 0.0 * one);
|
||||
|
||||
const a0 = b0.xzyw + s0.xzyw*sh.xxyy;
|
||||
const 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
|
||||
const 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`.
|
||||
const sn = uniforms.time_size_width.x;
|
||||
const cs = uniforms.time_size_width.y;
|
||||
const 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);
|
||||
|
||||
const xcos = perlin_pos.x * cs;
|
||||
const xsin = perlin_pos.x * sn;
|
||||
const ycos = perlin_pos.y * cs;
|
||||
const ysin = perlin_pos.y * sn;
|
||||
const zcos = perlin_pos.z * cs;
|
||||
const zsin = perlin_pos.z * sn;
|
||||
|
||||
// Rotate Time Y
|
||||
const perlin_pos_y = vec3<f32>(xcos + zsin, perlin_pos.y, -xsin + xcos);
|
||||
|
||||
// Rotate Time Z
|
||||
const 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
|
||||
const 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> {
|
||||
const 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> {
|
||||
const norm = normalize(cross(b - c, a - c));
|
||||
const 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 {
|
||||
const 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 {
|
||||
const p_pos = vec2<f32>(position);
|
||||
const b_pos = make_position(p_pos + vec2<f32>(offsets.xy));
|
||||
const c_pos = make_position(p_pos + vec2<f32>(offsets.zw));
|
||||
const a_pos = make_position(p_pos);
|
||||
const original_pos = vec4<f32>(p_pos.x * 0.5, 0.0, p_pos.y * Y_SCL, 1.0);
|
||||
|
||||
const vm = uniforms.view;
|
||||
const transformed_pos = vm * a_pos;
|
||||
//TODO: use vector splats for division
|
||||
const water_pos = transformed_pos.xyz * (1.0 / transformed_pos.w);
|
||||
const normal = make_normal((vm * a_pos).xyz, (vm * b_pos).xyz, (vm * c_pos).xyz);
|
||||
const eye = normalize(-water_pos);
|
||||
const 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);
|
||||
|
||||
const 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;
|
||||
}
|
||||
|
||||
|
||||
const water_colour: vec3<f32> = vec3<f32>(0.0, 0.46, 0.95);
|
||||
const zNear: f32 = 10.0;
|
||||
const 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 {
|
||||
const z_n: f32 = 2.0 * depth - 1.0;
|
||||
const 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> {
|
||||
const reflection_colour = textureSample(reflection, colour_sampler, in.f_WaterScreenPos.xy).xyz;
|
||||
|
||||
const pixel_depth = to_linear_depth(in.position.z);
|
||||
const normalized_coords = in.position.xy / vec2<f32>(uniforms.time_size_width.w, uniforms.viewport_height);
|
||||
const terrain_depth = to_linear_depth(textureSample(terrain_depth_tex, colour_sampler, normalized_coords).r);
|
||||
|
||||
const dist = terrain_depth - pixel_depth;
|
||||
const clamped = pow(smoothStep(0.0, 1.5, dist), 4.8);
|
||||
|
||||
const final_colour = in.f_Light + reflection_colour;
|
||||
const t = smoothStep(1.0, 5.0, dist) * 0.2; //TODO: splat for mix()?
|
||||
const depth_colour = mix(final_colour, water_colour, vec3<f32>(t, t, t));
|
||||
|
||||
return vec4<f32>(depth_colour, clamped * (1.0 - in.f_Fresnel));
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
#version 450
|
||||
|
||||
const vec3 water_colour = vec3(0.0, 117.0 / 255.0, 242.0 / 255.0);
|
||||
const float zNear = 10.0;
|
||||
const float zFar = 400.0;
|
||||
|
||||
layout(set = 0, binding = 0) uniform Uniforms {
|
||||
mat4x4 _view;
|
||||
mat4x4 _projection;
|
||||
vec4 time_size_width;
|
||||
float viewport_height;
|
||||
};
|
||||
|
||||
layout(set = 0, binding = 1) uniform texture2D reflection;
|
||||
layout(set = 0, binding = 2) uniform texture2D terrain_depth_tex;
|
||||
layout(set = 0, binding = 3) uniform sampler colour_sampler;
|
||||
|
||||
layout(location = 0) in vec2 f_WaterScreenPos;
|
||||
layout(location = 1) in float f_Fresnel;
|
||||
layout(location = 2) in vec3 f_Light;
|
||||
|
||||
layout(location = 0) out vec4 outColor;
|
||||
|
||||
float to_linear_depth(float depth) {
|
||||
float z_n = 2.0 * depth - 1.0;
|
||||
float z_e = 2.0 * zNear * zFar / (zFar + zNear - z_n * (zFar - zNear));
|
||||
return z_e;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec3 reflection_colour = texture(sampler2D(reflection, colour_sampler), f_WaterScreenPos.xy).xyz;
|
||||
|
||||
float pixel_depth = to_linear_depth(gl_FragCoord.z);
|
||||
float terrain_depth = to_linear_depth(texture(sampler2D(terrain_depth_tex, colour_sampler), gl_FragCoord.xy / vec2(time_size_width.w, viewport_height)).r);
|
||||
|
||||
float dist = terrain_depth - pixel_depth;
|
||||
float clamped = pow(smoothstep(0.0, 1.5, dist), 4.8);
|
||||
|
||||
outColor.a = clamped * (1.0 - f_Fresnel);
|
||||
|
||||
vec3 final_colour = f_Light + reflection_colour;
|
||||
|
||||
vec3 depth_colour = mix(final_colour, water_colour, smoothstep(1.0, 5.0, dist) * 0.2);
|
||||
|
||||
outColor.xyz = depth_colour;
|
||||
}
|
||||
Binary file not shown.
@@ -1,211 +0,0 @@
|
||||
#version 450
|
||||
|
||||
layout(set = 0, binding = 0) uniform Uniforms {
|
||||
mat4x4 view;
|
||||
mat4x4 projection;
|
||||
vec4 time_size_width;
|
||||
float _viewport_height;
|
||||
};
|
||||
|
||||
const vec3 light_point = vec3(150.0, 70.0, 0.0);
|
||||
const vec3 light_colour = vec3(1.0, 250.0 / 255.0, 209.0 / 255.0);
|
||||
|
||||
const float Y_SCL = 0.86602540378443864676372317075294;
|
||||
const float CURVE_BIAS = -0.1;
|
||||
const float INV_1_CURVE_BIAS = 1.0 / (1.0 + CURVE_BIAS);
|
||||
|
||||
layout(location = 0) in ivec2 position;
|
||||
layout(location = 1) in ivec4 offsets;
|
||||
|
||||
layout(location = 0) out vec2 f_WaterScreenPos;
|
||||
layout(location = 1) out float f_Fresnel;
|
||||
layout(location = 2) out vec3 f_Light;
|
||||
|
||||
//
|
||||
// The following code to calculate simplex 3D
|
||||
// is from https://github.com/ashima/webgl-noise
|
||||
//
|
||||
// Simplex 3D Noise
|
||||
// by Ian McEwan, Ashima Arts.
|
||||
//
|
||||
vec4 permute(vec4 x) {
|
||||
return mod(((x*34.0)+1.0)*x, 289.0);
|
||||
}
|
||||
|
||||
vec4 taylorInvSqrt(vec4 r){
|
||||
return 1.79284291400159 - 0.85373472095314 * r;
|
||||
}
|
||||
|
||||
float snoise(vec3 v){
|
||||
const vec2 C = vec2(1.0/6.0, 1.0/3.0);
|
||||
const vec4 D = vec4(0.0, 0.5, 1.0, 2.0);
|
||||
|
||||
// First corner
|
||||
vec3 i = floor(v + dot(v, C.yyy));
|
||||
vec3 x0 = v - i + dot(i, C.xxx);
|
||||
|
||||
// Other corners
|
||||
vec3 g = step(x0.yzx, x0.xyz);
|
||||
vec3 l = 1.0 - g;
|
||||
vec3 i1 = min(g.xyz, l.zxy);
|
||||
vec3 i2 = max(g.xyz, l.zxy);
|
||||
|
||||
// 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;
|
||||
vec3 x1 = x0 - i1 + C.xxx;
|
||||
vec3 x2 = x0 - i2 + C.yyy;// 2.0*C.x = 1/3 = C.y
|
||||
vec3 x3 = x0 - D.yyy;// -1.0+3.0*C.x = -0.5 = -D.y
|
||||
|
||||
// Permutations
|
||||
i = mod(i, 289.0);
|
||||
vec4 p = permute(permute(permute(
|
||||
i.z + vec4(0.0, i1.z, i2.z, 1.0))
|
||||
+ i.y + vec4(0.0, i1.y, i2.y, 1.0))
|
||||
+ i.x + vec4(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)
|
||||
float n_ = 0.142857142857;// 1.0/7.0
|
||||
vec3 ns = n_ * D.wyz - D.xzx;
|
||||
|
||||
vec4 j = p - 49.0 * floor(p * ns.z * ns.z);// mod(p,7*7)
|
||||
|
||||
vec4 x_ = floor(j * ns.z);
|
||||
vec4 y_ = floor(j - 7.0 * x_);// mod(j,N)
|
||||
|
||||
vec4 x = x_ *ns.x + ns.yyyy;
|
||||
vec4 y = y_ *ns.x + ns.yyyy;
|
||||
vec4 h = 1.0 - abs(x) - abs(y);
|
||||
|
||||
vec4 b0 = vec4(x.xy, y.xy);
|
||||
vec4 b1 = vec4(x.zw, y.zw);
|
||||
|
||||
//vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
|
||||
//vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
|
||||
vec4 s0 = floor(b0)*2.0 + 1.0;
|
||||
vec4 s1 = floor(b1)*2.0 + 1.0;
|
||||
vec4 sh = -step(h, vec4(0.0));
|
||||
|
||||
vec4 a0 = b0.xzyw + s0.xzyw*sh.xxyy;
|
||||
vec4 a1 = b1.xzyw + s1.xzyw*sh.zzww;
|
||||
|
||||
vec3 p0 = vec3(a0.xy, h.x);
|
||||
vec3 p1 = vec3(a0.zw, h.y);
|
||||
vec3 p2 = vec3(a1.xy, h.z);
|
||||
vec3 p3 = vec3(a1.zw, h.w);
|
||||
|
||||
//Normalise gradients
|
||||
vec4 norm = taylorInvSqrt(vec4(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));
|
||||
p0 *= norm.x;
|
||||
p1 *= norm.y;
|
||||
p2 *= norm.z;
|
||||
p3 *= norm.w;
|
||||
|
||||
// Mix final noise value
|
||||
vec4 m = max(0.6 - vec4(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), 0.0);
|
||||
m = m * m;
|
||||
return 9.0 * dot(m*m, vec4(dot(p0, x0), dot(p1, x1),
|
||||
dot(p2, x2), dot(p3, x3)));
|
||||
}
|
||||
|
||||
// End of 3D simplex code.
|
||||
|
||||
vec3 apply_distortion(vec3 pos) {
|
||||
vec3 perlin_pos = pos;
|
||||
|
||||
//Do noise transformation to permit for smooth,
|
||||
//continuous movement.
|
||||
|
||||
float sin = time_size_width.x;
|
||||
float cos = time_size_width.y;
|
||||
float size = time_size_width.z;
|
||||
|
||||
// Rotate 90 Z
|
||||
perlin_pos.xy = perlin_pos.yx;
|
||||
perlin_pos.x = -perlin_pos.x;
|
||||
// Move Left Size / 2
|
||||
perlin_pos.x -= size;
|
||||
|
||||
float xcos = perlin_pos.x * cos;
|
||||
float xsin = perlin_pos.x * sin;
|
||||
float ycos = perlin_pos.y * cos;
|
||||
float ysin = perlin_pos.y * sin;
|
||||
float zcos = perlin_pos.z * cos;
|
||||
float zsin = perlin_pos.z * sin;
|
||||
|
||||
// Rotate Time Y
|
||||
vec3 perlin_pos_y = vec3(xcos + zsin, perlin_pos.y, -xsin + xcos);
|
||||
|
||||
// Rotate Time Z
|
||||
vec3 perlin_pos_z = vec3(xcos - ysin, xsin + ycos, perlin_pos.x);
|
||||
|
||||
// Rotate 90 Y
|
||||
perlin_pos.xz = perlin_pos.zx;
|
||||
perlin_pos.x = -perlin_pos.x;
|
||||
|
||||
// Rotate Time X
|
||||
vec3 perlin_pos_x = vec3(perlin_pos.x, ycos - zsin, ysin + zcos);
|
||||
|
||||
// Sample at different places for x/y/z to get random-looking water.
|
||||
return vec3(pos.x + snoise(perlin_pos_x + 2.0) * 0.4, pos.y + snoise(perlin_pos_y - 2.0) * 1.8, pos.z + snoise(perlin_pos_z) * 0.4);
|
||||
}
|
||||
|
||||
// Multiply the input by the scale values.
|
||||
vec3 make_position(vec2 original) {
|
||||
vec3 interpreted = vec3(original.x * 0.5, 0.0, original.y * Y_SCL);
|
||||
return apply_distortion(interpreted);
|
||||
}
|
||||
|
||||
// Create the normal, and apply the curve. Change the Curve Bias above.
|
||||
vec3 make_normal(vec3 a, vec3 b, vec3 c) {
|
||||
vec3 norm = normalize(cross(b - c, a - c));
|
||||
vec3 center = (a + b + c) / 3.0;
|
||||
return (normalize(a - center) * CURVE_BIAS + norm) * INV_1_CURVE_BIAS;
|
||||
}
|
||||
|
||||
// Calculate the fresnel effect.
|
||||
float calc_fresnel(vec3 view, vec3 normal) {
|
||||
float refractive = abs(dot(view, normal));
|
||||
refractive = pow(refractive, 1.33333333333);
|
||||
return refractive;
|
||||
}
|
||||
|
||||
// Calculate the specular lighting.
|
||||
float calc_specular(vec3 eye, vec3 normal, vec3 light) {
|
||||
vec3 light_reflected = reflect(light, normal);
|
||||
float specular = max(dot(eye, light_reflected), 0.0);
|
||||
specular = pow(specular, 10.0);
|
||||
return specular;
|
||||
}
|
||||
|
||||
void main() {
|
||||
vec2 p_pos = position;
|
||||
vec3 b_pos = make_position(p_pos + offsets.xy);
|
||||
vec3 c_pos = make_position(p_pos + offsets.zw);
|
||||
vec4 a_pos = vec4(make_position(p_pos), 1.0);
|
||||
vec4 original_pos = vec4(p_pos.x * 0.5, 0.0, p_pos.y * Y_SCL, 1.0);
|
||||
|
||||
vec4 water_pos = a_pos;
|
||||
|
||||
mat4x4 vm = view;
|
||||
|
||||
vec4 transformed_pos = vm * water_pos;
|
||||
water_pos.xyz = transformed_pos.xyz / transformed_pos.w;
|
||||
|
||||
vec3 normal = make_normal((vm * a_pos).xyz, (vm * vec4(b_pos, 1.0)).xyz, (vm * vec4(c_pos, 1.0)).xyz);
|
||||
vec3 eye = normalize(-water_pos.xyz);
|
||||
|
||||
vec4 transformed_light = vm * vec4(light_point, 1.0);
|
||||
|
||||
f_Light = light_colour * calc_specular(eye, normal, normalize(water_pos.xyz - (transformed_light.xyz / transformed_light.w)));
|
||||
f_Fresnel = calc_fresnel(eye, normal);
|
||||
|
||||
vec4 projected_pos = projection * transformed_pos;
|
||||
|
||||
gl_Position = projected_pos;
|
||||
|
||||
vec4 gridpos = projection * vm * original_pos;
|
||||
f_WaterScreenPos.xy = (0.5 * gridpos.xy / gridpos.w) + 0.5;
|
||||
}
|
||||
Binary file not shown.
Reference in New Issue
Block a user