我有鼠标坐标: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;
}
答案 0 :(得分:1)
一般来说,你应该使用Matrix4f.unproject
,所以@httpdigest在他的回答中证明了这一点。
所以我想专注于背景:
为什么坐标x,y相同?
坐标是相同的,因为源的x
和y
坐标是相同的,并且在乘以逆投影矩阵后没有透视分割。操作mul
不执行透视划分,它将Vector4f
转换为Matrix4f
,结果也是Vector4f
类型。
此外,与逆投影矩阵相乘的源坐标必须是规范化设备坐标,其中x
,y
和z
在[-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点的映射。
相机平截头体(截头金字塔)中的眼睛空间坐标被映射到立方体(标准化设备坐标)。
因此,视口上的x
和y
坐标取决于深度(视图空间z
坐标)。
答案 1 :(得分:1)
您似乎正在使用的矩阵库JOML通过以下代码(适用于您的代码)提供此操作(通常称为" unprojecting"):
Vector3f worldCoords = new Matrix4f(pMatrix).mul(view).unproject(x, y, z,
new int[] { 0, 0, wdwWidth, wdwHeight }, new Vector3f());