diff --git a/geom/src/heightmap.rs b/geom/src/heightmap.rs index 9c0f97e9..025403f7 100644 --- a/geom/src/heightmap.rs +++ b/geom/src/heightmap.rs @@ -442,7 +442,9 @@ impl Heightmap { .filter_map(|(x, y)| { let chunk_id = (x as u16, y as u16); let corner = vec2(x as f32, y as f32) * SIZE as f32; - let (t_min, t_max) = self.get_chunk(chunk_id)?.bbox(corner).raycast(ray)?; + let mut bbox = self.get_chunk(chunk_id)?.bbox(corner); + bbox.ll.z -= Self::CELL_SIZE; // give a bit of margin to avoid missing intersections when the heightmap is at the lowest + let (t_min, t_max) = bbox.raycast(ray)?; Some((t_min, t_max)) }); diff --git a/native_app/src/game_loop.rs b/native_app/src/game_loop.rs index b777f7f8..be2450db 100644 --- a/native_app/src/game_loop.rs +++ b/native_app/src/game_loop.rs @@ -136,8 +136,13 @@ impl engine::framework::State for State { if let Some(ray) = ray { let cast = map.environment.raycast(ray); - self.uiw.write::().unprojected = cast.map(|x| x.0); - self.uiw.write::().unprojected_normal = cast.map(|x| x.1); + let inp = &mut self.uiw.write::(); + + inp.unprojected = cast.map(|(mut proj, _)| { + proj.z = proj.z.max(0.0); + proj + }); + inp.unprojected_normal = cast.map(|x| x.1); } } diff --git a/native_app/src/inputmap.rs b/native_app/src/inputmap.rs index 946f649f..6331962c 100644 --- a/native_app/src/inputmap.rs +++ b/native_app/src/inputmap.rs @@ -61,7 +61,7 @@ pub struct InputMap { pub act: FastSet, /// Mouse wheel delta pub wheel: f32, - /// Mouse position in world space on the terrain + /// Mouse position in world space on the terrain (max height 0) pub unprojected: Option, pub unprojected_normal: Option, diff --git a/native_app/src/rendering/map_rendering/map_mesh.rs b/native_app/src/rendering/map_rendering/map_mesh.rs index 630b3e3c..e870eea2 100644 --- a/native_app/src/rendering/map_rendering/map_mesh.rs +++ b/native_app/src/rendering/map_rendering/map_mesh.rs @@ -832,7 +832,7 @@ fn inter_pylon( ) { let interpos = inter.pos.up(ROAD_Z_OFFSET); - let h = unwrap_ret!(env.height(inter.pos.xy())); + let h = unwrap_ret!(env.true_height(inter.pos.xy())); if (h - interpos.z).abs() <= 2.0 { return; } diff --git a/simulation/src/map/objects/road.rs b/simulation/src/map/objects/road.rs index 75899879..5e4c224e 100644 --- a/simulation/src/map/objects/road.rs +++ b/simulation/src/map/objects/road.rs @@ -261,7 +261,7 @@ impl Road { interfaced_points .equipoints_dir(80.0, true) .filter_map(move |(pos, dir)| { - let h = env.height(pos.xy())?; + let h = env.true_height(pos.xy())?; if (h - pos.z).abs() <= 2.0 { return None; } @@ -331,13 +331,10 @@ impl Road { ) .chain(std::iter::once(p.last())) { - let h = env - .height(pos) - .unwrap_or_else(|| { - height_error = true; - 0.0 - }) - .max(0.0); + let h = env.height(pos).unwrap_or_else(|| { + height_error = true; + 0.0 + }); contour.push(h); points.push(pos.z(h)); } diff --git a/simulation/src/map/terrain.rs b/simulation/src/map/terrain.rs index 55ffb8e7..e57c14aa 100644 --- a/simulation/src/map/terrain.rs +++ b/simulation/src/map/terrain.rs @@ -73,7 +73,13 @@ impl Environment { me } + /// Returns the height of the terrain at the given position in meters, capped at 0 pub fn height(&self, pos: Vec2) -> Option { + self.heightmap.height(pos).map(|x| x.max(0.0)) + } + + /// Returns the height of the terrain at the given position in meters, not capped at 0 (can be negative in water) + pub fn true_height(&self, pos: Vec2) -> Option { self.heightmap.height(pos) }