Skip to content

Commit

Permalink
implement raycast on heightmap and aabb
Browse files Browse the repository at this point in the history
  • Loading branch information
Uriopass committed Dec 14, 2023
1 parent 19fa56b commit b5e01c5
Show file tree
Hide file tree
Showing 8 changed files with 266 additions and 49 deletions.
2 changes: 1 addition & 1 deletion engine_demo/src/helmet.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl DemoElement for Helmet {
Self { mesh: Some(mesh) }
}

fn update(&mut self, _ctx: &mut Context) {}
fn update(&mut self, _ctx: &mut Context, _cam: &Camera) {}

fn render(&mut self, fc: &mut FrameContext, _cam: &Camera, _frustrum: &InfiniteFrustrum) {
fc.draw(self.mesh.clone());
Expand Down
4 changes: 2 additions & 2 deletions engine_demo/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ trait DemoElement {
fn init(ctx: &mut Context) -> Self
where
Self: Sized;
fn update(&mut self, ctx: &mut Context);
fn update(&mut self, ctx: &mut Context, cam: &Camera);
fn render(&mut self, fc: &mut FrameContext, cam: &Camera, frustrum: &InfiniteFrustrum);
fn render_gui(&mut self, _ui: &mut egui::Ui) {}
}
Expand Down Expand Up @@ -144,7 +144,7 @@ impl engine::framework::State for State {
if !*enabled {
continue;
}
de.update(ctx);
de.update(ctx, &self.camera);
}

for v in self.play_queue.drain(..) {
Expand Down
2 changes: 1 addition & 1 deletion engine_demo/src/spheres.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ impl DemoElement for Spheres {
Self { meshes }
}

fn update(&mut self, _ctx: &mut Context) {}
fn update(&mut self, _ctx: &mut Context, _cam: &Camera) {}

fn render(&mut self, fc: &mut FrameContext, _cam: &Camera, _frustrum: &InfiniteFrustrum) {
fc.draw(self.meshes.clone());
Expand Down
68 changes: 56 additions & 12 deletions engine_demo/src/terrain.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,21 @@
use crate::DemoElement;
use engine::meshload::load_mesh;
use engine::terrain::TerrainRender as EngineTerrainRender;
use engine::{Context, FrameContext};
use geom::{vec2, Camera, InfiniteFrustrum};
use engine::{Context, FrameContext, InstancedMeshBuilder, MeshInstance};
use geom::{vec2, Camera, Heightmap, HeightmapChunk, InfiniteFrustrum, LinearColor, Vec3};

const CSIZE: usize = 512;
const CRESO: usize = 16;
const MAP_SIZE: usize = 50;

pub struct Terrain {
terrain: EngineTerrainRender<CSIZE, CRESO>,
_heights: Box<[[[[f32; CRESO]; CRESO]; MAP_SIZE]; MAP_SIZE]>,
heights: Heightmap<CRESO, { CSIZE as u32 }>,
reload: bool,

last_hitpos: Option<Vec3>,
plane_hitpos: Option<Vec3>,
hitmesh: InstancedMeshBuilder<false>,
}

impl DemoElement for Terrain {
Expand All @@ -21,17 +26,16 @@ impl DemoElement for Terrain {
fn init(ctx: &mut Context) -> Self {
let gfx = &mut ctx.gfx;

let mut heights: Box<[[[[f32; CRESO]; CRESO]; MAP_SIZE]; MAP_SIZE]> =
vec![[[[0.0; CRESO]; CRESO]; MAP_SIZE]; MAP_SIZE]
.into_boxed_slice()
.try_into()
.unwrap();
let hitmesh = load_mesh(gfx, "sphere.glb").unwrap();

let mut h = Heightmap::new(MAP_SIZE as u16, MAP_SIZE as u16);

for y in 0..MAP_SIZE {
for x in 0..MAP_SIZE {
let mut c = [[0.0; CRESO]; CRESO];
for i in 0..CRESO {
for j in 0..CRESO {
heights[y][x][i][j] = 3000.0
c[i][j] = 3000.0
* geom::fnoise::<6>(
0.002 * vec2((x * CRESO + j) as f32, (y * CRESO + i) as f32),
)
Expand All @@ -41,6 +45,7 @@ impl DemoElement for Terrain {
// (CSIZE / CRESO * i) as f32 + 0.5 * (CSIZE / CRESO * j) as f32;
}
}
h.set_chunk((x as u16, y as u16), HeightmapChunk::new(c));
}
}

Expand All @@ -50,28 +55,67 @@ impl DemoElement for Terrain {

for x in 0..MAP_SIZE {
for y in 0..MAP_SIZE {
terrain.update_chunk(gfx, (x as u32, y as u32), &heights[y][x]);
terrain.update_chunk(
gfx,
(x as u32, y as u32),
&h.get_chunk((x as u16, y as u16)).unwrap().heights(),
);
}
}

terrain.invalidate_height_normals(&ctx.gfx);

Self {
terrain,
_heights: heights,
heights: h,
reload: false,
last_hitpos: None,
plane_hitpos: None,
hitmesh: InstancedMeshBuilder::new(hitmesh),
}
}

fn update(&mut self, ctx: &mut Context) {
fn update(&mut self, ctx: &mut Context, cam: &Camera) {
if self.reload {
self.reload = false;
self.terrain.invalidate_height_normals(&ctx.gfx);
}

self.last_hitpos = None;
self.plane_hitpos = None;
if let Some(unproj) = cam.unproj_ray(ctx.input.mouse.screen) {
let p = geom::Plane { n: Vec3::Z, o: 0.0 };
if let Some(mut v) = unproj.intersection_plane(&p) {
v.z = self.heights.height(v.xy()).unwrap_or(0.0);
self.plane_hitpos = Some(v);
}

if let Some((hitpos, _hitnormal)) = self.heights.raycast(unproj) {
self.last_hitpos = Some(hitpos);
}
}
}

fn render(&mut self, fc: &mut FrameContext, cam: &Camera, frustrum: &InfiniteFrustrum) {
self.terrain.draw_terrain(cam, frustrum, fc);

self.hitmesh.instances.clear();
if let Some(pos) = self.last_hitpos {
self.hitmesh.instances.push(MeshInstance {
pos,
dir: Vec3::X * 20.0,
tint: LinearColor::WHITE,
});
}
if let Some(pos) = self.plane_hitpos {
self.hitmesh.instances.push(MeshInstance {
pos,
dir: Vec3::X * 10.0,
tint: LinearColor::RED,
});
}

fc.draw(self.hitmesh.build(fc.gfx));
}

fn render_gui(&mut self, ui: &mut egui::Ui) {
Expand Down
20 changes: 19 additions & 1 deletion geom/src/aabb3.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use super::Vec3;
use super::{Ray3, Vec3};
use crate::{Intersect3, Shape3, AABB};
use serde::{Deserialize, Serialize};

Expand Down Expand Up @@ -106,6 +106,24 @@ impl AABB3 {
&& point.z <= self.ur.z + tolerance
&& point.z >= self.ll.z - tolerance
}

/// as ray is defined by O + tD, return the t values for the entering and exiting intersections
/// Returns a 2-tuple of (t_near, t_far)
/// Adapted from https://gist.github.com/DomNomNom/46bb1ce47f68d255fd5d
/// If the ray origin is inside the box, t_near will be zero
#[inline]
pub fn raycast(&self, ray: Ray3) -> Option<(f32, f32)> {
let t_min = (self.ll - ray.from) / ray.dir;
let t_max = (self.ur - ray.from) / ray.dir;
let t1 = t_min.min(t_max);
let t2 = t_min.max(t_max);
let t_near = f32::max(f32::max(t1.x, t1.y), t1.z);
let t_far = f32::min(f32::min(t2.x, t2.y), t2.z);
if t_near >= t_far || t_far < 0.0 {
return None;
}
Some((t_near.max(0.0), t_far))
}
}

impl Intersect3<AABB3> for AABB3 {
Expand Down
Loading

0 comments on commit b5e01c5

Please sign in to comment.