将鼠标坐标转换为世界空间坐标

问题描述 投票:0回答:2

我正在使用 GLFW,我想通过窗口上的鼠标坐标获取世界空间坐标,以在单击选定位置时绘制对象。首先,我试图仅使用矩阵变换来获取这个坐标,但结果我没有得到任何有意义的东西。

glfwGetCursorPos(window, &xPos, &yPos);
mat4 inverse_projection = glm::inverse(projection);
mat4 inverse_view = glm::inverse(view);

GLdouble normalized_coord2D_x = (2.0 * xPos / -1.0),
    normalized_coord2D_y = (2.0 * yPos / -1.0);

vec4 worldCoordNear;
vec4 worldCoordFar;

vec4 normalizedCoordNear = vec4(normalized_coord2D_x, normalized_coord2D_y, -1.0, 1.0);
vec4 clipCoordNear = normalizedCoordNear;
vec4 eyeCoordNear = inverse_projection * clipCoordNear;
worldCoordNear /= worldCoordNear.w;

vec4 normalizedCoordFar = vec4(normalized_coord2D_x, normalized_coord2D_y, 1.0, 1.0);
vec4 clipCoordFar = normalizedCoordFar;
vec4 eyeCoordFar = inverse_projection * clipCoordFar;
worldCoordFar = inverse_view * eyeCoordFar;
worldCoordFar /= worldCoordFar.w;

现在我放弃了该解决方案并尝试在简单的 2D 场景上使用 gluUnProject 解决问题,我的函数如下所示:

void mouseButtonCallback(GLFWwindow *window, int button, int action, int mods)
{
    if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) {
    std::cout << "Left button pressed" << std::endl;

    GLdouble xPos, yPos;
    glfwGetCursorPos(window, &xPos, &yPos);

    GLint viewport[4];
    GLdouble modelview[16];
    GLdouble projection[16];
    GLfloat winX, winY, winZ;
    GLdouble posX, posY, posZ;

    glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
    glGetDoublev(GL_PROJECTION_MATRIX, projection);
    glGetIntegerv(GL_VIEWPORT, viewport);

    winX = (float)xPos;
    winY = (float)viewport[3] - (float)yPos;
    glReadPixels(xPos, int(winY), 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, &winZ);

    gluUnProject(winX, winY, winZ, modelview, projection, viewport, &posX, &posY, &posZ);
    }
}

我收到错误:

LNK2019 中引用的未解析的外部符号 _gluUnProject@48 函数“void __cdecl mouseButtonCallback(结构 GLFW窗口*,int,int,int)" (?mouseButtonCallback@@YAXPAUGLFWwindow@@HHH@Z)

我正在开发 VS2015,这就是我的内容:

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <math.h>
#include <iostream>
#include <GL/GLU.h>
#include <Windows.h>

值得指出的是,我使用 NuGet Packages 下载的 glu 库

我将非常感谢所有帮助以及如何解决问题的解释。

c++ opengl glfw
2个回答
0
投票

基本上,您的投影矩阵将从相机/眼睛空间到剪辑空间获取顶点,然后进行透视划分以获得标准化的设备坐标。然后您提到的使用该窗口变换的视口将应用于其上以获得屏幕坐标。 gluUnProject 正在以相反的顺序为您执行此操作。所以请放心,它会带来良好的价值。


0
投票

准确了解您要做什么以及起作用的变量非常重要。因此,要将鼠标坐标转换为可以与模型顶点交互的坐标,就像这样。

在屏幕空间中,坐标从左上角 (0, 0) 开始,到右下角结束(屏幕宽度、屏幕高度)

世界空间使用 x 轴和 y 轴上均介于 -1 和 1 之间的网格系统进行操作。所以你要做的就是将基于宽度/高度的坐标转换为基于 -1/1 的坐标。

为此,请将坐标系和当前位置视为字符串上的距离。鼠标坐标的当前位置就是您的鼠标移动了该字符串总距离的 X%。

我发现最有效的转换方法使用以下变量;世界空间网格的总大小,即值 2。在特定轴上行驶的距离的百分比,即 x 或 y 坐标分别除以宽度或高度。最终变量的偏移量为 1,这是必需的,因为世界空间中屏幕的左上角是 (-1, 1),而不是 (0,0)。

转换当前 x 轴的方程式如下所示:

float worldX = 2*(mouseX/screenWidth)-1;

y 轴的方程几乎相同。由于视口变换的工作方式,2 和 1 常量值的符号被反转。 Y 轴方程如下所示:

float worldY = -2*(mouseY/screenHeight)+1;

需要注意的是,系统的实际屏幕分辨率可能会导致上述方程无法产生准确的结果。为了确保正确的精度,请根据显示器的实际宽高比设置窗口的宽度和高度。如果您不这样做,您将必须手动调整窗口大小,并且帧缓冲区大小回调将纠正该问题。

© www.soinside.com 2019 - 2024. All rights reserved.