diff --git a/assets/shaders/pbr/render.wgsl b/assets/shaders/pbr/render.wgsl index 51f0df64..0abbc269 100644 --- a/assets/shaders/pbr/render.wgsl +++ b/assets/shaders/pbr/render.wgsl @@ -1,6 +1,6 @@ -#include "dither.wgsl" -#include "tonemap.wgsl" -#include "atmosphere.wgsl" +#include "../dither.wgsl" +#include "../tonemap.wgsl" +#include "../atmosphere.wgsl" fn fresnelSchlick(cosTheta: f32, F0: vec3) -> vec3 { return F0 + (1.0 - F0) * pow(clamp(1.0 - cosTheta, 0.0, 1.0), 5.0); diff --git a/assets/shaders/terrain.frag.wgsl b/assets/shaders/terrain/terrain.frag.wgsl similarity index 98% rename from assets/shaders/terrain.frag.wgsl rename to assets/shaders/terrain/terrain.frag.wgsl index 21d2db3e..4836fbc0 100644 --- a/assets/shaders/terrain.frag.wgsl +++ b/assets/shaders/terrain/terrain.frag.wgsl @@ -1,6 +1,6 @@ -#include "render_params.wgsl" -#include "shadow.wgsl" -#include "pbr/render.wgsl" +#include "../render_params.wgsl" +#include "../shadow.wgsl" +#include "../pbr/render.wgsl" struct FragmentOutput { @location(0) out_color: vec4, diff --git a/assets/shaders/terrain.vert.wgsl b/assets/shaders/terrain/terrain.vert.wgsl similarity index 75% rename from assets/shaders/terrain.vert.wgsl rename to assets/shaders/terrain/terrain.vert.wgsl index 030e7c8d..fd8b1c69 100644 --- a/assets/shaders/terrain.vert.wgsl +++ b/assets/shaders/terrain/terrain.vert.wgsl @@ -1,4 +1,5 @@ -#include "render_params.wgsl" +#include "../render_params.wgsl" +#include "unpack.wgsl" struct Uniforms { u_view_proj: mat4x4, @@ -36,20 +37,6 @@ normal: vec3(self.cell_size * scale as f32, 0.0, hx - height) .normalize(), */ -const MAX_HEIGHT: f32 = 1024.0; -const MAX_DIFF: f32 = 32.0; - -fn unpack_height(h: u32) -> f32 { - return ((f32(h) - 32768.0) / 32767.0 ) * MAX_HEIGHT; -} - -fn unpack_diffs(v: u32) -> vec2 { - let x = v & 0xFFu; - let y = (v & 0xFF00u) >> 8u; - return vec2((f32(x) - 128.0) / 127.0 * MAX_DIFF, - (f32(y) - 128.0) / 127.0 * MAX_DIFF); -} - @vertex fn vert(@builtin(vertex_index) vid: u32, @location(0) in_off: vec2, @@ -75,19 +62,15 @@ fn vert(@builtin(vertex_index) vid: u32, let tpos: vec2 = in_position * i32(cdata.lod_pow2) + vec2(in_off * cdata.inv_cell_size); - let texLoad: vec2 = textureLoad(t_terraindata, tpos, 0).rg; - - let height: f32 = unpack_height(texLoad.r); - let diffs: vec2 = unpack_diffs(texLoad.g); + let h_dx_dy: vec3 = unpack(textureLoad(t_terraindata, tpos, 0).r, 1.0); - let world_pos: vec3 = vec3(vec2(in_position * i32(cdata.lod_pow2)) * cdata.cell_size + in_off, height); + let world_pos: vec3 = vec3(vec2(in_position * i32(cdata.lod_pow2)) * cdata.cell_size + in_off, h_dx_dy.x); + let clip_pos: vec4 = global.u_view_proj * vec4(world_pos, 1.0); //let dist_to_cam: f32 = length(params.cam_pos.xyz - vec3(pos.xy, 0.0)); //let transition_alpha: f32 = smoothstep(cdata.distance_lod_cutoff * 0.8, cdata.distance_lod_cutoff, dist_to_cam); - var out_normal: vec3 = normalize(vec3(diffs.x, diffs.y, cdata.cell_size * 2.0)); // https://stackoverflow.com/questions/49640250/calculate-normals-from-heightmap - - let position: vec4 = global.u_view_proj * vec4(world_pos, 1.0); + var out_normal: vec3 = normalize(vec3(h_dx_dy.yz, cdata.cell_size * 2.0)); // https://stackoverflow.com/questions/49640250/calculate-normals-from-heightmap #ifdef DEBUG var debug = 0.0; @@ -104,5 +87,5 @@ fn vert(@builtin(vertex_index) vid: u32, #ifdef DEBUG debug, #endif - position); + clip_pos); } diff --git a/assets/shaders/terrain/unpack.wgsl b/assets/shaders/terrain/unpack.wgsl new file mode 100644 index 00000000..3100acad --- /dev/null +++ b/assets/shaders/terrain/unpack.wgsl @@ -0,0 +1,18 @@ +const MAX_HEIGHT: f32 = 1024.0; +const MAX_DIFF: f32 = 32.0; + +fn unpack_height(h: u32) -> f32 { + return ((f32(h) - 32768.0) / 32767.0 ) * MAX_HEIGHT; +} + +fn unpack_diffs(v: u32, lod_pow2: f32) -> vec2 { + let x = (f32(v >> 8u) - 128.0) / 127.0 * (MAX_DIFF * lod_pow2); + let y = (f32(v & 0xFFu) - 128.0) / 127.0 * (MAX_DIFF * lod_pow2); + return vec2(x, y); +} + +fn unpack(v: u32, lod_pow2: f32) -> vec3 { + let h = unpack_height(v & 0xFFFFu); + let d = unpack_diffs(v >> 16u, lod_pow2); + return vec3(h, d); +} \ No newline at end of file diff --git a/engine/src/drawables/terrain.rs b/engine/src/drawables/terrain.rs index 5af803d2..c327ec1b 100644 --- a/engine/src/drawables/terrain.rs +++ b/engine/src/drawables/terrain.rs @@ -50,7 +50,7 @@ impl TerrainRender TerrainRender Option, ) -> bool { fn pack(height: f32, diffx: f32, diffy: f32) -> [u8; 4] { - let a = ((height.clamp(-MAX_HEIGHT, MAX_HEIGHT) / MAX_HEIGHT * i16::MAX as f32 - + 32768.0) as u16) - .to_le_bytes(); + let h_encoded = ((height.clamp(-MAX_HEIGHT, MAX_HEIGHT) / MAX_HEIGHT * i16::MAX as f32 + + 32768.0) as u16); + + let dx_encoded: u8; + let dy_encoded: u8; if height >= MAX_HEIGHT || height <= -MAX_HEIGHT { - return [a[0], a[1], 128, 128]; // normal is zero if we hit max height + dx_encoded = 128; + dy_encoded = 128; // normal is zero if we hit max height + } else { + dx_encoded = + (diffx.clamp(-MAX_DIFF, MAX_DIFF) / MAX_DIFF * i8::MAX as f32 + 128.0) as u8; + dy_encoded = + (diffy.clamp(-MAX_DIFF, MAX_DIFF) / MAX_DIFF * i8::MAX as f32 + 128.0) as u8; } - let b = (diffx.clamp(-MAX_DIFF, MAX_DIFF) / MAX_DIFF * i8::MAX as f32 + 128.0) as u8; - let c = (diffy.clamp(-MAX_DIFF, MAX_DIFF) / MAX_DIFF * i8::MAX as f32 + 128.0) as u8; - [a[0], a[1], b, c] + let packed = (dx_encoded as u32) << 24 | (dy_encoded as u32) << 16 | h_encoded as u32; + packed.to_le_bytes() } let mut contents = Vec::with_capacity(CRESOLUTION * CRESOLUTION); @@ -386,10 +393,10 @@ impl PipelineBuilder for TerrainPipeline { .collect::>(), label: Some("terrain bindgroup layout"), }); - let vert = &mk_module("terrain.vert"); + let vert = &mk_module("terrain/terrain.vert"); if !self.depth { - let frag = &mk_module("terrain.frag"); + let frag = &mk_module("terrain/terrain.frag"); return gfx.color_pipeline( "terrain", diff --git a/engine/src/shader.rs b/engine/src/shader.rs index 2d000862..212795aa 100644 --- a/engine/src/shader.rs +++ b/engine/src/shader.rs @@ -134,9 +134,9 @@ fn replace_imports(base: &Path, src: &str, deps: &mut Vec) -> String { let mut p = base.to_path_buf(); p.pop(); p.push(loc); - let mut s = std::fs::read_to_string(p) - .unwrap_or_else(|_| panic!("could not find included file {loc}")); - s = replace_imports(base, &s, deps); + let mut s = std::fs::read_to_string(&p) + .unwrap_or_else(|_| panic!("could not find included file {loc} for {base:?}")); + s = replace_imports(&p, &s, deps); return Cow::Owned(s); } Cow::Borrowed(x)