为glm :: unProject查找备份winZ

时间:2018-07-28 21:36:44

标签: c++ opengl glm-math coordinate-transformation

我有一个OpenGL程序,它基本上只是渲染一堆点。我需要从任意光标位置找到世界空间坐标,就像这样:

for item in data1['ListOrderItemsResponse']['ListOrderItemsResult']['OrderItems']:
  item_list.append(item['SellerSKU'])

如果光标位于对象上,则效果很好,但如果它位于屏幕的空白部分(即大部分)上,则假定它位于远剪切平面上(winZ = 1),并且glm :: unProject返回inf值。理想情况下,我想向其传递与世界空间坐标中z = 0处xy平面相对应的另一个winZ,但我不知道如何获得该值。

1 个答案:

答案 0 :(得分:1)

因为有一个glm::unProject函数,所以它也是一个glm::project函数。

如果您想知道z坐标为0的点的深度,该点位于与视图空间平行的平面上,则必须glm::project在该平面上的一个点。它可以是平面上的任何点,因为您仅对其z坐标感兴趣。您可以为此使用世界起源:

glm::vec3 world_origin{ 0.0f, 0.0f, 0.0f };
glm::vec3 origin_ndc = glm::project(screenCoords, view, graphics.projection, viewport);
float depth0         = world_origin[2];

其中view是视图矩阵,它从世界空间转换为相机空间(从glm::lookAt得到)。

因此实现可能如下所示:

glm::mat4 modelview = graphics.view * graphics.model;
glm::vec4 viewport  = { 0.0, 0.0, windowWidth, windowHeight };

float winX = cursorX;
float winY = viewport[3] - cursorY;
float depth;
glReadPixels(winX, winY- cursorY, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &depth);

const float epsi = 0.00001f;
if ( depth > 1.0f-epsi )
{
    glm::vec3 world_origin{ 0.0f, 0.0f, 0.0f };
    glm::vec3 origin_ndc = glm::project(world_origin, graphics.view, graphics.projection, viewport);
    depth                = origin_ndc[2];  
}

glm::vec3 screenCoords{ winX, winY, depth };
glm::vec3 cursorPosition = glm::unProject(screenCoords, modelview, graphics.projection, viewport);