use std::ops::Index; use na::{Point2, Vector3, Identity, Transform, Rotate, Norm}; use na; use ray::{Ray, RayCast, RayIntersection}; use ray; use entities::shape::{BaseMesh, BaseMeshElement, TriMesh, Polyline}; use entities::bounding_volume::AABB; use entities::partitioning::BVTCostFn; use math::{Point, Vector}; impl
RayCast
for BaseMesh
where P: Point, M: Transform
+ Rotate {
#[inline]
fn toi_with_ray(&self, m: &M, ray: &Ray , _: bool) -> Option< , _: bool) -> Option , solid: bool) -> Option () != 3 {
return self.toi_and_normal_with_ray(m, ray, solid);
}
let ls_ray = Ray::new(m.inverse_transform(&ray.origin), m.inverse_rotate(&ray.dir));
let mut cost_fn = BaseMeshRayToiAndNormalAndUVsCostFn { mesh: self, ray: &ls_ray };
let cast = self.bvt().best_first_search(&mut cost_fn);
match cast {
None => None,
Some((best, inter)) => {
let toi = inter.0.toi;
let n = inter.0.normal.clone();
let uv = inter.1; // barycentric coordinates to compute the exact uvs.
let idx = &self.indices()[*best];
let uvs = self.uvs().as_ref().unwrap();
let uv1 = uvs[idx[0]];
let uv2 = uvs[idx[1]];
let uv3 = uvs[idx[2]];
let uvx = uv1.x * uv.x + uv2.x * uv.y + uv3.x * uv.z;
let uvy = uv1.y * uv.x + uv2.y * uv.y + uv3.y * uv.z;
// XXX: this interpolation should be done on the two other ray cast too!
match *self.normals() {
None => {
Some(RayIntersection::new_with_uvs(toi, m.rotate(&n), Some(Point2::new(uvx, uvy))))
},
Some(ref ns) => {
let n1 = &ns[idx[0]];
let n2 = &ns[idx[1]];
let n3 = &ns[idx[2]];
let mut n123 = *n1 * uv.x + *n2 * uv.y + *n3 * uv.z;
if na::is_zero(&n123.normalize_mut()) {
Some(RayIntersection::new_with_uvs(toi, m.rotate(&n), Some(Point2::new(uvx, uvy))))
}
else {
if na::dot(&n123, &ls_ray.dir) > na::zero() {
Some(RayIntersection::new_with_uvs(toi, -m.rotate(&n123), Some(Point2::new(uvx, uvy))))
}
else {
Some(RayIntersection::new_with_uvs(toi, m.rotate(&n123), Some(Point2::new(uvx, uvy))))
}
}
}
}
}
}
}
}
/*
* Costs functions.
*/
struct BaseMeshRayToiCostFn<'a, P: 'a + Point, I: 'a, E: 'a> {
mesh: &'a BaseMesh ,
ray: &'a Ray
}
impl<'a, P, I, E> BVTCostFn< > for BaseMeshRayToiCostFn<'a, P, I, E>
where P: Point,
E: BaseMeshElement + RayCast {
type UserData = ) -> Option< ,
ray: &'a Ray
}
impl<'a, P, I, E> BVTCostFn< > for BaseMeshRayToiAndNormalCostFn<'a, P, I, E>
where P: Point,
E: BaseMeshElement + RayCast {
type UserData = RayIntersection ) -> Option< ,
ray: &'a Ray
}
impl<'a, P, I, E> BVTCostFn< >
for BaseMeshRayToiAndNormalAndUVsCostFn<'a, P, I, E>
where P: Point,
I: Index {
type UserData = (RayIntersection ) -> Option< RayCast for TriMesh
where P: Point,
M: Transform + Rotate , solid: bool) -> Option< , solid: bool) -> Option , solid: bool) -> Option RayCast for Polyline
where P: Point,
M: Transform + Rotate , solid: bool) -> Option< , solid: bool) -> Option , solid: bool) -> Option