Java OpenGL - 从窗口到世界空间的鼠标位置

时间:2015-12-27 17:31:36

标签: java opengl mouseevent

我尝试将窗口鼠标坐标(0/0是左上角)转换为世界空间坐标。我只是试图通过this描述来解决它。这是我的代码:

public void showMousePosition(float mx, float my){
    Matrix4f projectionMatrix = camera.getProjectionMatrix();
    Matrix4f viewMatrix = camera.getViewMatrix();
    Matrix4f projMulView = projectionMatrix.mul(viewMatrix);
    projMulView.invert();
    float px = ((2*mx)/650)-1;
    float py = ((2*my)/650)-1;
    Vector4f vec4 = new Vector4f(px, py*(-1), 0.0f, 1.0f);
    vec4.mul(projMulView);
    vec4.w = 1.0f / vec4.w;
    vec4.x *= vec4.w;
    vec4.y *= vec4.w;
    vec4.z *= vec4.w;

    System.out.println(vec4.x + ", " + vec4.y);
}

但那并非100%正确。我在世界空间的0 / -11上有一个Object,当我将鼠标移动到这一点时,我的功能就是0 / 9,8。当我走到窗口的左侧时,x值为5,6,但它应该是28。

有人知道我的代码有什么问题吗?

1 个答案:

答案 0 :(得分:0)

首先,您的代码表示您的窗口大小始终为width = 650,height = 650。

然后在z = 0时获得该位置。但是这个z位于屏幕空间中,因此当您更改摄像机位置和方向时它会发生变化。通常,您使用glReadPixel从深度缓冲区获取此信息。在这种情况下你应该这样做。

然而,还有另一种方法可以做到这一点。在我将分享的代码中,我正在寻找光线(从鼠标位置生成)和平面(0,0,0)与普通(0,1,0)之间的交集,我希望这会有所帮助。

/*Given the inverse PV (projection*view) matrix, the position of the mouse on screen and the size of the screen, transforms the screen coordinates to world coordinates*/
glm::vec3 Picking::OnWorld(glm::mat4 const& m_inv, glm::vec2 const & spos,size_t width, size_t height) {
float x = spos.x;
float y = spos.y;

y = height - y;

//InputOrigin, start of the ray for intersection with plane 
glm::vec4 inputO = glm::vec4(x / width*2.0f - 1.0f, y / height*2.0f - 1.0f, -1.0f, 1.0f);   //transforms screen position to the unit cube range
glm::vec4 resO = m_inv*inputO;      //transforms to world space
if (resO.w == 0.0f)  
    return glm::vec3(-1); //return an invalid value to show a problem during a calculation, normally this means that the m_inv matrix was incorrect

resO /= resO.w;     //homogeneous division

glm::vec4 inputE = inputO;      //inputEnd, the end of the ray
inputE.z = 1.0;

//End of ray to world space
glm::vec4 resE = m_inv*inputE;

//checks that the coordinates are correct
if (resE.w == 0.0f)
    return glm::vec3(-1); //return an invalid value to show a problem during a calculation, normally this means that the m_inv matrix was incorrect

resE /= resE.w;

//ray for intersection
glm::vec3 ray = glm::vec3(resE - resO);     //vector between z=-1 and z=1

glm::vec3 normalRay = glm::normalize(ray);
glm::vec3 normalPlane = glm::vec3(0, 1, 0);     //detects collision with plane 0, normal 1
float denominator = glm::dot(normalRay, normalPlane);       
if (denominator == 0)
    return glm::vec3(-1);   //return an invalid value to show a problem during a calculation, normally this means that the m_inv matrix was incorrect

float numerator = glm::dot(glm::vec3(resO), normalPlane);

//intersection between ray and plane
glm::vec3 result = glm::vec3(resO) - normalRay*(numerator / denominator);

return result;
}

可以从此链接读取交集的数学运算: https://www.cs.princeton.edu/courses/archive/fall00/cs426/lectures/raycast/sld017.htm