在右手坐标系中找到交点 ray/triangle

Find intersection point ray/triangle in a right-hand coordinate system

我想得到三角形上一条线(由矢量和原点定义)的交点。 我的引擎使用右手坐标系,所以X指向前方,Y指向左侧,Z指向上方。


----编辑----

在 Antares 的帮助下,我将我的积分转换为引擎 space:

p0.x = -pt0.y;
p0.y = pt0.z;
p0.z = pt0.x;

但我不知道如何对方向向量做同样的事情。


我使用了, original poster use this tutorial中的函数。

首先我们寻找从原点到交点的距离t,以找到它的坐标。 但是我有一个负 t,当光线在三角形外时,代码 return 为真。我把它放在外面视觉上。 当我在三角形中时,它 return 有时是假的。

这是我用来获取交点的函数,我已经检查过它是否有效,具有 'classic' 值,与原始 post.

中一样
float kEpsilon = 0.000001;

V3f crossProduct(V3f point1, V3f point2){

  V3f vector; 

  vector.x = point1.y * point2.z - point2.y * point1.z; 
  vector.y = point2.x * point1.z - point1.x * point2.z; 
  vector.z = point1.x * point2.y - point1.y * point2.x; 

  return vector;
}

float dotProduct(V3f dot1, V3f dot2){

  float dot = dot1.x * dot2.x + dot1.y * dot2.y + dot1.z * dot2.z; 

  return dot;
}

//orig: ray origin, dir: ray direction, Triangle vertices: p0, p1, p2.  
bool rayTriangleIntersect(V3f orig, V3f dir, V3f p0, V3f p1, V3f p2){ 

// compute plane's normal

  V3f p0p1, p0p2;

  p0p1.x = p1.x - p0.x; 
  p0p1.y = p1.y - p0.y; 
  p0p1.z = p1.z - p0.z; 

  p0p2.x = p2.x - p0.x;
  p0p2.y = p2.y - p0.y; 
  p0p2.z = p2.z - p0.z;

  // no need to normalize
  V3f N = crossProduct(p0p1, p0p2); // N 

  // Step 1: finding P

  // check if ray and plane are parallel ?
  float NdotRayDirection = dotProduct(N, dir); // if the result is 0, the function will return the value false (no intersection).

  if (fabs(NdotRayDirection) < kEpsilon){ // almost 0 

      return false; // they are parallel so they don't intersect ! 
  }

  // compute d parameter using equation 2
  float d = dotProduct(N, p0); 

  // compute t (equation P=O+tR P intersection point ray origin O and its direction R)

  float t = -((dotProduct(N, orig) - d) / NdotRayDirection);

  // check if the triangle is in behind the ray
  //if (t < 0){ return false; } // the triangle is behind 

  // compute the intersection point using equation
  V3f P; 

  P.x = orig.x + t * dir.x; 
  P.y = orig.y + t * dir.y; 
  P.z = orig.z + t * dir.z; 


  // Step 2: inside-outside test
  V3f C; // vector perpendicular to triangle's plane 

  // edge 0
  V3f edge0; 

  edge0.x = p1.x - p0.x;
  edge0.y = p1.y - p0.y;
  edge0.z = p1.z - p0.z;

  V3f vp0; 

  vp0.x = P.x - p0.x;
  vp0.y = P.y - p0.y; 
  vp0.z = P.z - p0.z; 

  C = crossProduct(edge0, vp0); 

  if (dotProduct(N, C) < 0) { return false; }// P is on the right side 

  // edge 1
  V3f edge1;

  edge1.x = p2.x - p1.x;
  edge1.y = p2.y - p1.y;
  edge1.z = p2.z - p1.z;

  V3f vp1; 

  vp1.x = P.x - p1.x; 
  vp1.y = P.y - p1.y; 
  vp1.z = P.z - p1.z; 

  C = crossProduct(edge1, vp1); 

  if (dotProduct(N, C) < 0) { return false; } // P is on the right side 

  // edge 2
  V3f edge2;

  edge2.x = p0.x - p2.x;    
  edge2.y = p0.y - p2.y;
  edge2.z = p0.z - p2.z;

  V3f vp2; 

  vp2.x = P.x - p2.x;
  vp2.y = P.y - p2.y;
  vp2.z = P.z - p2.z;

  C = crossProduct(edge2, vp2);

  if (dotProduct(N, C) < 0) { return false; } // P is on the right side; 

  return true; // this ray hits the triangle 
} 

我的问题是我得到了 t:-52.603783

交点 P : [-1143.477295, -1053.412842, 49.525799] 这给了我相对于 640X480 纹理的 uv 点:[-658, 41].

可能是因为我的引擎使用 Z 指向上?

My engine use right handed coordinate system, so X pointing forward, Y pointing left and Z pointing up.

您对右手坐标系的理解有点不正确...请检查https://en.wikipedia.org/wiki/Cartesian_coordinate_system#In_three_dimensions

顾名思义,X指向右(右手拇指向右),Y指向上方(直食指)Z(直中指)指向"forward"(实际上是-Z在相机坐标系中是向前的,Z是向后的。
实际上...您的坐标分量是右手边的,但是 X 向前等的解释是不寻常的。

如果您怀疑问题可能出在您引擎的坐标系上(可能是 OGRE?普通 OpenGL?还是自制的东西?),那么您需要将您的点和方向坐标转换为您的算法的坐标系。如果我没记错的话,您介绍的算法适用于相机坐标系。当然,您需要将生成的交点转换回您在引擎中使用的解释。 要转动矢量分量的方向(例如 Z 坐标),您可以使用与 -1 的乘法来实现效果。

编辑: 还有一件事:我意识到该算法也使用方向向量,而不仅仅是点。如果我没记错的话,组件的重新排列只对点有效,对方向无效。也许您必须与 CameraView 变换矩阵(或其逆 M^-1 或转置 M^T,我不确定)进行矩阵乘法。我帮不了你,我希望你能弄明白或者只是试错。

My problem is I get t: -52.603783

intersection point P : [-1143.477295, -1053.412842, 49.525799] This give me, relative to a 640X480 texture, the uv point: [-658, 41]

我想你认为你的价值观不正确。您希望获得哪些 t 和 UV 坐标值?哪些是 "correct" 您的输入?

希望这能让您入门。 GL,HF 与您的项目! :)

@GUNNM:关于你不知道如何处理方向向量的反馈,这里有一些想法可能对你有用。

我说了,应该有矩阵乘法的方式。查找 "transforming directional vector with a matrix" 或 "transforming normals (normal vectors) with a matrix" 等关键词。这应该产生类似于:"use the transpose of the used transformation matrix" 或 "the inverse of the matrix" 或类似的东西。

解决方法是:您可以 "convert" 指向一个点的方向向量,方法是将方向视为 "two points" 形成一个向量:起点和位于该方向上的另一个点你要点。

你的射线起点,你已经有了。现在您需要确保您的方向矢量被解释为 "second point" 而不是 "directional vector"。

如果您的引擎像第一种情况一样处理光线,您将拥有: 这是我的起点 (0,0,0),这是我的方向矢量 (5,6,-7)(我编造了这些数字并以原点为起点来举一个简单的例子)。所以这只是通常的 "start + gaze direction" 情况。

在第二种情况下,您将拥有: 这是我的起点 (0,0,0),我的第二个点是我的方向矢量 (5,6,-7) 上的一个点,例如任何 t* 方向。如果 t=1 被认为是矢量(并且起点是原点 (0,0,0)),那么 t=1 应该准确给出方向矢量指向的点。

现在您需要检查您的算法如何处理该方向。如果它在某处执行ray=startpoint+direction,那么它会将其解释为点+矢量,从而导致起点移动偏移,同时保持矢量的方向和方向。
如果它执行 ray=startpoint-direction 则它将其解释为两个点,通过减去两个点形成方向向量。

要从两点生成方向矢量,通常只需将它们相减即可。虽然这给出了 "pure direction",但没有定义方向(可以是 +t 或 -t)。所以如果你需要固定这个方向,你可以在以后的计算中使用你的 "vector sliding value" t 的绝对值(可能不是 best/fastest 的方法)。