翻译到世界坐标

时间:2018-05-15 13:20:10

标签: java opengl opengl-es opengl-es-2.0 lwjgl

我有鼠标坐标:mousePos,矩阵视图view和透视投影矩阵pMatrix

我将坐标转换为世界:我找到逆投影矩阵和逆矩阵视图,并乘以鼠标的坐标。原点的坐标为z = 4,结尾的坐标为z = -100

在第一种情况下,我得到坐标mouseDir1 = (-0.1985 0.02887 4),在第二种情况下得到mouseDir2 = (-0.1985 0.02887 -100)

为什么坐标x, y相同?

private Vector3f getCoord(MouseInput mouseInput,float z){
        int wdwWitdh = 640;
        int wdwHeight =640;

        Vector2d mousePos = mouseInput.getCurrentPos();
        float x = (float)(2 * mousePos.x) / (float)wdwWitdh - 1.0f;
        float y = 1.0f - (float)(2 * mousePos.y) / (float)wdwHeight;

        Matrix4f invProjectionMatrix = new Matrix4f();
        invProjectionMatrix.set(pMatrix);
        invProjectionMatrix.invert();
        Vector4f tmpVec = new Vector4f();
        tmpVec.set(x, y, z, 0);
        tmpVec.mul(invProjectionMatrix);
        tmpVec.z = z;
        tmpVec.w = 0.0f;

        Matrix4f viewMatrix = new Matrix4f().set(view);
        Matrix4f invViewMatrix = new Matrix4f();
        invViewMatrix.set(viewMatrix);
        invViewMatrix.invert();
        tmpVec.mul(invViewMatrix);
        Vector3f mouseDir1 = new Vector3f();
        mouseDir1.set(tmpVec.x, tmpVec.y, tmpVec.z);

        ///ТЕСТОВАЯ ПРОВЕРКА Z=-100;
        //конеч координаты луча
        Vector4f tmpVec1 = new Vector4f();
        tmpVec1.set(x, y, -100, 1.0f);
        tmpVec1.mul(invProjectionMatrix);
        tmpVec1.z =-100f;
        tmpVec1.w = 0.0f;
        tmpVec1.mul(invViewMatrix);
        Vector3f mouseDir2 = new Vector3f();
        mouseDir2.set(tmpVec1.x, tmpVec1.y, tmpVec1.z);
        System.out.println();
        return mouseDir1;
    }

输出光线: enter image description here

2 个答案:

答案 0 :(得分:1)

一般来说,你应该使用Matrix4f.unproject,所以@httpdigest在他的回答中证明了这一点。

所以我想专注于背景:

  

为什么坐标x,y相同?

坐标是相同的,因为源的xy坐标是相同的,并且在乘以逆投影矩阵后没有透视分割。操作mul不执行透视划分,它将Vector4f转换为Matrix4f,结果也是Vector4f类型。

此外,与逆投影矩阵相乘的源坐标必须是规范化设备坐标,其中xyz在[-1.0,1.0]范围内]。 z=-1.0是最小深度(近平面),z=1.0是最大深度(远平面)。

注意,视线(视线)投影到视口上当然是一个重点。

当你用(逆)投影矩阵进行乘法时,结果不是Cartesian coordinates,而是Homogeneous coordinates。 您必须执行Perspective divide才能从齐次坐标转换为笛卡尔坐标:

// transform x and y mouse coordinate to normalized device space 
Vector2d mousePos = mouseInput.getCurrentPos();
float x = (float)(2 * mousePos.x) / (float)wdwWitdh - 1.0f;
float y = 1.0f - (float)(2 * mousePos.y) / (float)wdwHeight;

....

// normalized device coordinate to view space coordinate (near plane)
Vector4f tmpVec = new Vector4f();
tmpVec.set(x, y, -1.0f, 1.0f);
tmpVec.mul(invProjectionMatrix);

// perspective divide
tmpVec.x = tmpVec.x / tmpVec.w;
tmpVec.y = tmpVec.y / tmpVec.w;
tmpVec.z = tmpVec.z / tmpVec.w;
tmpVec.w = 1.0;

// normalized device coordinate to view space coordinate (far plane)
Vector4f tmpVec1 = new Vector4f();
tmpVec1.set(x, y, 1.0f, 1.0f);
tmpVec1.mul(invProjectionMatrix);

// perspective divide
tmpVec1.x = tmpVec1.x / tmpVec1.w;
tmpVec1.y = tmpVec1.y / tmpVec1.w;
tmpVec1.z = tmpVec1.z / tmpVec1.w;
tmpVec1.w = 1.0;


投影矩阵描述了从场景的3D点到视口的2D点的映射。投影矩阵从视图空间变换到剪辑空间。通过除以剪辑的w分量,剪辑空间中的坐标转换为范围(-1,-1,-1)到(1,1,1)范围内的规范化设备坐标(NDC)坐标。

在Perspective Projection中,投影矩阵描述了从针孔相机到视口的2D点看世界中3D点的映射。
相机平截头体(截头金字塔)中的眼睛空间坐标被映射到立方体(标准化设备坐标)。

enter image description here

因此,视口上的xy坐标取决于深度(视图空间z坐标)。

答案 1 :(得分:1)

您似乎正在使用的矩阵库JOML通过以下代码(适用于您的代码)提供此操作(通常称为" unprojecting"):

Vector3f worldCoords = new Matrix4f(pMatrix).mul(view).unproject(x, y, z, 
  new int[] { 0, 0, wdwWidth, wdwHeight }, new Vector3f());

JavaDoc:https://joml-ci.github.io/JOML/apidocs/org/joml/Matrix4f.html#unproject-float-float-float-int:A-org.joml.Vector3f-