使用glm::unproject()获取Z = 0平面上的光标位置?

3

我正试图使用鼠标坐标来获取网格(z = 0)的坐标(x,y)。经过长时间的搜索,我找到了使用glm :: unproject的方法。

首先,我使用回调函数获取鼠标坐标:

void cursorCallback(GLFWwindow *window, double x, double y)
{
    this->cursorCoordinate = glm::vec3(x, (this->windowHeight - y - 1.0f), 0.0f);
}

然后将这些坐标转换:

glm::vec3 cursorCoordinatesToWorldCoordinates()
{
            glm::vec3 pointInitial = glm::unProject(
                                              glm::vec3(this->cursorCoordinate.x, this->cursorCoordinate.y, 0.0),
                                              this->modelMatrix * this->viewMatrix,
                                              this->projectionMatrix,
                                              this->viewPort
                                              );

            glm::vec3 pointFinal = glm::unProject(
                                              glm::vec3(this->cursorCoordinate.x, this->cursorCoordinate.y, 1.0),
                                              this->modelMatrix * this->viewMatrix,
                                              this->projectionMatrix,
                                              this->viewPort
                                              );

            glm::vec3 vectorDirector = pointFinal - pointInitial;

            double lambda = (-pointInitial.y) / vectorDirector.y;

            double x = pointInitial.x + lambda * vectorDirector.x;
            double y = pointInitial.z + lambda * vectorDirector.z;

            return glm::vec3(x, y, 0.0f);
}

我使用一个ArcBall相机围绕指定轴旋转世界,这就是我生成MVP矩阵的方法:

this->position = glm::vec3(0.0f, 10.0f, 5.0f);
this->up = glm::vec3(0.0f, 1.0f, 0.0f);
this->lookAt = glm::vec3(0.0f, 0.0f, 0.0f);

this->fieldView = 99.0f;
this->farDistance = 100.0f;
this->nearDistance = 0.1f;

this->modelMatrix      = glm::mat4(1.0f);
this->viewMatrix       = glm::lookAt(this->position, this->lookAt, this->up) * glm::rotate(glm::degrees(this->rotationAngle) * this->dragSpeed, this->rotationAxis);
this->projectionMatrix = glm::perspective(glm::radians(this->fieldView), 1.0f, this->nearDistance, this->farDistance);

但是有些事情出了问题,因为我没有得到正确的结果。看一下应用程序的打印输出:

enter image description here

每个正方形是1单位,立方体渲染在位置(0, 0, 0)。当rotationAngle = 0时,当光标位于(0,0)、(1,1)、(2,2)、(3,3)、(4,4)、(5,5)时,分别获得(0, 5.7)、(0.8, 6.4)、(1.6, 6.9)、(2.4, 7.6)、(3.2, 8.2)、(4.2, 8.8)。这不是预期的。

  • 为什么y会延迟6个单位?
  • 基于rotationAngle,需要旋转结果cursorCoordinatesToWorldCoordinates吗?

--

我已经做过的:

  • 检查视口是否与glViewport匹配 - OK
  • 检查OpenGL坐标(Y向上,而不是Z) - OK

5
[标签:glm]!=[标签:glm-math] - genpfault
@httpdigest 谢谢!但问题仍然存在。 - Vinícius Lara
网格的z坐标(假设它位于xy平面上)在最终计算中必须发挥作用,不仅仅是来自farPoint、nearPoint的坐标。我的意思是,未投影的射线必须与网格所在的平面相交。 - Ripi2
@Ripi2 我想我明白了,但是出了什么问题? - Vinícius Lara
lambda=表达式是错误的。如果网格中的所有点都是(x,y,K)(其中K是某个固定的z),则lambda =(K-nearPoint.z)/ lineSegment.z。对于其他平面,您需要平面线交点。 K-nearPoint.z表示nearPoint和网格之间的lineSegment部分。 - Ripi2
@Ripi2没错。我更新了问题,修复了它并展示了新的结果。 - Vinícius Lara
1个回答

1
你想要将从glm::vec3(this->cursorCoordinate.x, this->cursorCoordinate.y, 0.0)glm::vec3(this->cursorCoordinate.x, this->cursorCoordinate.y, 1.0)的射线与世界空间中的网格相交,而不是模型空间(立方体)。 你需要跳过this.modelMatrix
glm::vec3 pointInitial = glm::unProject(
    glm::vec3(this->cursorCoordinate.x, this->cursorCoordinate.y, 0.0),
    this->viewMatrix,
    this->projectionMatrix,
    this->viewPort);

glm::vec3 pointFinal = glm::unProject(
    glm::vec3(this->cursorCoordinate.x, this->cursorCoordinate.y, 1.0),
    this->viewMatrix,
    this->projectionMatrix,
    this->viewPort);

无论如何,this->modelMatrix * this->viewMatrix都是不正确的。如果您想在模型空间中与射线相交,则必须使用this->viewMatrix * this->modelMatrix。矩阵乘法不是可交换的

感谢您的帮助。您之前的所有答案都很好,帮助我解决了问题。对于未来的读者:请记得检查视口、OpenGL坐标系统,正确获取方向向量并将其归一化。 - Vinícius Lara

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