我想在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/