【问题标题】:OpenGL Object got Distored after dragging in the Screen SpaceOpenGL 对象在屏幕空间中拖动后变形
【发布时间】:2020-11-08 17:27:16
【问题描述】:

我想在 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));

【问题讨论】:

  • “如果我从其他角度看,物体会严重变形。” - 你说的是透视变形吗?
  • 你在说什么失真?我觉得这三张照片都很好。
  • 抱歉,第三张图可能不是很明显。我上传了一张更扭曲的图片。骰子应该是一个立方体。但就像您从第四张图片中看到的那样,它看起来像是被垂直压扁了。

标签: c++ opengl glm-math opengl-3 homogenous-transformation


【解决方案1】:

您可以省略矩阵转换,只查询屏幕上的光标位置。如果你使用 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 位置,相机视图方向 a.k.a. -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;

【讨论】:

  • 感谢您的回答,但恐怕您的方法可能不适合我。我想要做的是在按住鼠标左键时拖动对象。所以我需要那个鼠标偏移位置来计算转换。不完全将对象放在光标当前所在的位置。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多