Record relative ray direction on hit

This commit is contained in:
numzero 2024-06-10 23:30:38 +03:00
parent d5c2e34157
commit fdc4e22da0

View File

@ -133,7 +133,7 @@ struct Hit {
distance: f32, distance: f32,
id: i32, id: i32,
pos: Vec2, // положение в основной СК pos: Vec2, // положение в основной СК
rel: Vec2, // положение в локальной ортонормированной СК объекта rel: Ray, // в локальной ортонормированной СК объекта
} }
struct HitInternal<'a> { struct HitInternal<'a> {
@ -200,8 +200,10 @@ impl Space {
objects: hits.into_iter().filter_map(|HitInternal { object, distance }| objects: hits.into_iter().filter_map(|HitInternal { object, distance }|
if distance < dist { if distance < dist {
let pos = ray.forward(distance).pos; let pos = ray.forward(distance).pos;
// NB: object.loc.rot задан относительно object.loc.pos, поэтому и ray_to_global надо делать относительно object.loc.pos, а не pos.
let rel = object.loc.rot.inverse() * cell.ray_to_global(Ray { pos: object.loc.pos, dir: pos - object.loc.pos }).dir; let rel = object.loc.rot.inverse() * cell.ray_to_global(Ray { pos: object.loc.pos, dir: pos - object.loc.pos }).dir;
Some(Hit { id: object.id, distance, pos: cell.pos_to_global(pos), rel }) let dir = object.loc.rot.inverse() * cell.ray_to_global(Ray { pos: object.loc.pos, dir: ray.dir }).dir;
Some(Hit { id: object.id, distance, pos: cell.pos_to_global(pos), rel: Ray { pos: rel, dir } })
} else { None } } else { None }
).collect(), ).collect(),
} }
@ -220,7 +222,8 @@ impl Space {
if distance < dist { if distance < dist {
let pos = ray.forward(distance).pos; let pos = ray.forward(distance).pos;
let rel = object.loc.rot.inverse() * (pos - object.loc.pos); let rel = object.loc.rot.inverse() * (pos - object.loc.pos);
Some(Hit { id: object.id, distance, pos, rel }) let dir = object.loc.rot.inverse() * ray.dir;
Some(Hit { id: object.id, distance, pos, rel: Ray { pos: rel, dir } })
} else { None } } else { None }
).collect(), ).collect(),
} }
@ -336,10 +339,20 @@ fn draw_ray_2(gc: &mut Vec<Draw>, space: &Space, base: Vec2, dir: Vec2) {
for hit in ret.objects { for hit in ret.objects {
let obj = space.objs[hit.id as usize]; let obj = space.objs[hit.id as usize];
hits.move_to(obj.loc.pos.x, obj.loc.pos.y); hits.move_to(obj.loc.pos.x, obj.loc.pos.y);
for pt in trace_iter(&space.rect, obj.loc.pos, obj.loc.rot * hit.rel, hit.rel.length() / 100.0).take(100) { for pt in trace_iter(&space.rect, obj.loc.pos, obj.loc.rot * hit.rel.pos, hit.rel.pos.length() / 100.0).take(100) {
hits.line_to(pt.x, pt.y); hits.line_to(pt.x, pt.y);
} }
hits.circle(hit.pos.x, hit.pos.y, 1.5); hits.circle(hit.pos.x, hit.pos.y, 1.5);
let Ray { pos: rel, dir } = hit.rel;
let diff = rel.dot(dir).powi(2) - dir.length_squared() * (rel.length_squared() - obj.r.powi(2));
assert!(diff >= 0.0);
let t = (-rel.dot(dir) + diff.sqrt()) / dir.length_squared();
let rel2 = hit.rel.forward(t).pos;
let pos2 = trace_iter(&space.rect, obj.loc.pos, obj.loc.rot * rel2, rel2.length() / 100.0).nth(100).unwrap();
hits.move_to(pos2.x - 1.0, pos2.y - 1.0);
hits.line_to(pos2.x + 1.0, pos2.y + 1.0);
hits.move_to(pos2.x - 1.0, pos2.y + 1.0);
hits.line_to(pos2.x + 1.0, pos2.y - 1.0);
} }
let a = ray.pos; let a = ray.pos;
ray = match ret.end { ray = match ret.end {