正确调用glm :: unproject(),困惑

时间:2018-01-06 07:33:53

标签: c++ opengl matrix glm-math

我尝试使用glm :: unproject()将我的SDL鼠标坐标转换为x / z平面上的世界位置矢量。基本上我想弄清楚哪个" x / z"协调用鼠标点击的用户。

other stack overflow answers我需要调用glm :: unproject()。我认为我传递了错误的论据,因为我回到世界位置的价值(打印std std :: cerr)并不是我所期望的世界位置值。

我是否在下面正确构造了glm :: unproject()的参数?具体来说我应该梳理相机的世界位置和视图矩阵(使用glm :: lookAt计算)来计算传递给glm :: unproject的模型视图矩阵吗?

struct Dimensions {
  int x, y, w, h;
};

glm::mat4
Camera::view_matrix() const
{
  // VIEW matrix is created by looking at some target member
  auto const& target = target_->translation;
  auto const position_xyz = world_position();

  glm::vec3 const UP{0, 1, 0};
  return glm::lookAt(position_xyz, target, UP);
}

glm::mat4
Camera::projection_matrix() const
{
  auto const fov = glm::radians(90.0f);
  return glm::perspective(fov, 4.0f/3.0f, 0.1f, 200.0f);
}

glm::vec3
calculate_worldpos(Camera const& camera, int const mouse_x, int const mouse_y)
{
  float const width = 1024.0f, height = 768.0f;
  glm::vec4 const viewport = glm::vec4(0.0f, 0.0f, width, height);
  glm::mat4 const modelview = camera.view_matrix();
  glm::mat4 const projection = camera.projection_matrix();

  float z = 0.0;
  glm::vec3 screenPos = glm::vec3(mouse_x, height - mouse_y - 1, z);
  std::cerr << "screenpos: xyz: '" << glm::to_string(screenPos) << "'\n";

  glm::vec3 worldPos = glm::unProject(screenPos, modelview, projection, viewport);
  std::cerr << "worldpos: xyz: '" << glm::to_string(worldPos) << "'\n";
  return worldPos;
}

在下图中,我有以下设置。

相机lookAt target =(0,0,0)

相机世界位置=(-0.009,5.107,-0.368)

(mouse_x,mouse_y,mouse_z)=(286,393,0)

如果您查看下图,您可以看到我的鼠标悬停在世界位置(3,0,0)上,如网格所示。我希望计算我的鼠标的世界位置(如图所示)将返回向量(3,0,0)。它没有,而是我得到了矢量:(0.049,5.007,-0.360)。

enter image description here

有谁知道我可能会出错?我假设我在某处做了某种不正确的假设。

1 个答案:

答案 0 :(得分:4)

您的假设是错误的:glm :: unproject返回由像素坐标中的xy位置和存储深度值的z坐标给出的输入的世界空间坐标。在屏幕上的每个像素上,世界空间中有无数个点投射到该像素(所有这些点都位于从投影中心通过该像素的光线上)。通过选择深度坐标来识别您想要哪一个,而不是在此光线上产生一个特定点。选择z = 0意味着结果将始终是相机近平面上的一个点。

您实际需要的是此光线(通过相机位置和计算点)与xz平面(y = 0)的交点。

光线由其上的两个点(摄像机位置 C ,靠近平面点 P )给出,如下所示:

                  -0.009            0.058
C + l * (P-C) = (  5.107 ) + l * ( -0.100 )
                  -0.368            0.008

,其中l是自由变量。

如前所述,我们正在寻找与y = 0平面的交点(a,b),因此我们可以制定以下等式:

  -0.009            0.058       a
(  5.107 ) + l * ( -0.100 ) = ( 0 )
  -0.368            0.008       b

求解l的y方程(5.107 + l * -0.1 = 0)得到l = 51.07。粘贴在x和z的方程中产生:

a = -0.009 + 51.07 * 0.058 = 2.95306
b = -0.368 + 51.07 * 0.008 = 0.04056

接近预期的世界空间位置。差异很可能是因为你只是在问题中显示了舍入的数字。出于准确性原因,我也不会计算近平面上的点,而是计算远平面上的点(z = 1),因为近平面距离通常非常小并且可能导致数值问题。

结论:提供的所有值都是正确的,但您没有计算出您的预期。