从相机坐标计算世界坐标
Calculating world coordinates from camera coordinates
我有一个以 2D 呈现的世界,我正在从顶部查看它。 Tjat 看起来像这样(地砖还没有纹理,只有随机的绿色):
在渲染我的实体之前,我像这样变换模型视图矩阵(position
是位置,zoom
是相机的变焦,ROTATION
是 45):
glScalef(this.zoom, this.zoom, 1);
glTranslatef(this.position.x, this.position.y, 0);
glRotatef(ROTATION, 0, 0, 1);
现在我想计算相机当前位置的世界坐标。我正在尝试的是用 glPushMatrix
创建一个新矩阵,然后以与摄像机变换相同的方式对其进行变换,然后获取矩阵并将给定的摄像机坐标与其相乘:
private Vector2f toWorldCoordinates(Vector2f position) {
glPushMatrix();
// do the same as when rendering
glScalef(this.zoom, this.zoom, 1);
glTranslatef(this.position.x, this.position.y, 0);
glRotatef(ROTATION, 0, 0, 1);
// get the model-view matrix
ByteBuffer m = ByteBuffer.allocateDirect(64);
m.order(ByteOrder.nativeOrder());
glGetFloatv(GL_MODELVIEW_MATRIX, m);
// calculate transformed position
float x = (position.x * m.getFloat(0)) + (position.y * m.getFloat(4)) + m.getFloat(12);
float y = (position.x * m.getFloat(1)) + (position.y * m.getFloat(5)) + m.getFloat(13);
System.out.println(x + "/" + y);
glPopMatrix();
return new Vector2f(x, y);
}
现在的问题是:这适用于 x
坐标,但是 y
坐标是错误的并且始终为 0。我是否以某种方式误用了矩阵?有没有 "smoother" 从眼睛坐标获取世界坐标的方法?
问题在于您的呼叫方式 getFloat()
。当您使用 ByteBuffer
上的索引调用它时,索引是缓冲区中开始读取浮点数的字节数,而不是浮点数。您需要将每个索引乘以 4:
float x = (position.x * m.getFloat(0)) + (position.y * m.getFloat(16)) + m.getFloat(48);
float y = (position.x * m.getFloat(4)) + (position.y * m.getFloat(20)) + m.getFloat(52);
但是鉴于 x 已经为您工作,我怀疑您可能还需要转置矩阵坐标,因此正确的代码是:
float x = (position.x * m.getFloat(0)) + (position.y * m.getFloat(4)) + m.getFloat(12);
float y = (position.x * m.getFloat(16)) + (position.y * m.getFloat(20)) + m.getFloat(28);
(巧合的是,将矩阵的第一行转置到第一列得到的索引是原来的 4 倍,因此在 x 而不是 y 的情况下,这两个错误相互抵消)。
如果您正在寻找一种更流畅的方法,请考虑使用 gluUnProject,尽管您可能需要应用一些额外的变换(它从 window 映射到对象坐标).
我有一个以 2D 呈现的世界,我正在从顶部查看它。 Tjat 看起来像这样(地砖还没有纹理,只有随机的绿色):
在渲染我的实体之前,我像这样变换模型视图矩阵(position
是位置,zoom
是相机的变焦,ROTATION
是 45):
glScalef(this.zoom, this.zoom, 1);
glTranslatef(this.position.x, this.position.y, 0);
glRotatef(ROTATION, 0, 0, 1);
现在我想计算相机当前位置的世界坐标。我正在尝试的是用 glPushMatrix
创建一个新矩阵,然后以与摄像机变换相同的方式对其进行变换,然后获取矩阵并将给定的摄像机坐标与其相乘:
private Vector2f toWorldCoordinates(Vector2f position) {
glPushMatrix();
// do the same as when rendering
glScalef(this.zoom, this.zoom, 1);
glTranslatef(this.position.x, this.position.y, 0);
glRotatef(ROTATION, 0, 0, 1);
// get the model-view matrix
ByteBuffer m = ByteBuffer.allocateDirect(64);
m.order(ByteOrder.nativeOrder());
glGetFloatv(GL_MODELVIEW_MATRIX, m);
// calculate transformed position
float x = (position.x * m.getFloat(0)) + (position.y * m.getFloat(4)) + m.getFloat(12);
float y = (position.x * m.getFloat(1)) + (position.y * m.getFloat(5)) + m.getFloat(13);
System.out.println(x + "/" + y);
glPopMatrix();
return new Vector2f(x, y);
}
现在的问题是:这适用于 x
坐标,但是 y
坐标是错误的并且始终为 0。我是否以某种方式误用了矩阵?有没有 "smoother" 从眼睛坐标获取世界坐标的方法?
问题在于您的呼叫方式 getFloat()
。当您使用 ByteBuffer
上的索引调用它时,索引是缓冲区中开始读取浮点数的字节数,而不是浮点数。您需要将每个索引乘以 4:
float x = (position.x * m.getFloat(0)) + (position.y * m.getFloat(16)) + m.getFloat(48);
float y = (position.x * m.getFloat(4)) + (position.y * m.getFloat(20)) + m.getFloat(52);
但是鉴于 x 已经为您工作,我怀疑您可能还需要转置矩阵坐标,因此正确的代码是:
float x = (position.x * m.getFloat(0)) + (position.y * m.getFloat(4)) + m.getFloat(12);
float y = (position.x * m.getFloat(16)) + (position.y * m.getFloat(20)) + m.getFloat(28);
(巧合的是,将矩阵的第一行转置到第一列得到的索引是原来的 4 倍,因此在 x 而不是 y 的情况下,这两个错误相互抵消)。
如果您正在寻找一种更流畅的方法,请考虑使用 gluUnProject,尽管您可能需要应用一些额外的变换(它从 window 映射到对象坐标).