c++ - 在屏幕空间中拖动后,OpenGL对象会变形

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

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

gl_Position = projection * view * model * vec4(aPos, 1.0);
因此,我认为我应该求反(投影* View ),然后将它们乘以agian以获得将应用于模型矩阵的变换。
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());
当我拖动该对象时,该对象正在跟随鼠标移动。但是如果我从另一个角度看,这个物体就会发生很大的变形。那我做错了什么? (投影* View )应该反转吗?
拖动之前骰子:

拖动后骰子:

您可以从其他角度看到变形:

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

更新:我仅通过保留位置翻译来设法解决了该问题。因此,我怀疑转换中的左上方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));

最佳答案

您可以省略矩阵转换,而只是查询屏幕上的光标位置。如果您使用的是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
让我们用摄像机坐标系定义摄像机,其中 vector u指向屏幕的右侧, vector v指向屏幕的顶部, vector 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;

关于c++ - 在屏幕空间中拖动后,OpenGL对象会变形,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62978829/

相关文章:

c++ - C++ 中 vector push_back 操作的类型转换

c++ - 静态库调用错误: Exception: "A null reference pointer was passed to the stub." (using winsock2 Win32)

c++ - 如何在 Visual Studio 2010 中设置宏?

c++ - 在 OpenGL 中旋转立方体

c++ - 为什么我的 vector 不能正确旋转 OpenGL/GLM?

c++ - SDL 与 WSL

c++ - OpenGL 使用 std::vector 和 glm::vec3

c++ - 存在冲突符号时使用一个或多个命名空间?

Java OpenGL 仅蓝色纹理

opengl - OpenGL 纹理坐标是否必须在 0-1 范围内