common: Ray

This commit is contained in:
Quaternions 2025-02-20 09:29:49 -08:00
parent 510aef07a8
commit b0e0bda101
4 changed files with 114 additions and 120 deletions
engine/physics/src
lib/common/src

@ -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,

@ -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);
}

@ -1,5 +1,6 @@
pub mod bvh;
pub mod map;
pub mod ray;
pub mod run;
pub mod aabb;
pub mod model;

20
lib/common/src/ray.rs Normal file

@ -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())
}
}