Ray - Triangle Intersection

Started by rupy, March 24, 2014, 00:26:08

Previous topic - Next topic

rupy

So I'm doing collision detection, and this example kind of works:

http://www.java-gaming.org/index.php?topic=5409.0

but the whole plane of all triangles trigger the collision... how do I modify this so it's only if the ray goes through the surface between the 3 points of the triangle that the collision is triggered?

Do I need to do this on the "I" point returned:

http://www.blackpawn.com/texts/pointinpoly/

"It's like Homeworld in first person."

quew8

Yes you do. Were you looking for a more in depth description of this technique? Or a recommendation? I think the Barycentric coordinates are a better option. Faster (according to the article, I didn't know this) and still pretty simple implementation.

Mickelukas

Something like this:
    public static Float getDistanceLineIntersectTriangle(final Point3DFloat startP, final Point3DFloat endP,
            final Point3DFloat vertex1, final Point3DFloat vertex2, final Point3DFloat vertex3, final boolean extendToInfinity,
            final boolean ignoreBackFaces) {

        final Point3DFloat direction =
            new Point3DFloat(endP.getX() - startP.getX(), endP.getY() - startP.getY(), endP.getZ() - startP.getZ());

        //Calculate the vector that represents the first side of the triangle.
        final Point3DFloat edge1 =
            new Point3DFloat(vertex3.getX() - vertex2.getX(), vertex3.getY() - vertex2.getY(), vertex3.getZ() - vertex2.getZ());

        //Calculate the vector that represents the second side of the triangle.
        final Point3DFloat edge2 =
            new Point3DFloat(vertex1.getX() - vertex2.getX(), vertex1.getY() - vertex2.getY(), vertex1.getZ() - vertex2.getZ());

        //Calculate a vector which is perpendicular to the vector between point 0 and point 1,
        //and the direction vector for the ray.
        final Point3DFloat directionCrossEdge2 = crossProduct(direction, edge2);

        //Calculate the dot product of the above vector and the vector between point 0 and point 2.
        final float determinant = dotProduct(edge1, directionCrossEdge2);

        //If we should ignore triangles the ray passes through the back side of,
        //and the ray points in the same direction as the normal of the plane,
        //then the ray passed through the back side of the plane,  
        //and the ray does not intersect the plane the triangle lies in.
        if (ignoreBackFaces && determinant >= 0) {
            return null;
        }

        //If the ray is (almost) parallel to the plane,
        //then the ray does not intersect the plane the triangle lies in.
        if (determinant > -0.00001 && determinant < 0.00001) {
            return null;
        }

        final float inverseDeterminant = 1 / determinant;

        //Calculate a vector between the starting point of our ray, and the first point of the triangle,
        //which is at UV(0,0)
        final Point3DFloat distanceVector =
            new Point3DFloat(startP.getX() - vertex2.getX(), startP.getY() - vertex2.getY(), startP.getZ() - vertex2.getZ());

        //Calculate the U coordinate of the intersection point.
        final float triangleU = inverseDeterminant * dotProduct(distanceVector, directionCrossEdge2);

        //Is the U coordinate outside the range of values inside the triangle?
        if (triangleU < 0 || triangleU > 1) {
            //The ray has intersected the plane outside the triangle.
            return null;
        }

        final Point3DFloat distanceCrossEdge1 = crossProduct(distanceVector, edge1);

        //Calculate the V coordinate of the intersection point.
        final float triangleV = inverseDeterminant * dotProduct(direction, distanceCrossEdge1);

        //Is the V coordinate outside the range of values inside the triangle?  
        //Does U+V exceed 1.0?  
        if (triangleV < 0 || triangleU + triangleV > 1) {
            //The ray has intersected the plane outside the triangle.       
            return null;
        }

        //Calculate the distance of the intersection point from the starting point of the ray.
        //This distance is scaled so that at p, the start of the ray, intersectionPointDistance=0, and at endP, the end of the ray, intersectionPointDistance=1.
        //If the intersection point is behind p, then intersectionPointDistance will be negative, and if the intersection point is
        //beyond endP then intersectionPointDistance will be greater than 1. 
        final float intersectionPointDistance = inverseDeterminant * dotProduct(edge2, distanceCrossEdge1);

        //If the triangle is behind p, ignore this intersection.
        //We want a directional ray, which only intersects triangles in the direction it points.
        if (intersectionPointDistance < 0) {
            return null;
        }

        //If the plane is beyond endP, and we do not want the ray to extend to infinity, then ignore this intersection.
        if (!extendToInfinity && intersectionPointDistance > 1) {
            return null;
        }

        //The ray intersects the triangle!      
        return intersectionPointDistance * vectorLength(direction);
    }

    private static float dotProduct(final Point3DFloat p, final Point3DFloat p2) {
        return p.getX() * p2.getX() + p.getY() * p2.getY() + p.getZ() * p2.getZ();
    }

    public static Point3DFloat crossProduct(final Point3DFloat p, final Point3DFloat p2) {
        return new Point3DFloat(p.getY() * p2.getZ() - p.getZ() * p2.getY(), p.getZ() * p2.getX() - p.getX() * p2.getZ(), p.getX()
            * p2.getY()
            - p.getY()
            * p2.getX());
    }