refactor ray collisions to return face normal

This commit is contained in:
Lillian Vixe 2024-03-21 09:16:07 -07:00
parent 471ce62c35
commit 2fe1812f35

View file

@ -602,7 +602,7 @@ pub fn ray_obb_intersection(
ray_origin: Vec3,
ray_direction_normalized: Vec3,
bounds: &OBB,
) -> Option<Vec3> {
) -> Option<RayBoundsIntersection> {
let transform: Transform = Transform::from_translation(bounds.position)
.with_rotation(bounds.orientation)
.with_scale(bounds.half_size * 2.);
@ -612,8 +612,26 @@ pub fn ray_obb_intersection(
let passthru =
distance_to_ray_bounds_intersection(ro_trans, rd_trans, Vec3::ZERO, Vec3::splat(0.5));
if passthru.is_some() {
let unwrapped = passthru.unwrap();
return Some(ray_origin + (ray_direction_normalized * unwrapped));
let hitpoint = ray_origin + (ray_direction_normalized * passthru.unwrap());
let mut dist_array: [(Vec3, f32); 6] = Default::default();
let mut min_dist: usize = 8;
for (index, norm) in constants::cardinal_directions::ORDERED.iter().enumerate() {
let pos = norm.clone() * bounds.half_size * 2.;
let pos = pos + bounds.position;
let pos = matrix.transform_vector3(pos);
let dist = pos.distance(hitpoint);
dist_array[index] = (norm.clone(), dist);
if index == 0 {
min_dist = index;
} else if dist_array[min_dist].1 > dist {
min_dist = index;
}
}
let normal = dist_array[min_dist].0;
return Some(RayBoundsIntersection {
hitpoint: hitpoint,
untransformed_normal: normal,
});
} else {
return None;
}
@ -662,13 +680,18 @@ pub fn ray_sphere_intersection(
return Some(ray_origin + (ray_direction_normalized * t));
}
#[derive(Clone)]
pub struct RayBoundsIntersection {
hitpoint: Vec3,
untransformed_normal: Vec3,
}
pub fn ray_aabb_intersection(
ray_origin: Vec3,
ray_direction_normalized: Vec3,
bound_center: Vec3,
bound_half_size: Vec3,
) -> Option<Vec3> {
) -> Option<RayBoundsIntersection> {
let passthru = distance_to_ray_bounds_intersection(
ray_origin,
ray_direction_normalized,
@ -676,7 +699,25 @@ pub fn ray_aabb_intersection(
bound_half_size,
);
if passthru.is_some() {
return Some(ray_origin + (ray_direction_normalized * passthru.unwrap()));
let hitpoint = ray_origin + (ray_direction_normalized * passthru.unwrap());
let mut dist_array: [(Vec3, f32); 6] = Default::default();
let mut min_dist: usize = 8;
for (index, norm) in constants::cardinal_directions::ORDERED.iter().enumerate() {
let pos = norm.clone() * bound_half_size * 2.;
let pos = pos + bound_center;
let dist = pos.distance(hitpoint);
dist_array[index] = (norm.clone(), dist);
if index == 0 {
min_dist = index;
} else if dist_array[min_dist].1 > dist {
min_dist = index;
}
}
let normal = dist_array[min_dist].0;
return Some(RayBoundsIntersection {
hitpoint: hitpoint,
untransformed_normal: normal,
});
} else {
return None;
}
@ -720,7 +761,7 @@ pub fn sphere_obb_intersection(
None
}
#[derive(Debug)]
#[derive(Debug, PartialEq)]
pub struct OctTreeCollisionPoint {
pos_in_oct: Vec3,
pos_in_global: Vec3,
@ -1048,7 +1089,7 @@ mod constants {
pub const PPP: Vec3 = Vec3::new(1., 1., 1.);
pub const ORDERED: [Vec3; 8] = [NNN, NNP, NPN, NPP, PNN, PNP, PPN, PPP];
}
mod cardinal_directions {
pub(crate) mod cardinal_directions {
use bevy::math::Vec3;
pub const PX: Vec3 = Vec3::X;
pub const NX: Vec3 = Vec3::NEG_X;
@ -1056,6 +1097,7 @@ mod constants {
pub const NY: Vec3 = Vec3::NEG_Y;
pub const PZ: Vec3 = Vec3::Z;
pub const NZ: Vec3 = Vec3::NEG_Z;
pub const ORDERED: [Vec3; 6] = [PX, NX, PY, NY, PZ, NZ];
}
}
@ -1216,21 +1258,30 @@ pub fn test_ray_x_bounding_collisions() {
Quat::from_rotation_z(f32::to_radians(90.)),
Vec3::splat(5.),
);
let aabb_test: Option<Vec3> =
let aabb_test: Option<RayBoundsIntersection> =
ray_aabb_intersection(Vec3::ZERO, Vec3::X, abounds.position, abounds.half_size);
let obb_test: Option<Vec3> = ray_obb_intersection(Vec3::ZERO, Vec3::X, &abounds);
let obb_test: Option<RayBoundsIntersection> =
ray_obb_intersection(Vec3::ZERO, Vec3::X, &abounds);
assert_eq!(aabb_test.unwrap(), Vec3::new(5., 0., 0.));
assert_eq!(aabb_test.clone().unwrap().hitpoint, Vec3::new(5., 0., 0.));
assert_eq!(
aabb_test.unwrap().untransformed_normal,
Vec3::new(-1., 0., 0.)
);
assert_eq!(obb_test.unwrap().round(), Vec3::new(5., 0., 0.));
assert_eq!(obb_test.unwrap().hitpoint.round(), Vec3::new(5., 0., 0.));
let rotated_bounds: OBB = OBB::new(
Vec3::new(20., 0., 0.),
Quat::from_rotation_z(f32::to_radians(45.0)),
Quat::from_rotation_z(f32::to_radians(-50.0)),
Vec3::splat(5.),
);
let rotated_obb_test = ray_obb_intersection(Vec3::ZERO, Vec3::X, &rotated_bounds).unwrap();
assert_eq!(rotated_obb_test.round().x, 13.);
assert_eq!(rotated_obb_test.hitpoint.round().x, 13.);
assert_eq!(
rotated_obb_test.untransformed_normal,
Vec3::new(0., -1., 0.)
);
}
#[test]
@ -1267,10 +1318,10 @@ pub fn test_oct_x_oct_collisions() {
);
assert!(x.is_some());
let mut oct1 = OctTree::new(Vec3::splat(1.), 10);
let mut oct1 = OctTree::new(Vec3::splat(10.), 10);
oct1.set_voxel_at_location(Vec3::new(1., 0., 1.), 1);
let mut oct2 = OctTree::new(Vec3::splat(0.), 10);
oct2.set_voxel_at_location(Vec3::new(0., 1., 0.), 1);
oct2.set_voxel_at_location(Vec3::new(0., 10., 0.), 1);
let x = octtree_overlap(
&oct1,
@ -1283,8 +1334,69 @@ pub fn test_oct_x_oct_collisions() {
),
);
assert!(x.is_some());
dbg!(&x.unwrap());
panic!();
let x = x.unwrap();
//dbg!(&x);
assert_eq!(
x[0],
(
OctTreeCollisionPoint {
pos_in_oct: Vec3::new(1.0, 0.0, 1.0,),
pos_in_global: Vec3::new(1.0, 0.0, 1.0,),
path: Path {
packed: 0,
length: 0,
},
},
OctTreeCollisionPoint {
pos_in_oct: Vec3::new(0.0, 0.0, 0.0,),
pos_in_global: Vec3::new(0.0, 0.0, 0.0,),
path: Path {
packed: 0,
length: 0,
},
},
),
);
{
let mut oct1 = OctTree::new(Vec3::splat(10.), 10);
let mut oct2 = OctTree::new(Vec3::splat(-10.), 10);
oct1.set_voxel_at_location(Vec3::splat(1.), 1);
oct2.set_voxel_at_location(Vec3::splat(1.), 1);
let orient1 = OBB::new(
Vec3::splat(5.),
Quat::from_rotation_x(f32::to_radians(10.)),
Vec3::splat(1.),
);
let orient2 = OBB::new(
Vec3::splat(5.),
Quat::from_rotation_x(f32::to_radians(-10.)),
Vec3::splat(1.),
);
let x = octtree_overlap(&oct1, &orient1, &oct2, &orient2);
assert!(x.is_some());
assert_eq!(
x.unwrap()[0],
(
OctTreeCollisionPoint {
pos_in_oct: Vec3::new(1.0, 1.0, 1.0,),
pos_in_global: Vec3::new(7.0, 6.622319, 7.3169117,),
path: Path {
packed: 0,
length: 0,
},
},
OctTreeCollisionPoint {
pos_in_oct: Vec3::new(1.0, 1.0, 1.0,),
pos_in_global: Vec3::new(7.0, 7.3169117, 6.622319,),
path: Path {
packed: 0,
length: 0,
},
},
)
);
}
}
/*
use rand::Rng;