1

我想在OpenGL中用鼠标位置偏移拖动一个对象。渲染管道是这样的。

gl_Position = projection * view * model * vec4(aPos, 1.0);

所以我想我应该反转(投影*视图)然后将它们相乘以获得将应用于模型矩阵的转换。

glm::mat4 CalculateDragTransform(double xOffset, double yOffset) {
    double x = (2 * xOffset) / m_width;
    double y = (2 * yOffset) / m_height;
    glm::mat4 projection = glm::perspective(glm::radians(m_camera->GetFOV()),
                                            (float) m_width /
                                            (float) m_height, 0.1f,
                                            100.0f);
    glm::mat4 view = m_camera->GetViewMatrix();
    glm::mat4 transform = glm::translate(glm::mat4(1.0), glm::vec3(x, y, 0));
    return glm::inverse(projection * view) * transform * projection * view;
m_objects[index]->SetModelMatrix(transform * m_objects[index]->GetModelMatrix());

当我拖动它时,该对象正在跟随鼠标移动。但是如果我从其他角度看,这个物体会严重变形。那么我做错了什么?(投影*视图)应该倒置吗?

拖动前的骰子:
拖动前骰子

拖动后的骰子:
拖动后骰子

您可以从其他角度看到失真:
你可以从其他角度看到失真

失真的一个更明显的例子:
失真的一个更明显的例子

更新:我设法通过仅保留位置转换来解决问题(某种)。所以我怀疑转换中左上角的 3x3 矩阵有问题。调试的时候发现第四行的前三列不是零,这是绝对错误的!但我不明白是什么原因造成的。这种现象只有在我使用 glm::perspective 作为投影矩阵时才会发生。使用 glm::ortho 也是一种无需丢弃左上角 3x3 矩阵的解决方案。

    glm::mat4 view = m_camera->GetViewMatrix();
    glm::mat4 transform = glm::translate(glm::mat4(1.0), glm::vec3(x, y, 0));
    transform = glm::inverse(projection * view) * transform * projection * view;
    float x = transform[3][0];
    float y = transform[3][1];
    float z = transform[3][2];
    transform = glm::translate(glm::mat4(1.0f), glm::vec3(x, y, z));
4

1 回答 1

0

您可以省略矩阵转换,只查询屏幕上的光标位置。如果您使用的是 GLFW,它看起来像这样

glm::vec2 mouse_pos = glm::vec2(0.f);
void mouse_callback(GLFWwindow* window, double xpos, double ypos) {
    mouse_pos = glm::vec2(xpos / width - 0.5, 1.0 - ypos / height - 0.5);
}

你会用它

GLFWwindow* window = ... ;
glfwSetCursorPosCallback(window, mouse_callback);

这样,我们可以得到鼠标在屏幕上的位置,中心在哪里,glm::vec2(0)x 和 y 的范围都从+1.0-1.0。有关 GLRF 如何处理鼠标位置的更多信息,请参阅https://www.glfw.org/docs/3.0/group__input.html#ga01d37b6c40133676b9cea60ca1d7c0cc

让我们用相机坐标系定义相机,其中矢量u指向屏幕右侧,矢量v指向屏幕顶部,矢量w指向负观看方向。

要获得 3d 位置,相机视图方向也-w可以随视野 (fov) 角旋转。

float inv_aspect_ratio = height / width;
glm::mat4 rotation_horizontal = glm::rotate(glm::mat4(1.f), -0.5f * fov * mouse_pos.x, v);
glm::mat4 rotation_vertical = glm::rotate(glm::mat4(1.f), -0.5f * fov * inv_aspect_ratio
    * mouse_pos.y, u);

fov 是为宽度定义的。这样,高度的 fov 可以通过乘以屏幕的反纵横比来计算。

对于最后一步,将旋转应用于负相机方向-w,并指定与相机原点的距离。

glm::vec3 dice_direction = glm::vec3(rotation_vertical * rotation_horizontal * glm::vec4(-w, 0.f));
float dice_distance_from_camera
glm::vec3 dice_position = dice_direction * dice_distance_from_camera;
于 2020-07-19T23:11:42.650 回答