[committed] Ray/Triangle intersections miss on triangle edge

Ray.intersectWhere(…) finds the intersection between the ray and a triangle defined by three points.  The code fails to detect intersections along the edge from the last point back to the first.



Here's the diff for the fix:

com.jme.math.Ray


Index: src/com/jme/math/Ray.java
===================================================================
--- src/com/jme/math/Ray.java   (revision 4056)
+++ src/com/jme/math/Ray.java   (working copy)
@@ -220,7 +220,7 @@
         }
 
         float dirDotDiffxEdge2 = sign * direction.dot(diff.cross(edge2, edge2));
-        if (dirDotDiffxEdge2 > 0.0f) {
+        if (dirDotDiffxEdge2 >= 0.0f) {
             float dirDotEdge1xDiff = sign
                     * direction.dot(edge1.crossLocal(diff));
             if (dirDotEdge1xDiff >= 0.0f) {



And here's a unit test that exercises the method (NB - the current code fails on the third pick test):


package com.jme.math;


public class TestRay extends junit.framework.TestCase {
   private Vector3f v0;
   private Vector3f v1;
   private Vector3f v2;

   public void setUp() throws Exception {
      v0 = new Vector3f(-1f,-1f,-1f);
      v1 = new Vector3f(+1f,-1f,-1f);
      v2 = new Vector3f(+1f,+1f,-1f);
   }

   public void testIntersectWhere() throws Exception {
      
      Vector3f intersectionPoint = new Vector3f();
      Ray pickRay;
      
      // inside triangle
      pickRay = new Ray(new Vector3f(0.5f,-0.5f,3f),new Vector3f(0f,0f,-1f));      
      assertTrue(pickRay.intersectWhere(v0, v1, v2, intersectionPoint));

      // horizontal edge
      pickRay = new Ray(new Vector3f(0f,-1f,3f),new Vector3f(0f,0f,-1f));      
      assertTrue(pickRay.intersectWhere(v0, v1, v2, intersectionPoint));
      
      // diagonal edge
      pickRay = new Ray(new Vector3f(0f,0f,3f),new Vector3f(0f,0f,-1f));      
      assertTrue(pickRay.intersectWhere(v0, v1, v2, intersectionPoint));

      // vertical edge
      pickRay = new Ray(new Vector3f(+1f,0f,3f),new Vector3f(0f,0f,-1f));      
      assertTrue(pickRay.intersectWhere(v0, v1, v2, intersectionPoint));

      // v0
      pickRay = new Ray(new Vector3f(-1f,-1f,3f),new Vector3f(0f,0f,-1f));      
      assertTrue(pickRay.intersectWhere(v0, v1, v2, intersectionPoint));

      // v1
      pickRay = new Ray(new Vector3f(+1f,-1f,3f),new Vector3f(0f,0f,-1f));      
      assertTrue(pickRay.intersectWhere(v0, v1, v2, intersectionPoint));

      // v2
      pickRay = new Ray(new Vector3f(1f,1f,3f),new Vector3f(0f,0f,-1f));      
      assertTrue(pickRay.intersectWhere(v0, v1, v2, intersectionPoint));
      
      // outside horizontal edge
      pickRay = new Ray(new Vector3f(0f,-1.1f,3f),new Vector3f(0f,0f,-1f));      
      assertFalse(pickRay.intersectWhere(v0, v1, v2, intersectionPoint));
      
      // outside diagonal edge
      pickRay = new Ray(new Vector3f(-0.1f,0.1f,3f),new Vector3f(0f,0f,-1f));      
      assertFalse(pickRay.intersectWhere(v0, v1, v2, intersectionPoint));

      // outside vertical edge
      pickRay = new Ray(new Vector3f(+1.1f,0f,3f),new Vector3f(0f,0f,-1f));      
      assertFalse(pickRay.intersectWhere(v0, v1, v2, intersectionPoint));

      // inside triangle but ray pointing other way
      pickRay = new Ray(new Vector3f(-0.5f,-0.5f,3f),new Vector3f(0f,0f,+1f));      
      assertFalse(pickRay.intersectWhere(v0, v1, v2, intersectionPoint));
   }
}

Thanks jeff_m_t, good find.

This is not committed yet, should it go in?

My 3D math knowledge is pretty much not existent  :wink:

I would say yes, it just simply changes '>' to '>=' so it should be fine :slight_smile:



(Although it will probably still fail from time to time due to floating point error…)

Yeah, put it in.

committed the fix and junit test

Thanks for checking this in for me Core-Dump.  I had a little trouble figuring out how to commit at GoogleCode (I kept trying to use my GMail password) and then I got buried at work.

No problem, i'll be happy to commit things.



Are you registered as a contributor?

Only then, and using the https:// svn address you can commit patches.


Yeah, Mark P gave me commit access.  I just got tripped up because I didn't realize that GoogleCode associates a password with my profile that is different from my regular google password.  I'm all set now.