Trace all objects hit

This commit is contained in:
numzero 2024-06-10 00:35:33 +03:00
parent ab5446385b
commit 69cc1904a8

View File

@ -1,4 +1,3 @@
use std::cmp::Ordering;
use std::f32::consts::PI; use std::f32::consts::PI;
use flo_draw::*; use flo_draw::*;
use flo_canvas::*; use flo_canvas::*;
@ -125,10 +124,14 @@ enum Subspace {
Inner, Inner,
} }
enum FlatTraceResult { struct Hit {
Infinity(Vec2), distance: f32,
Edge(Ray), id: i32,
Object(Ray, i32), }
struct FlatTraceResult {
end: Option<Ray>,
objects: Vec<Hit>,
} }
impl Space { impl Space {
@ -178,24 +181,23 @@ impl Space {
let cell = RectInside { rect: self.rect }; let cell = RectInside { rect: self.rect };
let ray = cell.ray_to_local(ray); let ray = cell.ray_to_local(ray);
let dist = cell.to_boundary(ray).expect("Can't get outta here!"); let dist = cell.to_boundary(ray).expect("Can't get outta here!");
let ray = Ray { pos: ray.pos + ray.dir * dist, dir: ray.dir }; let ray = ray.forward(dist);
cell.ray_to_global(ray) cell.ray_to_global(ray)
} }
fn trace_outer(&self, ray: Ray) -> FlatTraceResult { fn trace_outer(&self, ray: Ray) -> FlatTraceResult {
assert_eq!(self.which_subspace(ray.pos), Outer); assert_eq!(self.which_subspace(ray.pos), Outer);
let cell = basic_shapes::Rect { size: vec2(self.rect.outer_radius, self.rect.external_halflength) }; let cell = basic_shapes::Rect { size: vec2(self.rect.outer_radius, self.rect.external_halflength) };
let obj = Self::trace_to_object(self.list_objects_outer(), ray); let objs = Self::trace_to_objects(self.list_objects_outer(), ray);
let sub = cell.trace_into(ray); if let Some(dist) = cell.trace_into(ray) {
let rray = |dist: f32| Ray { pos: ray.pos + ray.dir * dist, dir: ray.dir }; FlatTraceResult {
match (sub, obj) { end: Some(ray.forward(dist)),
(None, None) => FlatTraceResult::Infinity(ray.dir), objects: objs.into_iter().filter(|hit| hit.distance < dist).collect(),
(Some(dist), None) => FlatTraceResult::Edge(rray(dist)), }
(None, Some((id, dist))) => FlatTraceResult::Object(rray(dist), id), } else {
(Some(sdist), Some((id, odist))) => if sdist < odist { FlatTraceResult {
FlatTraceResult::Edge(rray(sdist)) end: None,
} else { objects: objs,
FlatTraceResult::Object(rray(odist), id)
} }
} }
} }
@ -211,7 +213,7 @@ impl Space {
self.objs.as_slice() self.objs.as_slice()
} }
fn trace_to_object(objs: &[Object], ray: Ray) -> Option<(i32, f32)> { fn trace_to_objects(objs: &[Object], ray: Ray) -> Vec<Hit> {
objs.iter() objs.iter()
.filter_map(|obj| { .filter_map(|obj| {
let rel = ray.pos - obj.loc.pos; let rel = ray.pos - obj.loc.pos;
@ -219,16 +221,16 @@ impl Space {
if diff > 0.0 { if diff > 0.0 {
let t = (-rel.dot(ray.dir) - diff.sqrt()) / ray.dir.length_squared(); let t = (-rel.dot(ray.dir) - diff.sqrt()) / ray.dir.length_squared();
if t >= 0.0 { if t >= 0.0 {
return Some((obj.id, t)); return Some(Hit { id: obj.id, distance: t });
} }
} }
None None
}) }).collect()
.min_by(|(_, d1), (_, d2)| f32::total_cmp(d1, d2))
} }
} }
fn draw_ray_2(gc: &mut Vec<Draw>, space: &Space, base: Vec2, dir: Vec2) { fn draw_ray_2(gc: &mut Vec<Draw>, space: &Space, base: Vec2, dir: Vec2) {
let mut hits = Vec::<Draw>::new();
let dir = space.rect.globalize(base, dir); let dir = space.rect.globalize(base, dir);
gc.new_path(); gc.new_path();
gc.move_to(base.x, base.y); gc.move_to(base.x, base.y);
@ -253,23 +255,18 @@ fn draw_ray_2(gc: &mut Vec<Draw>, space: &Space, base: Vec2, dir: Vec2) {
ray = space.trace_inner(ray); ray = space.trace_inner(ray);
} }
Outer => { Outer => {
ray = match space.trace_outer(ray) { let ret = space.trace_outer(ray);
FlatTraceResult::Edge(r) => r, for hit in ret.objects {
FlatTraceResult::Infinity(dir) => { let r = ray.forward(hit.distance);
ray.pos += dir * (1000.0 / DT); hits.circle(r.pos.x, r.pos.y, 1.5);
}
ray = match ret.end {
Some(r) => r,
None => {
ray = ray.forward(1000.0 / DT);
gc.line_to(ray.pos.x, ray.pos.y); gc.line_to(ray.pos.x, ray.pos.y);
gc.stroke();
break; break;
} }
FlatTraceResult::Object(r, id) => {
gc.line_to(r.pos.x, r.pos.y);
gc.stroke();
gc.new_path();
gc.new_dash_pattern();
gc.circle(r.pos.x, r.pos.y, 1.5);
gc.stroke();
r
}
}; };
} }
Boundary => panic!(), Boundary => panic!(),
@ -281,7 +278,10 @@ fn draw_ray_2(gc: &mut Vec<Draw>, space: &Space, base: Vec2, dir: Vec2) {
gc.move_to(ray.pos.x, ray.pos.y); gc.move_to(ray.pos.x, ray.pos.y);
} }
gc.stroke(); gc.stroke();
gc.new_path();
gc.new_dash_pattern(); gc.new_dash_pattern();
gc.append(&mut hits);
gc.stroke();
} }
fn draw_fan_2(gc: &mut Vec<Draw>, space: &Space, base: Vec2, dir: Vec2, spread: f32) { fn draw_fan_2(gc: &mut Vec<Draw>, space: &Space, base: Vec2, dir: Vec2, spread: f32) {
@ -367,6 +367,12 @@ struct Ray {
dir: Vec2, dir: Vec2,
} }
impl Ray {
fn forward(&self, dist: f32) -> Ray {
Ray { pos: self.pos + self.dir * dist, dir: self.dir }
}
}
mod basic_shapes { mod basic_shapes {
use glam::{Vec2, vec2}; use glam::{Vec2, vec2};
use crate::Ray; use crate::Ray;