无法鼠标选择在帧缓冲区中渲染的四边形

时间:2019-06-23 20:13:46

标签: opengl lwjgl picking mouse-picking ray-picking

努力用鼠标选择一个点/四点。我相信我在错误的空间中使用了坐标,或者也许没有考虑帧缓冲区的位置/大小(这是主窗口的子窗口)。

试图转换为各种不同的坐标空间,也将模型矩阵求逆。当前在世界空间中投射一条射线(希望正确),并试图将其与点的(四)位置进行比较。该点是在本地空间中指定的,但是该实体是在原点(0f,0f,0f)处渲染的,因此我认为它在世界空间中应该没有任何不同吗?

要获取世界空间中的鼠标射线,

private fun calculateRay(): Vector3f {
        val mousePosition = Mouse.getCursorPosition()
        val ndc = toDevice(mousePosition)
        val clip = Vector4f(ndc.x, ndc.y, -1f, 1f)
        val eye = toEye(clip)
        return toWorld(eye)
    }

private fun toDevice(mousePosition: Vector2f): Vector2f {
        mousePosition.x -= fbo.x // Correct thing to do?
        mousePosition.y -= fbo.y
        val x = (2f * mousePosition.x) / fboSize.x - 1
        val y = (2f * mousePosition.y) / fboSize.y - 1
        return Vector2f(x, y)
    }

private fun toEye(clip: Vector4f): Vector4f {
        val invertedProjection = Matrix4f(projectionMatrix).invert()
        val eye = invertedProjection.transform(clip)
        return Vector4f(eye.x, eye.y, -1f, 0f)
    }

    private fun toWorld(eye: Vector4f): Vector3f {
        val viewMatrix = Maths.createViewMatrix(camera)
        val invertedView = Matrix4f(viewMatrix).invert()
        val world = invertedView.transform(eye)
        return Vector3f(world.x, world.y, world.z).normalize()
    }

当悬停在一个点(11.25,-0.75)上时,射线坐标为(0.32847548,0.05527423)。我尝试归一化该点的位置,但仍然不匹配。

感觉像我丢失/忽略了某些东西,或者只是错误地操纵了坐标系。任何见解将不胜感激,谢谢。

编辑以获取更多信息:

四边形的顶点为: (-0.5f, 0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f, -0.5f)

将矩阵加载到着色器:

private fun loadMatrices(position: Vector3f, rotation: Float, scale: Float, viewMatrix: Matrix4f, currentRay: Vector3f) {
        val modelMatrix = Matrix4f()
        modelMatrix.translate(position)
        modelMatrix.m00(viewMatrix.m00())
        modelMatrix.m01(viewMatrix.m10())
        modelMatrix.m02(viewMatrix.m20())
        modelMatrix.m10(viewMatrix.m01())
        modelMatrix.m11(viewMatrix.m11())
        modelMatrix.m12(viewMatrix.m21())
        modelMatrix.m20(viewMatrix.m02())
        modelMatrix.m21(viewMatrix.m12())
        modelMatrix.m22(viewMatrix.m22())
        modelMatrix.rotate(Math.toRadians(rotation.toDouble()).toFloat(), Vector3f(0f, 0f, 1f))
        modelMatrix.scale(scale)
        shader.loadModelViewMatrix(viewMatrix.mul(modelMatrix))
        shader.loadProjectionMatrix(projectionMatrix)
    }

在顶点着色器中计算gl_Position:

gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 0.0, 1.0);

编辑2:在根据拉比德的注释阅读了更多资料后,更改了我的代码。不知道我是否需要视口大小除以2(我有视网膜MacBook显示屏)。

mousePosition.sub(fboPosition)
        val w = (fboSize.x / 2).toInt()
        val h = (fboSize.y / 2).toInt()
        val y = h - mousePosition.y

        val viewMatrix = Maths.createViewMatrix(camera)
        val origin = Vector3f()
        val dir = Vector3f()
        Matrix4f(projectionMatrix).mul(viewMatrix)
                                  .unprojectRay(mousePosition.x, y, intArrayOf(0, 0, w, h), origin, dir)

1 个答案:

答案 0 :(得分:2)

窗口的左上角原点为(0,0)。因此,如果得到(0,0),则如果鼠标位于窗口的左上方,则必须跳过:

mousePosition.x -= fbo.x // Correct thing to do?
mousePosition.y -= fbo.y

由于帧缓冲区的左下角是(0,0),因此必须翻转y坐标:

val y = 1 - (2f * mousePosition.y) / fboSize.y

Cartesian coordinate由(逆)投影矩阵转换时,结果为Homogeneous coordinates。您必须进行Perspective divide才能在视图空间中获得笛卡尔坐标:

val eye = invertedProjection.transform(clip)
return Vector3f(eye.x/eye.w, eye.y/eye.w, eye.z/eye.w)