【问题标题】:Ray transformation for ray-triangle intersection射线与三角形相交的射线变换
【发布时间】:2019-04-12 04:34:54
【问题描述】:

在 openGL 中,我有一个 3D 模型,我正在使用论文“快速、最小存储射线/三角形交点”(http://jgt.akpeters.com/papers/MollerTrumbore97/) 中解释的代码执行射线-三角形交点。

我的光标位置未使用以下代码投影到世界空间中:

bool SCamera::unproject(Vector3 input, Vector3 & output){

  GLint viewport[4]; 
  glGetIntegerv(GL_VIEWPORT,viewport); //Grab screen info

  float x = input.mX; 
  float y = input.mY;
  float z = input.mZ;

  Matrix4 P, Mv, res;

  P = getProjection();
  Mv = getCameraTransform();

  Vector3 N; //Cursor point translated to having 0,0 at screen center
  N.mX = ((x-viewport[0]) / viewport[2])*2 - 1;
  N.mY = ((y-viewport[1]) / viewport[3])*2 - 1;
  N.mZ = z*2-1;

  res = P * Mv; //Multiply P * Mv to get transform
  Vector3 w = res.inverse() * N; //Apply transform to N.

  output.mX = w[0];
  output.mY = w[1];
  output.mZ = w[2];
  return true;
}

之后,我通过执行以下操作形成一条射线:

unproject(Vector3(xClick, yClick,0),resultUnproject)
ray.origin = cameraPosition;
ray.direction = resultUnproject - ray.origin;
ray.direction.normalize();

现在,最后我试图通过三角形代码(上面链接)运行这条射线,但我似乎无法正确转换它。我目前的尝试如下:

Matrix4 mview, T;
mview = getModelview();
T = mview.inverse();
ray.origin = T*ray.origin;
ray.direction = T*ray.direction;
ray.direction.normalize();

由于某种原因,这不起作用。我的光线形成错误了吗?还是改错了?

【问题讨论】:

    标签: math opengl matrix 3d raytracing


    【解决方案1】:

    一种方法可能是:

    取你的光线原点,并在世界空间中沿着光线方向计算出一个单位距离的点。然后,对这两个点进行转换 - 即乘以转换矩阵的逆矩阵。然后,您可以根据两个平移点之间的差异确定新的光线方向。检查此方向是否与原始方向不同将很快告诉您是否缺少步骤。

    【讨论】:

    • 太棒了!这是调试我没有想到的东西的一种非常好的方法。谢谢。
    • 很遗憾,我还是遇到了麻烦。您介意查看上面列出的简短代码摘录吗?
    • @Ian - 我不认为我能提供那么多帮助,因为它与我习惯的 OGL 东西有点不同,而且我是一个四元数人;)对我来说,光线确实有点可疑 - 通常使用 glFrustum,您可以在 (0,0) 和底部的屏幕上与用户一起计算出一个“金字塔” - 底部取决于 both 视口大小和坐标范围。
    • 谢谢。 :) 我已经为此苦苦思考了半周了,所以任何新的研究领域都是有用的。只需指出要查看的区域,您就提供了很多帮助。我会一直坚持到我做对为止。
    【解决方案2】:

    我对此的解决方案是按照 sje397 的建议进行操作,但只需将结果用作您的新光线。

    所以在我的项目(即 XNA)中,给定 ray 未从光标投射:

    rayTransform = Matrix.Invert(model_transform);
    
    //Transform ray (or more accurately its defining components into a new ray)
    Vector3 v1 = Vector3.Transform(ray.Position, rayTransform);
    Vector3 v2 = Vector3.Transform((ray.Position + ray.Direction), rayTransform);
    transformedray = new Ray(v1, v2 - v1);
    

    model_transform 这里的生成方式与着色器的变换相同(即不交换世界/局部乘法或任何东西)

    这在我的项目中运行良好,拾取目标以各种方式旋转、转换和缩放。

    此外,您可能会觉得这有点不礼貌,但如果您仍然遇到问题,您确定取消投影光标并生成拾取射线的代码工作正常吗?我想如果您的三角形拾取代码有效,它就必须如此,它只是在我看来就像它以“环绕”的方式获取光线。

    在我的项目中,我采取了两点,一个“在”视口“平面”上,所以 Vector3(cursorx,cursory,0) 再次这样做,但在 Z 轴 Vector3(cursorx,cursory,1) 上前进。取消投影这两个点,第一个的结果是你的原点,不同的是你的方向。

    祝你好运!

    【讨论】:

    • 无礼是好的,尤其是在有帮助的时候。我已经有一段时间没有查看我的代码部分了(它有效,所以我想稍后会担心优化),但看起来你的建议会很有帮助。谢谢。
    【解决方案3】:

    所以我终于得到了这个工作,虽然我对如何做并不满意。在我的情况下,单个模型旋转在渲染之前被应用为变换,所以我最终不得不通过模型视图矩阵变换目标三角形。

    我在上面尝试做的是计算一条可以达到相同目的的光线,方法是围绕对象移动光线的原点,这样就好像对象已经旋转了一样。不幸的是,我无法完全正确地计算出数学。

    最终结果意味着每个三角形一次变换,而不是每条射线一次。幸运的是,它对性能的影响似乎并没有那么糟糕,因为我只是用它来挑选。

    【讨论】:

      【解决方案4】:

      如果你有一些光线(已经转换到世界空间)并且你想检查它是否与一个对象/三角形相交,你需要将它乘以对象的倒置矩阵。这是一些伪代码:

      NewRayPosition = Vector3.Transform(OldRay.Position, Matrix.Invert(Transformation);
      NewRayDirection = Vector3.Transform(OldRay.Direction, Matrix.Invert(Rotation*Scale));
      NewRayDirection.Normalize();
      

      将光线位置乘以平移、缩放和旋转,但方向仅乘以缩放和旋转。由于性能原因,按照您的方式进行操作是不可接受的。 更多在这里: http://www.cl.cam.ac.uk/teaching/1999/AGraphHCI/SMAG/node2.html#SECTION00024100000000000000

      【讨论】:

        猜你喜欢
        • 2012-10-21
        • 2015-05-05
        • 1970-01-01
        • 2020-04-03
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-01-28
        相关资源
        最近更新 更多