From b0e0bda101594ff48d6486c099b1483ac8b45214 Mon Sep 17 00:00:00 2001 From: Quaternions <krakow20@gmail.com> Date: Thu, 20 Feb 2025 09:29:49 -0800 Subject: [PATCH] common: Ray --- engine/physics/src/push_solve.rs | 22 +--- lib/common/src/bvh.rs | 191 +++++++++++++++---------------- lib/common/src/lib.rs | 1 + lib/common/src/ray.rs | 20 ++++ 4 files changed, 114 insertions(+), 120 deletions(-) create mode 100644 lib/common/src/ray.rs diff --git a/engine/physics/src/push_solve.rs b/engine/physics/src/push_solve.rs index a40eaa8..5b1c5a7 100644 --- a/engine/physics/src/push_solve.rs +++ b/engine/physics/src/push_solve.rs @@ -1,4 +1,6 @@ -use strafesnet_common::integer::{self,vec3::{self,Vector3},Fixed,Planar64,Planar64Vec3,Ratio}; +use strafesnet_common::integer::vec3::{self,Vector3}; +use strafesnet_common::integer::{Fixed,Planar64Vec3,Ratio}; +use strafesnet_common::ray::Ray; // This algorithm is based on Lua code // written by Trey Reynolds in 2021 @@ -12,24 +14,6 @@ type Conts<'a>=arrayvec::ArrayVec<&'a Contact,4>; // hack to allow comparing ratios to zero const RATIO_ZERO:Ratio<Fixed<1,32>,Fixed<1,32>>=Ratio::new(Fixed::ZERO,Fixed::EPSILON); -struct Ray{ - origin:Planar64Vec3, - direction:Planar64Vec3, -} -impl Ray{ - fn extrapolate<Num,Den,N1,T1>(&self,t:Ratio<Num,Den>)->Planar64Vec3 - where - Num:Copy, - Den:Copy, - Num:core::ops::Mul<Planar64,Output=N1>, - Planar64:core::ops::Mul<Den,Output=N1>, - N1:integer::Divide<Den,Output=T1>, - T1:integer::Fix<Planar64>, - { - self.origin+self.direction.map(|elem|(t*elem).divide().fix()) - } -} - /// Information about a contact restriction pub struct Contact{ pub position:Planar64Vec3, diff --git a/lib/common/src/bvh.rs b/lib/common/src/bvh.rs index 5309ae4..836cf8c 100644 --- a/lib/common/src/bvh.rs +++ b/lib/common/src/bvh.rs @@ -1,11 +1,9 @@ use std::cmp::Ordering; use std::collections::BTreeMap; -use fixed_wide::fixed::Fixed; -use linear_ops::types::Vector3; - use crate::aabb::Aabb; -use crate::integer::{Ratio,Planar64,Planar64Vec3}; +use crate::ray::Ray; +use crate::integer::{Ratio,Planar64}; use crate::instruction::{InstructionCollector,TimedInstruction}; //da algaritum @@ -18,103 +16,94 @@ use crate::instruction::{InstructionCollector,TimedInstruction}; //sort the centerpoints on each axis (3 lists) //bv is put into octant based on whether it is upper or lower in each list -pub struct Ray{ - pub origin:Planar64Vec3, - pub direction:Planar64Vec3, -} -impl Ray{ - pub fn extrapolate(&self,t:Ratio<Planar64,Planar64>)->Ratio<Vector3<Fixed<2,64>>,Planar64>{ - // o+d*t - (self.origin*t.den+self.direction*t.num)/t.den + +pub fn intersect_aabb(ray:&Ray,aabb:&Aabb)->Option<Ratio<Planar64,Planar64>>{ + // n.(o+d*t)==n.p + // n.o + n.d * t == n.p + // t == (n.p - n.o)/n.d + let mut hit=None; + match ray.direction.x.cmp(&Planar64::ZERO){ + Ordering::Less=>{ + let rel_min=aabb.min()-ray.origin; + let rel_max=aabb.max()-ray.origin; + let dy=rel_max.x*ray.direction.y; + let dz=rel_max.x*ray.direction.z; + // x is negative, so inequalities are flipped + if rel_min.y*ray.direction.x>dy&&dy>rel_max.y*ray.direction.x + &&rel_min.z*ray.direction.x>dz&&dz>rel_max.z*ray.direction.x{ + let t=rel_max.x/ray.direction.x; + hit=Some(hit.map_or(t,|best_t|t.min(best_t))); + } + }, + Ordering::Equal=>(), + Ordering::Greater=>{ + let rel_min=aabb.min()-ray.origin; + let rel_max=aabb.max()-ray.origin; + let dy=rel_min.x*ray.direction.y; + let dz=rel_min.x*ray.direction.z; + // x is positive, so inequalities are normal + if rel_min.y*ray.direction.x<dy&&dy<rel_max.y*ray.direction.x + &&rel_min.z*ray.direction.x<dz&&dz<rel_max.z*ray.direction.x{ + let t=rel_min.x/ray.direction.x; + hit=Some(hit.map_or(t,|best_t|t.min(best_t))); + } + }, } - pub fn intersect_aabb(&self,aabb:&Aabb)->Option<Ratio<Planar64,Planar64>>{ - // n.(o+d*t)==n.p - // n.o + n.d * t == n.p - // t == (n.p - n.o)/n.d - let mut hit=None; - match self.direction.x.cmp(&Planar64::ZERO){ - Ordering::Less=>{ - let rel_min=aabb.min()-self.origin; - let rel_max=aabb.max()-self.origin; - let dy=rel_max.x*self.direction.y; - let dz=rel_max.x*self.direction.z; - // x is negative, so inequalities are flipped - if rel_min.y*self.direction.x>dy&&dy>rel_max.y*self.direction.x - &&rel_min.z*self.direction.x>dz&&dz>rel_max.z*self.direction.x{ - let t=rel_max.x/self.direction.x; - hit=Some(hit.map_or(t,|best_t|t.min(best_t))); - } - }, - Ordering::Equal=>(), - Ordering::Greater=>{ - let rel_min=aabb.min()-self.origin; - let rel_max=aabb.max()-self.origin; - let dy=rel_min.x*self.direction.y; - let dz=rel_min.x*self.direction.z; - // x is positive, so inequalities are normal - if rel_min.y*self.direction.x<dy&&dy<rel_max.y*self.direction.x - &&rel_min.z*self.direction.x<dz&&dz<rel_max.z*self.direction.x{ - let t=rel_min.x/self.direction.x; - hit=Some(hit.map_or(t,|best_t|t.min(best_t))); - } - }, - } - match self.direction.z.cmp(&Planar64::ZERO){ - Ordering::Less=>{ - let rel_min=aabb.min()-self.origin; - let rel_max=aabb.max()-self.origin; - let dx=rel_max.z*self.direction.x; - let dy=rel_max.z*self.direction.y; - // z is negative, so inequalities are flipped - if rel_min.x*self.direction.z>dx&&dx>rel_max.x*self.direction.z - &&rel_min.y*self.direction.z>dy&&dy>rel_max.y*self.direction.z{ - let t=rel_max.z/self.direction.z; - hit=Some(hit.map_or(t,|best_t|t.min(best_t))); - } - }, - Ordering::Equal=>(), - Ordering::Greater=>{ - let rel_min=aabb.min()-self.origin; - let rel_max=aabb.max()-self.origin; - let dx=rel_min.z*self.direction.x; - let dy=rel_min.z*self.direction.y; - // z is positive, so inequalities are normal - if rel_min.x*self.direction.z<dx&&dx<rel_max.x*self.direction.z - &&rel_min.y*self.direction.z<dy&&dy<rel_max.y*self.direction.z{ - let t=rel_min.z/self.direction.z; - hit=Some(hit.map_or(t,|best_t|t.min(best_t))); - } - }, - } - match self.direction.y.cmp(&Planar64::ZERO){ - Ordering::Less=>{ - let rel_min=aabb.min()-self.origin; - let rel_max=aabb.max()-self.origin; - let dz=rel_max.y*self.direction.z; - let dx=rel_max.y*self.direction.x; - // y is negative, so inequalities are flipped - if rel_min.z*self.direction.y>dz&&dz>rel_max.z*self.direction.y - &&rel_min.x*self.direction.y>dx&&dx>rel_max.x*self.direction.y{ - let t=rel_max.y/self.direction.y; - hit=Some(hit.map_or(t,|best_t|t.min(best_t))); - } - }, - Ordering::Equal=>(), - Ordering::Greater=>{ - let rel_min=aabb.min()-self.origin; - let rel_max=aabb.max()-self.origin; - let dz=rel_min.y*self.direction.z; - let dx=rel_min.y*self.direction.x; - // y is positive, so inequalities are normal - if rel_min.z*self.direction.y<dz&&dz<rel_max.z*self.direction.y - &&rel_min.x*self.direction.y<dx&&dx<rel_max.x*self.direction.y{ - let t=rel_min.y/self.direction.y; - hit=Some(hit.map_or(t,|best_t|t.min(best_t))); - } - }, - } - hit + match ray.direction.z.cmp(&Planar64::ZERO){ + Ordering::Less=>{ + let rel_min=aabb.min()-ray.origin; + let rel_max=aabb.max()-ray.origin; + let dx=rel_max.z*ray.direction.x; + let dy=rel_max.z*ray.direction.y; + // z is negative, so inequalities are flipped + if rel_min.x*ray.direction.z>dx&&dx>rel_max.x*ray.direction.z + &&rel_min.y*ray.direction.z>dy&&dy>rel_max.y*ray.direction.z{ + let t=rel_max.z/ray.direction.z; + hit=Some(hit.map_or(t,|best_t|t.min(best_t))); + } + }, + Ordering::Equal=>(), + Ordering::Greater=>{ + let rel_min=aabb.min()-ray.origin; + let rel_max=aabb.max()-ray.origin; + let dx=rel_min.z*ray.direction.x; + let dy=rel_min.z*ray.direction.y; + // z is positive, so inequalities are normal + if rel_min.x*ray.direction.z<dx&&dx<rel_max.x*ray.direction.z + &&rel_min.y*ray.direction.z<dy&&dy<rel_max.y*ray.direction.z{ + let t=rel_min.z/ray.direction.z; + hit=Some(hit.map_or(t,|best_t|t.min(best_t))); + } + }, } + match ray.direction.y.cmp(&Planar64::ZERO){ + Ordering::Less=>{ + let rel_min=aabb.min()-ray.origin; + let rel_max=aabb.max()-ray.origin; + let dz=rel_max.y*ray.direction.z; + let dx=rel_max.y*ray.direction.x; + // y is negative, so inequalities are flipped + if rel_min.z*ray.direction.y>dz&&dz>rel_max.z*ray.direction.y + &&rel_min.x*ray.direction.y>dx&&dx>rel_max.x*ray.direction.y{ + let t=rel_max.y/ray.direction.y; + hit=Some(hit.map_or(t,|best_t|t.min(best_t))); + } + }, + Ordering::Equal=>(), + Ordering::Greater=>{ + let rel_min=aabb.min()-ray.origin; + let rel_max=aabb.max()-ray.origin; + let dz=rel_min.y*ray.direction.z; + let dx=rel_min.y*ray.direction.x; + // y is positive, so inequalities are normal + if rel_min.z*ray.direction.y<dz&&dz<rel_max.z*ray.direction.y + &&rel_min.x*ray.direction.y<dx&&dx<rel_max.x*ray.direction.y{ + let t=rel_min.y/ray.direction.y; + hit=Some(hit.map_or(t,|best_t|t.min(best_t))); + } + }, + } + hit } pub enum RecursiveContent<N,L>{ @@ -171,7 +160,7 @@ impl<L> BvhNode<L>{ child.populate_nodes(collector,nodes,ray,start_time,f); }else{ // Am I an upcoming superstar? - if let Some(t)=ray.intersect_aabb(&child.aabb){ + if let Some(t)=intersect_aabb(ray,&child.aabb){ if start_time.lt_ratio(t)&&t.lt_ratio(collector.time()){ nodes.insert(t,child); } @@ -212,7 +201,7 @@ impl<L> BvhNode<L>{ // break open the node and predict collisions with the child nodes RecursiveContent::Branch(children)=>for child in children{ // Am I an upcoming superstar? - if let Some(t)=ray.intersect_aabb(&child.aabb){ + if let Some(t)=intersect_aabb(ray,&child.aabb){ if t<collector.time(){ nodes.insert(t,child); } diff --git a/lib/common/src/lib.rs b/lib/common/src/lib.rs index 69a3501..e6364ba 100644 --- a/lib/common/src/lib.rs +++ b/lib/common/src/lib.rs @@ -1,5 +1,6 @@ pub mod bvh; pub mod map; +pub mod ray; pub mod run; pub mod aabb; pub mod model; diff --git a/lib/common/src/ray.rs b/lib/common/src/ray.rs new file mode 100644 index 0000000..fe16127 --- /dev/null +++ b/lib/common/src/ray.rs @@ -0,0 +1,20 @@ +use ratio_ops::ratio::Ratio; +use crate::integer::{self,Planar64,Planar64Vec3}; + +pub struct Ray{ + pub origin:Planar64Vec3, + pub direction:Planar64Vec3, +} +impl Ray{ + pub fn extrapolate<Num,Den,N1,T1>(&self,t:Ratio<Num,Den>)->Planar64Vec3 + where + Num:Copy, + Den:Copy, + Num:core::ops::Mul<Planar64,Output=N1>, + Planar64:core::ops::Mul<Den,Output=N1>, + N1:integer::Divide<Den,Output=T1>, + T1:integer::Fix<Planar64>, + { + self.origin+self.direction.map(|elem|(t*elem).divide().fix()) + } +}