package toxi.geom.mesh; import toxi.geom.AABB; import toxi.geom.Intersector3D; import toxi.geom.IsectData3D; import toxi.geom.Ray3D; import toxi.geom.Vec3D; /** * * @author tux */ public class MeshIntersector implements Intersector3D { private static final float EPS = 0.00001f; private TriangleMesh mesh; private AABB bounds; private final IsectData3D isec; /** * * @param mesh */ public MeshIntersector(TriangleMesh mesh) { setMesh(mesh); this.isec = new IsectData3D(); } @Override public IsectData3D getIntersectionData() { return isec; } @Override public boolean intersectsRay(Ray3D ray) { isec.isIntersection = false; if (bounds.intersectsRay(ray, 0, Float.MAX_VALUE) != null) { Vec3D dir = ray.getDirection(); float minD = Float.MAX_VALUE; for (Face f : mesh.getFaces()) { float d = intersectTriangle(f.a, f.b, f.c, ray, dir); if (d >= 0.0 && d < minD) { isec.isIntersection = true; isec.normal = f.normal; minD = d; } } if (isec.isIntersection) { isec.pos = ray.getPointAtDistance(minD); isec.dist = minD; isec.dir = dir.getInverted(); } } return isec.isIntersection; } private float intersectTriangle(Vec3D a, Vec3D b, Vec3D c, Vec3D ro, Vec3D dir) { Vec3D e1 = b.sub(a); Vec3D e2 = c.sub(a); Vec3D pvec = dir.cross(e2); float det = e1.dot(pvec); if (det > -EPS && det < EPS) { return -1; } float invDet = 1f / det; Vec3D tvec = ro.sub(a); float u = tvec.dot(pvec) * invDet; if (u < 0.0 || u > 1.0) { return -1; } Vec3D qvec = tvec.cross(e1); float v = dir.dot(qvec) * invDet; if (v < 0.0 || u + v > 1.0) { return -1; } float t = e2.dot(qvec) * invDet; return t; } /** * * @param mesh */ public final void setMesh(TriangleMesh mesh) { this.mesh = mesh; this.bounds = mesh.getBoundingBox(); } }