45 lines
1.2 KiB
Rust
45 lines
1.2 KiB
Rust
use crate::mesh_loader::Face;
|
|
use glam::{mat3, Vec3};
|
|
|
|
pub type Mesh = [Face];
|
|
|
|
pub struct TraceResult {
|
|
pub distance: f32,
|
|
pub normal: Vec3,
|
|
}
|
|
|
|
pub fn trace_to_mesh_all(
|
|
mesh: &Mesh,
|
|
base: Vec3,
|
|
ray: Vec3,
|
|
) -> impl Iterator<Item = TraceResult> + '_ {
|
|
mesh.iter().filter_map(move |f| {
|
|
let fs = (0..3).map(|k| edge_dist(f.vertices[k], f.vertices[(k + 1) % 3], base, ray));
|
|
if fs.into_iter().any(|f| f < 0.0) {
|
|
return None;
|
|
}
|
|
let m = mat3(
|
|
f.vertices[1] - f.vertices[0],
|
|
f.vertices[2] - f.vertices[0],
|
|
-ray,
|
|
);
|
|
let m = m.inverse();
|
|
let rel = m * (base - f.vertices[0]);
|
|
Some(TraceResult {
|
|
distance: rel.z,
|
|
normal: f.normal,
|
|
})
|
|
})
|
|
}
|
|
|
|
pub fn trace_to_mesh(mesh: &Mesh, base: Vec3, ray: Vec3) -> Option<TraceResult> {
|
|
trace_to_mesh_all(mesh, base, ray)
|
|
.filter(|tr| tr.distance >= 0.0)
|
|
.min_by(|a, b| a.distance.total_cmp(&b.distance))
|
|
}
|
|
|
|
fn edge_dist(a: Vec3, b: Vec3, base: Vec3, dir: Vec3) -> f32 {
|
|
// Note: given that the input is not arbitrary but comes from a cartesian product of certain (a, b) pairs and certain (base, dir) pairs, this can be optimized from Cnm to an+bm+cnm with c<C.
|
|
mat3(b - a, base - a, -dir).determinant()
|
|
}
|