title: Ray-Triangle intersection picking not working
body: <p>I've been working on this for the past several days and have been stuck. I need to be able to touch the screen and return the x,y,z coordinates of the point on my model closest to the near plane that intersects the ray generated at the pick point. I think part of my problem is I'm doing a bunch of matrix transformations and rotations throughout the render code for my model, although the geometry I'm interested in is all rendered at a specific transformation state. My code that I'm using is below. If anyone can help me figure out how to get this working, that would be awesome. checkCollision() is fed the point that the user clicks on, and gluUnProject() is supposed to transform my 2d pick point into 3D coordinates on my near and far planes, 0 being the near plane and 1 being the far plane. My usage is here and is called right before the geometry is rendered, so all transforms have already been applied:</p>
  
  <pre><code>[self checkCollision:touchPoint panVector:panVec];
  </code></pre>
  
  <p>This code below is the collision checking code:</p>
  
  <pre><code>-(Boolean) checkCollision:(CGPoint)winPos panVector:(Vector3f*)panVec
  {   
  glGetIntegerv(GL_VIEWPORT, viewport);
  
  winPos.y = (float)viewport[3] - winPos.y;
  
  Vector3f nearPoint;
  Vector3f farPoint;
  
  glGetFloatv(GL_PROJECTION_MATRIX, projection);
  glGetFloatv(GL_MODELVIEW_MATRIX, modelview);
  
  //Retreiving position projected on near plane
  gluUnProject(winPos.x, winPos.y , 0, modelview, projection, viewport, &amp;nearPoint.x, &amp;nearPoint.y, &amp;nearPoint.z);
  
  //Retreiving position projected on far plane
  gluUnProject(winPos.x, winPos.y,  1, modelview, projection, viewport, &amp;farPoint.x, &amp;farPoint.y, &amp;farPoint.z);
  
  Vector3f *near = [[Vector3f alloc] initWithFloatsX:nearPoint.x Y:nearPoint.y Z:nearPoint.z];
  Vector3f *far = [[Vector3f alloc] initWithFloatsX:farPoint.x Y:farPoint.y Z:farPoint.z];
  Vector3f *d = [Vector3f subtractV1:far minusV2:near];
  
  Vector3f *v0 = [[Vector3f alloc] init];
  Vector3f *v1 = [[Vector3f alloc] init];
  Vector3f *v2 = [[Vector3f alloc] init];
  Vector3f *e1; // = [[Vector3f alloc] init];
  Vector3f *e2; // = [[Vector3f alloc] init];
  
  for (int i = 0; i &lt; assemblyObj-&gt;numObjects; i++) {
      for (int j = 0; j &lt; assemblyObj-&gt;partList[i].numVertices; j+=18) {
          v0.x = assemblyObj-&gt;partList[i].vertices[j+0];
          v0.y = assemblyObj-&gt;partList[i].vertices[j+1];
          v0.z = assemblyObj-&gt;partList[i].vertices[j+2];
  
          v1.x = assemblyObj-&gt;partList[i].vertices[j+6];
          v1.y = assemblyObj-&gt;partList[i].vertices[j+7];
          v1.z = assemblyObj-&gt;partList[i].vertices[j+8];
  
          v2.x = assemblyObj-&gt;partList[i].vertices[j+12];
          v2.y = assemblyObj-&gt;partList[i].vertices[j+13];
          v2.z = assemblyObj-&gt;partList[i].vertices[j+14];
  
          e1 = [Vector3f subtractV1:v1 minusV2:v0];
          e2 = [Vector3f subtractV1:v2 minusV2:v0];
  
          Vector3f *p = [[Vector3f alloc] init];
          [Vector3f cross:p V1:d V2:e2];
          float a = [Vector3f dot:e1 V2:p];
          if (a &gt; -.000001 &amp;&amp; a &lt; .000001) {
              continue;
          }
  
          float f = 1/a;
          Vector3f *s = [Vector3f subtractV1:near minusV2:v0];
          float u = f*([Vector3f dot:s V2:p]);
          if (u&lt;0 || u&gt;1) {
              continue;
          }
          Vector3f *q = [[Vector3f alloc] init];
          [Vector3f cross:q V1:s V2:e1];
          float v = f*([Vector3f dot:d V2:q]);
          if (v&lt;0 || (u+v)&gt;1) {
              continue;
          }
          //NSLog(@"hit polygon");
          return true;
      }
  }
  
  //NSLog(@"didn't hit polygon");
  return FALSE;   
  }  
  
  
  GLint gluUnProject(GLfloat winx, GLfloat winy, GLfloat winz,
           const GLfloat model[16], const GLfloat proj[16],
           const GLint viewport[4],
           GLfloat * objx, GLfloat * objy, GLfloat * objz)
  {
  /* matrice de transformation */
  GLfloat m[16], A[16];
  GLfloat in[4], out[4];
  
  /* transformation coordonnees normalisees entre -1 et 1 */
  in[0] = (winx - viewport[0]) * 2 / viewport[2] - 1.f;
  in[1] = (winy - viewport[1]) * 2 / viewport[3] - 1.f;
  in[2] = 2 * winz - 1.f;
  in[3] = 1.f;
  
  /* calcul transformation inverse */
  matmul(A, proj, model);
  invert_matrix(A, m);
  
  /* d'ou les coordonnees objets */
  transform_point(out, m, in);
  if (out[3] == 0.f)
      return GL_FALSE;
  *objx = out[0] / out[3];
  *objy = out[1] / out[3];
  *objz = out[2] / out[3];
  return GL_TRUE;
  }
  
  
  void transform_point(GLfloat out[4], const GLfloat m[16], const GLfloat in[4])
  {
  #define M(row,col)  m[col*4+row]
  out[0] =
  M(0, 0) * in[0] + M(0, 1) * in[1] + M(0, 2) * in[2] + M(0, 3) * in[3];
  out[1] =
  M(1, 0) * in[0] + M(1, 1) * in[1] + M(1, 2) * in[2] + M(1, 3) * in[3];
  out[2] =
  M(2, 0) * in[0] + M(2, 1) * in[1] + M(2, 2) * in[2] + M(2, 3) * in[3];
  out[3] =
  M(3, 0) * in[0] + M(3, 1) * in[1] + M(3, 2) * in[2] + M(3, 3) * in[3];
  #undef M
  }
  
  void matmul(GLfloat * product, const GLfloat * a, const GLfloat * b)
  {
  /* This matmul was contributed by Thomas Malik */
  GLfloat temp[16];
  GLint i;
  
  #define A(row,col)  a[(col&lt;&lt;2)+row]
  #define B(row,col)  b[(col&lt;&lt;2)+row]
  #define T(row,col)  temp[(col&lt;&lt;2)+row]
  
  /* i-te Zeile */
  for (i = 0; i &lt; 4; i++) {
      T(i, 0) =
      A(i, 0) * B(0, 0) + A(i, 1) * B(1, 0) + A(i, 2) * B(2, 0) + A(i,
                                                                    3) *
      B(3, 0);
      T(i, 1) =
      A(i, 0) * B(0, 1) + A(i, 1) * B(1, 1) + A(i, 2) * B(2, 1) + A(i,
                                                                    3) *
      B(3, 1);
      T(i, 2) =
      A(i, 0) * B(0, 2) + A(i, 1) * B(1, 2) + A(i, 2) * B(2, 2) + A(i,
                                                                    3) *
      B(3, 2);
      T(i, 3) =
      A(i, 0) * B(0, 3) + A(i, 1) * B(1, 3) + A(i, 2) * B(2, 3) + A(i,
                                                                    3) *
      B(3, 3);
  }
  
  #undef A
  #undef B
  #undef T
  memcpy(product, temp, 16 * sizeof(GLfloat));
  }
  
  int invert_matrix(const GLfloat * m, GLfloat * out)
  {
  /* NB. OpenGL Matrices are COLUMN major. */
  #define SWAP_ROWS(a, b) { GLfloat *_tmp = a; (a)=(b); (b)=_tmp; }
  #define MAT(m,r,c) (m)[(c)*4+(r)]
  
  GLfloat wtmp[4][8];
  GLfloat m0, m1, m2, m3, s;
  GLfloat *r0, *r1, *r2, *r3;
  
  r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3];
  
  r0[0] = MAT(m, 0, 0), r0[1] = MAT(m, 0, 1),
  r0[2] = MAT(m, 0, 2), r0[3] = MAT(m, 0, 3),
  r0[4] = 1.f, r0[5] = r0[6] = r0[7] = 0.f,
  r1[0] = MAT(m, 1, 0), r1[1] = MAT(m, 1, 1),
  r1[2] = MAT(m, 1, 2), r1[3] = MAT(m, 1, 3),
  r1[5] = 1.f, r1[4] = r1[6] = r1[7] = 0.f,
  r2[0] = MAT(m, 2, 0), r2[1] = MAT(m, 2, 1),
  r2[2] = MAT(m, 2, 2), r2[3] = MAT(m, 2, 3),
  r2[6] = 1.f, r2[4] = r2[5] = r2[7] = 0.f,
  r3[0] = MAT(m, 3, 0), r3[1] = MAT(m, 3, 1),
  r3[2] = MAT(m, 3, 2), r3[3] = MAT(m, 3, 3),
  r3[7] = 1.f, r3[4] = r3[5] = r3[6] = 0.f;
  
  /* choose pivot - or die */
  if (fabsf(r3[0]) &gt; fabsf(r2[0]))
      SWAP_ROWS(r3, r2);
  if (fabsf(r2[0]) &gt; fabsf(r1[0]))
      SWAP_ROWS(r2, r1);
  if (fabsf(r1[0]) &gt; fabsf(r0[0]))
      SWAP_ROWS(r1, r0);
  if (0.f == r0[0])
      return GL_FALSE;
  
  /* eliminate first variable     */
  m1 = r1[0] / r0[0];
  m2 = r2[0] / r0[0];
  m3 = r3[0] / r0[0];
  s = r0[1];
  r1[1] -= m1 * s;
  r2[1] -= m2 * s;
  r3[1] -= m3 * s;
  s = r0[2];
  r1[2] -= m1 * s;
  r2[2] -= m2 * s;
  r3[2] -= m3 * s;
  s = r0[3];
  r1[3] -= m1 * s;
  r2[3] -= m2 * s;
  r3[3] -= m3 * s;
  s = r0[4];
  if (s != 0.f) {
      r1[4] -= m1 * s;
      r2[4] -= m2 * s;
      r3[4] -= m3 * s;
  }
  s = r0[5];
  if (s != 0.f) {
      r1[5] -= m1 * s;
      r2[5] -= m2 * s;
      r3[5] -= m3 * s;
  }
  s = r0[6];
  if (s != 0.f) {
      r1[6] -= m1 * s;
      r2[6] -= m2 * s;
      r3[6] -= m3 * s;
  }
  s = r0[7];
  if (s != 0.f) {
      r1[7] -= m1 * s;
      r2[7] -= m2 * s;
      r3[7] -= m3 * s;
  }
  
  /* choose pivot - or die */
  if (fabsf(r3[1]) &gt; fabsf(r2[1]))
      SWAP_ROWS(r3, r2);
  if (fabsf(r2[1]) &gt; fabsf(r1[1]))
      SWAP_ROWS(r2, r1);
  if (0.f == r1[1])
      return GL_FALSE;
  
  /* eliminate second variable */
  m2 = r2[1] / r1[1];
  m3 = r3[1] / r1[1];
  r2[2] -= m2 * r1[2];
  r3[2] -= m3 * r1[2];
  r2[3] -= m2 * r1[3];
  r3[3] -= m3 * r1[3];
  s = r1[4];
  if (0.f != s) {
      r2[4] -= m2 * s;
      r3[4] -= m3 * s;
  }
  s = r1[5];
  if (0.f != s) {
      r2[5] -= m2 * s;
      r3[5] -= m3 * s;
  }
  s = r1[6];
  if (0.f != s) {
      r2[6] -= m2 * s;
      r3[6] -= m3 * s;
  }
  s = r1[7];
  if (0.f != s) {
      r2[7] -= m2 * s;
      r3[7] -= m3 * s;
  }
  
  /* choose pivot - or die */
  if (fabs(r3[2]) &gt; fabs(r2[2]))
      SWAP_ROWS(r3, r2);
  if (0.f == r2[2])
      return GL_FALSE;
  
  /* eliminate third variable */
  m3 = r3[2] / r2[2];
  r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4],
  r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], r3[7] -= m3 * r2[7];
  
  /* last check */
  if (0.f == r3[3])
      return GL_FALSE;
  
  s = 1.f / r3[3];        /* now back substitute row 3 */
  r3[4] *= s;
  r3[5] *= s;
  r3[6] *= s;
  r3[7] *= s;
  
  m2 = r2[3];         /* now back substitute row 2 */
  s = 1.f / r2[2];
  r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2),
  r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2);
  m1 = r1[3];
  r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1,
  r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1;
  m0 = r0[3];
  r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0,
  r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0;
  
  m1 = r1[2];         /* now back substitute row 1 */
  s = 1.f / r1[1];
  r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1),
  r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1);
  m0 = r0[2];
  r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0,
  r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0;
  
  m0 = r0[1];         /* now back substitute row 0 */
  s = 1.f / r0[0];
  r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0),
  r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0);
  
  MAT(out, 0, 0) = r0[4];
  MAT(out, 0, 1) = r0[5], MAT(out, 0, 2) = r0[6];
  MAT(out, 0, 3) = r0[7], MAT(out, 1, 0) = r1[4];
  MAT(out, 1, 1) = r1[5], MAT(out, 1, 2) = r1[6];
  MAT(out, 1, 3) = r1[7], MAT(out, 2, 0) = r2[4];
  MAT(out, 2, 1) = r2[5], MAT(out, 2, 2) = r2[6];
  MAT(out, 2, 3) = r2[7], MAT(out, 3, 0) = r3[4];
  MAT(out, 3, 1) = r3[5], MAT(out, 3, 2) = r3[6];
  MAT(out, 3, 3) = r3[7];
  
  return GL_TRUE;
  
  #undef MAT
  #undef SWAP_ROWS
  }
  </code></pre>
  
  <h1>Edit:</h1>
  
  <p>I followed Justin Meiners suggestion of rendering points to show me where my pick ray is getting generated and I can see what's happening now, but don't know why. My scene implements arcball rotation, zooming and panning through quaternions. I'll roughly lay out what my scene is doing then what is happening with my pick ray.</p>
  
  <p>First, setup my viewport:</p>
  
  <pre><code>glViewport(0, 0, scene.width, scene.height);
  glOrthof(-11.25, 11.25, -14.355, 14.355, -1000, 1000);
  </code></pre>
  
  <p>Next, I grab the 16 element matrix that I use as part of my arcball method to navigate my scene and multiply my modelview matrix by it:</p>
  
  <pre><code>float mat[16];
  [arcball get_Renamed:mat];
  glMultMatrixf(mat);
  </code></pre>
  
  <p>Now, I do my pick ray:</p>
  
  <pre><code>glGetIntegerv(GL_VIEWPORT, viewport);
  glGetFloatv(GL_PROJECTION_MATRIX, projection);
  glGetFloatv(GL_MODELVIEW_MATRIX, modelview);
  
  touchPoint.y = (float)viewport[3] - touchPoint.y;
  
  Vector3f nearPoint, farPoint;
  
  //Retreiving position projected on near plane
  gluUnProject(touchPoint.x, touchPoint.y , 0, modelview, projection, viewport, &amp;nearPoint.x, &amp;nearPoint.y, &amp;nearPoint.z);
  
  //Retreiving position projected on far plane
  gluUnProject(touchPoint.x, touchPoint.y,  1, modelview, projection, viewport, &amp;farPoint.x, &amp;farPoint.y, &amp;farPoint.z);
  
  float coords[3] = {nearPoint.x, nearPoint.y, nearPoint.z};
  float coords2[3] = {farPoint.x, farPoint.y, farPoint.z};
  
  glPointSize(100);
  glColor4f(1, 0, 0, 1);
  glEnableClientState(GL_VERTEX_ARRAY);
  glVertexPointer(3, GL_FLOAT, sizeof(coords[0])*3, coords);
  glDrawArrays(GL_POINTS, 0, 1);
  
  glPointSize(150);
  glColor4f(0, 0, 1, 1);
  glEnableClientState(GL_VERTEX_ARRAY);
  glVertexPointer(3, GL_FLOAT, sizeof(coords2[0])*3, coords2);
  glDrawArrays(GL_POINTS, 0, 1);
  glDisableClientState(GL_VERTEX_ARRAY);
  </code></pre>
  
  <p>I do this, and it works fine before I rotate my scene, but as soon as I start to rotate my scene, the far point starts to move around. If I rotate the scene around exactly 180 degrees, the far point is back in line with the near point. Any idea what is going on? The arcball is just based on Ken Shoemake's algorithm.</p>