实施Ray Picking

Tom*_*ell 31 opengl math directx geometry picking

我有一个使用directx和openGL的渲染器,以及一个3d场景.视口和窗口具有相同的尺寸.

如何以独立于平台的方式实现给定鼠标坐标x和y的拾取?

And*_*nck 29

如果可以,可以通过鼠标指针计算来自眼睛的光线并与模型相交来对CPU进行拾取.

如果这不是一个选项,我会使用某种类型的ID渲染.指定要拾取唯一颜色的每个对象,使用这些颜色渲染对象,最后从鼠标指针下的帧缓冲区中读出颜色.

编辑:如果问题是如何构建的光线从鼠标的坐标,你需要以下条件:投影矩阵P和摄像机变换Ç.如果鼠标指针的坐标是(x,y)并且视口的大小是(宽度,高度),则沿着光线的剪辑空间中的一个位置是:

mouse_clip = [
  float(x) * 2 / float(width) - 1,
  1 - float(y) * 2 / float(height),
  0,
  1]
Run Code Online (Sandbox Code Playgroud)

(注意我翻转了y轴,因为鼠标坐标的原点通常位于左上角)

以下情况也是如此:

mouse_clip = P * C * mouse_worldspace
Run Code Online (Sandbox Code Playgroud)

这使:

mouse_worldspace = inverse(C) * inverse(P) * mouse_clip
Run Code Online (Sandbox Code Playgroud)

我们现在有:

p = C.position(); //origin of camera in worldspace
n = normalize(mouse_worldspace - p); //unit vector from p through mouse pos in worldspace
Run Code Online (Sandbox Code Playgroud)

  • @Tom这个问题并不完全清楚.无论如何,我已经编辑了我的答案,希望它有所帮助. (4认同)
  • 我不确定错误是在你的工作中还是在我的工作中,但是当我使用近剪裁平面的负值作为mouse_clip的z坐标时,我才能使这个算法工作.IE:`mouse_clip = [float(x)*2/float(width) - 1,1 - float(y)*2/float(height), - 1*near_clipping_plane,1]` (2认同)
  • 只是为了省去别人的麻烦:这个方法只有在mouse_clip中的3.坐标不是0但是-near_depth时才有效.另外,对于正交矩阵,必须以不同方式计算p. (2认同)

nor*_*gon 23

这是观看视锥体:

查看视锥体

首先,您需要确定鼠标点击发生在近平面上的位置:

  1. 将窗口坐标(0..640,0..480)重新缩放为[-1,1],左下角为(-1,-1),右上角为(1,1).
  2. 通过将缩放的坐标乘以我称之为"unview"矩阵来"撤消"投影:unview = (P * M).inverse() = M.inverse() * P.inverse(),其中M是ModelView 矩阵,P是投影矩阵.

然后确定摄像机在世界空间中的位置,并从摄像机开始绘制光线并穿过您在近平面上找到的点.

摄像机位于M.inverse().col(4),即逆模型矩阵的最后一列.

最终的伪代码:

normalised_x = 2 * mouse_x / win_width - 1
normalised_y = 1 - 2 * mouse_y / win_height
// note the y pos is inverted, so +y is at the top of the screen

unviewMat = (projectionMat * modelViewMat).inverse()

near_point = unviewMat * Vec(normalised_x, normalised_y, 0, 1)
camera_pos = ray_origin = modelViewMat.inverse().col(4)
ray_dir = near_point - camera_pos
Run Code Online (Sandbox Code Playgroud)

  • 自从我写这篇文章已经有一段时间了,但我认为这是将世界坐标转换为相机坐标的矩阵。如果您的顶点着色器中有一条线,例如“ gl_Position = projection * modelView * vertexPos;”,则位于中间的那一行,其中“ projection”矩阵是从摄影机到视口坐标的转换。高度:/ (2认同)