使用OpenGL 2从鼠标进行光线投射

4

我试图通过鼠标单击来进行射线投射,最终目标是找到与平面的碰撞点。但我无法创建射线。世界是使用截锥体和我作为相机使用的另一个矩阵渲染的,按照截锥体*相机*顶点位置的顺序。以屏幕左上角为0,0,我可以获得单击像素的X、Y坐标。然后我使用下面的代码将其转换为射线:

  float x = (2.0f * x_screen_position) / width - 1.0f;
  float y = 1.0f - (2.0f * y_screen_position) / height;
  Vector4 screen_click = Vector4 (x, y, 1.0f, 1.0f);
  Vector4 ray_origin_world = get_camera_matrix() * screen_click;

  Vector4 tmp = (inverse(get_view_frustum()) * screen_click;
  tmp = get_camera_matrix() * tmp;
  Vector4 ray_direction = normalize(tmp);

视锥矩阵:

Matrix4 view_frustum(float angle_of_view, float aspect_ratio, float z_near, float z_far) {
    return Matrix4(
        Vector4(1.0/tan(angle_of_view), 0.0, 0.0, 0.0),
        Vector4(0.0, aspect_ratio/tan(angle_of_view), 0.0, 0.0),
        Vector4(0.0, 0.0, (z_far+z_near)/(z_far-z_near), 1.0),
        Vector4(0.0, 0.0, -2.0*z_far*z_near/(z_far-z_near), 0.0)
    );
}

当“相机”矩阵位于 0,0,0 时,可以得到预期结果,但一旦我改变为另一个位置的固定摄像机位置后,返回的结果完全不正确。 固定的“相机”矩阵:

Matrix4(
    Vector4(1.0, 0.0, 0.0, 0.0),
    Vector4(0.0, 0.70710678118, -0.70710678118, 0.000),
    Vector4(0.0, 0.70710678118, 0.70710678118, 0.0),
    Vector4(0.0, 8.0, 20.0, 1.000)
  );

因为我在网上找到的许多示例没有以这种方式实现相机,所以我无法找到更多帮助这种情况的信息。有人能提供任何见解或指点我更好的方向吗?

1个回答

4
Vector4 tmp = (inverse(get_view_frustum() * get_camera_matrix()) * screen_click; //take the inverse of the camera matrix as well
tmp /= tmp.w; //homogeneous coordinate "normalize" (different to typical normalization), needed with perspective projection or non-linear depth
Vector3 ray_direction = normalize(Vector3(tmp.x, tmp.y, tmp.z)); //make sure to normalize just the direction without w

[编辑]

这里有一个更长且类似的帖子:https://dev59.com/j53ls4cB2Jgan1zncOa5#20143963

如果您只有矩阵,则应使用起点和射线方向上的点。通常使用近平面和远平面上的点(优点是仅想要射线与可见物体相交)。也就是说,

(x,y,-1,1)(x,y,1,1)

这些点处于标准化设备坐标(NDC,-1到1的立方体是您的视野)。您需要做的就是将两个点全部移动到世界空间并进行归一化...

ndcPoint4 = /* from above */;
eyespacePoint4 = inverseProjectionMatrix * ndcPoint4;
worldSpacePoint4 = inverseCameraMatrix * eyespacePoint4;
worldSpacePoint3 = worldSpacePoint4.xyz / worldSpacePoint4.w;

//alternatively, with combined matrices
worldToClipMatrix = projectionMatrix * cameraMatrix; //called "clip" space before normalization
clipToWorldMatrix = inverse(worldToClipMatrix);
worldSpacePoint4 = clipToWorldMatrix * ndcPoint4;
worldSpacePoint3 = worldSpacePoint4.xyz / worldSpacePoint4.w;

//then for the ray, after transforming both start/end points
rayStart = worldPointOnNearPlane;
rayEnd = worldPointOnFarPlane;
rayDir = rayEnd - rayStart;

如果你有相机的世界坐标,你可以省略起点或终点,因为所有射线都通过相机的原点。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接