From f2ff8f7bc44ecfdb5d18f9fb2244d9ee94073fbc Mon Sep 17 00:00:00 2001 From: Amatsugu Date: Tue, 22 Oct 2024 20:36:56 -0400 Subject: [PATCH] update water waves --- .../src/generators/mesh_generator.rs | 44 +++-- engine/world_generation/src/map/map.rs | 153 +++++++++++++----- engine/world_generation/src/map/mesh_chunk.rs | 10 +- game/main/assets | 2 +- 4 files changed, 146 insertions(+), 63 deletions(-) diff --git a/engine/world_generation/src/generators/mesh_generator.rs b/engine/world_generation/src/generators/mesh_generator.rs index 1927d65..c86e72c 100644 --- a/engine/world_generation/src/generators/mesh_generator.rs +++ b/engine/world_generation/src/generators/mesh_generator.rs @@ -118,8 +118,7 @@ pub fn generate_chunk_water_mesh(chunk: &MeshChunkData, sealevel: f32, map_width create_tile_water_surface( tile_pos, - height, - chunk.min_height, + chunk.distance_to_land[idx], &n, neighbor_has_land, &mut verts, @@ -142,9 +141,8 @@ pub fn generate_chunk_water_mesh(chunk: &MeshChunkData, sealevel: f32, map_width fn create_tile_water_surface( pos: Vec3, - height: f32, - min_height: f32, - neighbors: &[f32; 6], + dist_to_land: f32, + neighbors: &[(f32, Option); 6], neighbor_has_land: bool, verts: &mut Vec, uvs: &mut Vec, @@ -152,16 +150,16 @@ fn create_tile_water_surface( normals: &mut Vec, ) { if !neighbor_has_land { - crate_tile_water_inner_surface(pos, height, min_height, verts, uvs, indices, normals); + crate_tile_water_inner_surface(pos, dist_to_land, neighbors, verts, uvs, indices, normals); return; } - crate_tile_water_shore_surface(pos, height, min_height, neighbors, verts, uvs, indices, normals); + crate_tile_water_shore_surface(pos, dist_to_land, neighbors, verts, uvs, indices, normals); } fn crate_tile_water_inner_surface( pos: Vec3, - height: f32, - min_height: f32, + dist_to_land: f32, + neighbors: &[(f32, Option); 6], verts: &mut Vec, uvs: &mut Vec, indices: &mut Vec, @@ -172,7 +170,14 @@ fn crate_tile_water_inner_surface( for i in 0..6 { let p = pos + HEX_CORNERS[i]; verts.push(p); - uvs.push(Vec2::new(0.0, height.remap(min_height, pos.y, 0.0, 1.0))); + let n1 = if let Some(v) = neighbors[i].1 { v } else { dist_to_land }; + let n2 = if let Some(v) = neighbors[(i + 5) % 6].1 { + v + } else { + dist_to_land + }; + let d = (n1 + n2 + dist_to_land) / 3.0; + uvs.push(Vec2::new(0.0, d.remap(0., 4., 1.0, 0.0))); normals.push(Vec3::Y); } for i in 0..3 { @@ -188,9 +193,8 @@ fn crate_tile_water_inner_surface( fn crate_tile_water_shore_surface( pos: Vec3, - height: f32, - min_height: f32, - neighbors: &[f32; 6], + dist_to_land: f32, + neighbors: &[(f32, Option); 6], verts: &mut Vec, uvs: &mut Vec, indices: &mut Vec, @@ -199,23 +203,29 @@ fn crate_tile_water_shore_surface( let idx = verts.len() as u32; //todo: only use triangle fan when on shoreline verts.push(pos); - uvs.push(Vec2::new(0.0, height.remap(min_height, pos.y, 0.0, 1.0))); + uvs.push(Vec2::new(0.0, dist_to_land.remap(0., 4., 1.0, 0.0))); normals.push(Vec3::Y); for i in 0..12 { let p = pos + WATER_HEX_CORNERS[i]; verts.push(p); - let mut uv = Vec2::new(0.0, height.remap(min_height, pos.y, 0.0, 1.0)); let ni = i / 2; let n = neighbors[ni]; let nn = neighbors[(ni + 5) % 6]; + let mut uv = Vec2::new(0.0, dist_to_land.remap(0., 4., 1.0, 0.0)); - if nn > pos.y || n > pos.y { + if nn.0 > pos.y || n.0 > pos.y { uv.x = 1.0; } if ni * 2 != i { - if n <= pos.y { + if n.0 <= pos.y { uv.x = 0.0; } + let d = if let Some(v) = n.1 { v } else { dist_to_land }; + uv.y = ((d + dist_to_land) / 2.0).remap(0., 4., 1.0, 0.0); + } else { + let d = if let Some(v) = n.1 { v } else { dist_to_land }; + let d2 = if let Some(v) = nn.1 { v } else { dist_to_land }; + uv.y = ((d + d2 + dist_to_land) / 3.0).remap(0., 4., 1.0, 0.0); } indices.push(idx); diff --git a/engine/world_generation/src/map/map.rs b/engine/world_generation/src/map/map.rs index 4224b15..a9ab300 100644 --- a/engine/world_generation/src/map/map.rs +++ b/engine/world_generation/src/map/map.rs @@ -42,9 +42,47 @@ impl Map { sealevel: self.sealevel, heights: chunk.heights.clone(), textures: chunk.textures.clone(), + distance_to_land: self.get_distance_from_land(chunk.chunk_offset, 4), }; } + fn get_distance_from_land(&self, chunk_offset: IVec2, range: usize) -> [f32; Chunk::AREA] { + #[cfg(feature = "tracing")] + let _spawn_span = info_span!("Chunk Land Dist Data").entered(); + let mut dists = [0.0; Chunk::AREA]; + let cx = chunk_offset.x as usize * Chunk::SIZE; + let cz = chunk_offset.y as usize * Chunk::SIZE; + for z in 0..Chunk::SIZE { + for x in 0..Chunk::SIZE { + let coord = HexCoord::from_grid_pos(x + cx, z + cz); + let index = coord.to_chunk_local_index(); + + if !self.is_in_bounds(&coord) { + warn!("Coord is not in bounds!?"); + } + + //Current tile is land tile + if self.sample_height(&coord) > self.sealevel { + dists[index] = 0.0; + continue; + } + + //Find closest land tile + if let Some(d) = self.hex_select_first(&coord, range, false, |_t, h, r| { + if h > self.sealevel { + return Some(r as f32); + } + return None; + }) { + dists[index] = d; + } else { + dists[index] = range as f32; + } + } + } + return dists; + } + pub fn get_neighbors(&self, pos: &HexCoord) -> [Option; 6] { let mut results: [Option; 6] = [None; 6]; let w = self.width * Chunk::SIZE; @@ -96,47 +134,6 @@ impl Map { let chunk = &self.chunks[pos.to_chunk_index(self.width)]; return chunk.biome_id[pos.to_chunk_local_index()]; } - /* - pub fn get_biome_noise(&self, pos: &HexCoord) -> &BiomeData { - assert!( - self.is_in_bounds(pos), - "The provided coordinate is not within the map bounds" - ); - - let chunk = &self.chunks[pos.to_chunk_index(self.width)]; - return &chunk.biome_data[pos.to_chunk_local_index()]; - } - - pub fn get_moisture(&self, pos: &HexCoord) -> f32 { - assert!( - self.is_in_bounds(pos), - "The provided coordinate is not within the map bounds" - ); - - let chunk = &self.chunks[pos.to_chunk_index(self.width)]; - return chunk.biome_data[pos.to_chunk_local_index()].moisture; - } - - pub fn get_tempurature(&self, pos: &HexCoord) -> f32 { - assert!( - self.is_in_bounds(pos), - "The provided coordinate is not within the map bounds" - ); - - let chunk = &self.chunks[pos.to_chunk_index(self.width)]; - return chunk.biome_data[pos.to_chunk_local_index()].temperature; - } - - pub fn get_continentality(&self, pos: &HexCoord) -> f32 { - assert!( - self.is_in_bounds(pos), - "The provided coordinate is not within the map bounds" - ); - - let chunk = &self.chunks[pos.to_chunk_index(self.width)]; - return chunk.biome_data[pos.to_chunk_local_index()].continentality; - } - */ pub fn get_center(&self) -> Vec3 { let w = self.get_world_width(); @@ -206,6 +203,80 @@ impl Map { return result; } + pub fn hex_select_first( + &self, + center: &HexCoord, + radius: usize, + include_center: bool, + op: OP, + ) -> Option + where + OP: (Fn(&HexCoord, f32, usize) -> Option) + Sync + Send, + { + assert!(radius != 0, "Radius cannot be zero"); + + if include_center { + let h = self.sample_height(¢er); + let r = (op)(center, h, 0); + if r.is_some() { + return r; + } + } + + for k in 0..(radius + 1) { + let mut p = center.scale(4, k); + for i in 0..6 { + for _j in 0..k { + p = p.get_neighbor(i); + if self.is_in_bounds(&p) { + let h = self.sample_height(&p); + let r = (op)(&p, h, k); + if r.is_some() { + return r; + } + } + } + } + } + + return None; + } + + pub fn ring_select_first( + &self, + center: &HexCoord, + start_radius: usize, + end_radius: usize, + op: OP, + ) -> Option + where + OP: (Fn(&HexCoord, f32, usize) -> Option) + Sync + Send, + { + assert!(start_radius != 0, "Start radius cannot be zero"); + assert!( + start_radius > end_radius, + "Start radius cannot be lower than end radius" + ); + + for k in start_radius..(end_radius + 1) { + let mut p = center.scale(4, k); + for i in 0..6 { + for _j in 0..k { + p = p.get_neighbor(i); + if self.is_in_bounds(&p) { + let h = self.sample_height(&p); + let r = (op)(&p, h, k); + if r.is_some() { + return r; + } + } + } + } + } + + return None; + } + pub fn hex_select_mut( &mut self, center: &HexCoord, diff --git a/engine/world_generation/src/map/mesh_chunk.rs b/engine/world_generation/src/map/mesh_chunk.rs index 5ec50d3..0800976 100644 --- a/engine/world_generation/src/map/mesh_chunk.rs +++ b/engine/world_generation/src/map/mesh_chunk.rs @@ -7,6 +7,7 @@ pub struct MeshChunkData { pub textures: [[u32; 2]; Chunk::AREA], pub min_height: f32, pub sealevel: f32, + pub distance_to_land: [f32; Chunk::AREA], } impl MeshChunkData { @@ -24,17 +25,18 @@ impl MeshChunkData { return data; } - pub fn get_neighbors_with_water_info(&self, coord: &HexCoord) -> ([f32; 6], bool) { + pub fn get_neighbors_with_water_info(&self, coord: &HexCoord) -> ([(f32, Option); 6], bool) { let mut has_land = false; - let mut data = [self.min_height; 6]; + let mut data = [(self.min_height, None); 6]; let n_tiles = coord.get_neighbors(); for i in 0..6 { let n = n_tiles[i]; if !n.is_in_bounds(Chunk::SIZE, Chunk::SIZE) { continue; } - data[i] = self.heights[n.to_index(Chunk::SIZE)]; - if data[i] > self.sealevel { + let idx = n.to_index(Chunk::SIZE); + data[i] = (self.heights[idx], Some(self.distance_to_land[idx])); + if data[i].0 > self.sealevel { has_land = true; } } diff --git a/game/main/assets b/game/main/assets index 939ce07..63384f1 160000 --- a/game/main/assets +++ b/game/main/assets @@ -1 +1 @@ -Subproject commit 939ce074e9e33b98c3789b3724d08fd1ae612778 +Subproject commit 63384f1ef849c521443c4688dd52d0f0c766ffc2