glGetFloat(GL_MODELVIEW_MATRIX, modelview) returns 单位矩阵
glGetFloat(GL_MODELVIEW_MATRIX, modelview) returns an identity matrix
我正在尝试将 3d 点坐标转换为 2d 屏幕坐标。
但是,问题是当我实现它和 运行 程序时,即使我改变了相机位置,输出也没有变化。尽管我可以完全看到 3d 模型,但输出通常超出屏幕坐标范围(因此任何点或三角形都不会超出屏幕坐标范围)。
3d坐标转2d坐标的方法:
public Vector2f get2DFrom3D(float x, float y, float z)
{
FloatBuffer screen_coords = BufferUtils.createFloatBuffer(4);
IntBuffer viewport = BufferUtils.createIntBuffer(16);
FloatBuffer modelview = BufferUtils.createFloatBuffer(16);
FloatBuffer projection = BufferUtils.createFloatBuffer(16);
GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelview);
System.out.println("modelview:");
displayFloatBuffer(modelview);
GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projection);
System.out.println("projection:");
displayFloatBuffer(projection);
GL11.glGetInteger(GL11.GL_VIEWPORT, viewport);
System.out.println("viewport:");
displayIntBuffer(viewport);
boolean result = GLU.gluProject(x, y, z, modelview, projection, viewport, screen_coords);
if (result)
{
System.out.printf("Convert [ %6.2f %6.2f %6.2f ] -> Screen [ %4d %4d ]\n", x, y, z, (int)screen_coords.get(0), (int)(screen_coords.get(3)-screen_coords.get(1)));
return new Vector2f((int)screen_coords.get(0), (int)(screen_coords.get(3)-screen_coords.get(1)));
}
else
{
return null;
}
}
投影矩阵通过此方法创建并直接加载到顶点着色器中:
private void createProjectionMatrix(){
float aspectRatio = (float) Display.getWidth() / (float) Display.getHeight();
float y_scale = (float) ((1f / Math.tan(Math.toRadians(FOV / 2f))) * aspectRatio);
float x_scale = y_scale / aspectRatio;
float frustum_length = FAR_PLANE - NEAR_PLANE;
projectionMatrix = new Matrix4f();
projectionMatrix.m00 = x_scale;
projectionMatrix.m11 = y_scale;
projectionMatrix.m22 = -((FAR_PLANE + NEAR_PLANE) / frustum_length);
projectionMatrix.m23 = -1;
projectionMatrix.m32 = -((2 * NEAR_PLANE * FAR_PLANE) / frustum_length);
projectionMatrix.m33 = 0;
}
顶点着色器:
#version 400 core
in vec3 position;
uniform mat4 transformationMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
void main(void) {
vec4 worldPosition = transformationMatrix * vec4(position, 1);
gl_Position = projectionMatrix * viewMatrix * worldPosition;
}
渲染器:
public void render(Entity entity, int displayMode) {
RawModel model = entity.getModel();
shader.start();
GL30.glBindVertexArray(model.getVaoID());
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
Matrix4f transformationMatrix = Maths.createTransformationMatrix(entity.getPosition(), entity.getRotX(),
entity.getRotY(), entity.getRotZ(), entity.getScale());
shader.loadTransformationMatrix(transformationMatrix);
GL11.glDrawElements(GL11.GL_TRIANGLES, model.getVertexAmount(), GL11.GL_UNSIGNED_INT, 0);
GL20.glDisableVertexAttribArray(0);
GL20.glDisableVertexAttribArray(1);
GL30.glBindVertexArray(0);
shader.stop();
}
然后,我调试代码并看到:
GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelView);
GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projection);
这些行只是没有采用我定义的实际矩阵值。它们只是 4 阶单位矩阵。然后,我搜索 glMatrixMode 来设置该矩阵或设置 gl_ModelViewMatrix,但事实证明我使用的 opengl 版本不再支持这些。
所以,我认为问题是我与这些变量有某种关联,我需要以某种方式设置它们。最后但同样重要的是,这里是 get2DFrom3D 方法的输出:
modelview:
1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0
0.0 0.0 1.0 0.0
0.0 0.0 0.0 1.0
projection:
1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0
0.0 0.0 1.0 0.0
0.0 0.0 0.0 1.0
viewport:
0 0 1209 891
0 0 0 0
0 0 0 0
0 0 0 0
我认为只有视口是正确的,但模型视图和投影矩阵看起来没有加载为它们计算的值。
注意:我目前使用的是 lwjgl 2.9.3。
我找到了解决问题的方法,而且效果很好。这是我的新 get2DFrom3D 方法:
public Vector2f get2DFrom3D(float x, float y, float z)
{
FloatBuffer screen_coords = BufferUtils.createFloatBuffer(4);
IntBuffer viewport = BufferUtils.createIntBuffer(16);
FloatBuffer modelview = BufferUtils.createFloatBuffer(16);
FloatBuffer projection = BufferUtils.createFloatBuffer(16);
Matrix4f modelviewMatrix = new Matrix4f();
Matrix4f transformationMatrix = new Matrix4f();
Matrix4f.mul(transformationMatrix
, Maths.createViewMatrix(camera)
, modelviewMatrix);
modelviewMatrix.store(modelview);
modelview.rewind();
projectionMatrix.store(projection);
projection.rewind();
GL11.glGetInteger(GL11.GL_VIEWPORT, viewport);
boolean result = GLU.gluProject(x, y, z, modelview, projection, viewport, screen_coords);
if (result)
{
Vector2f vector = new Vector2f((int)screen_coords.get(0), (int)(screen_coords.get(1)));
return vector;
}
else
{
return null;
}
}
而不是使用 glGetFloat 方法来获取模型视图和投影矩阵。我改为使用我已经在其他 类 中创建的矩阵,并将这些矩阵作为参数传递。然后,我将矩阵转换为缓冲区,以便我可以使用它们。倒带后,我终于能够从 gluProject 中获取点的正确屏幕坐标。
尽管问题已解决,但我仍然不知道为什么这些行不起作用:
GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelview);
System.out.println("modelview:");
displayFloatBuffer(modelview);
GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projection);
我正在尝试将 3d 点坐标转换为 2d 屏幕坐标。
但是,问题是当我实现它和 运行 程序时,即使我改变了相机位置,输出也没有变化。尽管我可以完全看到 3d 模型,但输出通常超出屏幕坐标范围(因此任何点或三角形都不会超出屏幕坐标范围)。
3d坐标转2d坐标的方法:
public Vector2f get2DFrom3D(float x, float y, float z)
{
FloatBuffer screen_coords = BufferUtils.createFloatBuffer(4);
IntBuffer viewport = BufferUtils.createIntBuffer(16);
FloatBuffer modelview = BufferUtils.createFloatBuffer(16);
FloatBuffer projection = BufferUtils.createFloatBuffer(16);
GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelview);
System.out.println("modelview:");
displayFloatBuffer(modelview);
GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projection);
System.out.println("projection:");
displayFloatBuffer(projection);
GL11.glGetInteger(GL11.GL_VIEWPORT, viewport);
System.out.println("viewport:");
displayIntBuffer(viewport);
boolean result = GLU.gluProject(x, y, z, modelview, projection, viewport, screen_coords);
if (result)
{
System.out.printf("Convert [ %6.2f %6.2f %6.2f ] -> Screen [ %4d %4d ]\n", x, y, z, (int)screen_coords.get(0), (int)(screen_coords.get(3)-screen_coords.get(1)));
return new Vector2f((int)screen_coords.get(0), (int)(screen_coords.get(3)-screen_coords.get(1)));
}
else
{
return null;
}
}
投影矩阵通过此方法创建并直接加载到顶点着色器中:
private void createProjectionMatrix(){
float aspectRatio = (float) Display.getWidth() / (float) Display.getHeight();
float y_scale = (float) ((1f / Math.tan(Math.toRadians(FOV / 2f))) * aspectRatio);
float x_scale = y_scale / aspectRatio;
float frustum_length = FAR_PLANE - NEAR_PLANE;
projectionMatrix = new Matrix4f();
projectionMatrix.m00 = x_scale;
projectionMatrix.m11 = y_scale;
projectionMatrix.m22 = -((FAR_PLANE + NEAR_PLANE) / frustum_length);
projectionMatrix.m23 = -1;
projectionMatrix.m32 = -((2 * NEAR_PLANE * FAR_PLANE) / frustum_length);
projectionMatrix.m33 = 0;
}
顶点着色器:
#version 400 core
in vec3 position;
uniform mat4 transformationMatrix;
uniform mat4 projectionMatrix;
uniform mat4 viewMatrix;
void main(void) {
vec4 worldPosition = transformationMatrix * vec4(position, 1);
gl_Position = projectionMatrix * viewMatrix * worldPosition;
}
渲染器:
public void render(Entity entity, int displayMode) {
RawModel model = entity.getModel();
shader.start();
GL30.glBindVertexArray(model.getVaoID());
GL20.glEnableVertexAttribArray(0);
GL20.glEnableVertexAttribArray(1);
Matrix4f transformationMatrix = Maths.createTransformationMatrix(entity.getPosition(), entity.getRotX(),
entity.getRotY(), entity.getRotZ(), entity.getScale());
shader.loadTransformationMatrix(transformationMatrix);
GL11.glDrawElements(GL11.GL_TRIANGLES, model.getVertexAmount(), GL11.GL_UNSIGNED_INT, 0);
GL20.glDisableVertexAttribArray(0);
GL20.glDisableVertexAttribArray(1);
GL30.glBindVertexArray(0);
shader.stop();
}
然后,我调试代码并看到:
GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelView);
GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projection);
这些行只是没有采用我定义的实际矩阵值。它们只是 4 阶单位矩阵。然后,我搜索 glMatrixMode 来设置该矩阵或设置 gl_ModelViewMatrix,但事实证明我使用的 opengl 版本不再支持这些。
所以,我认为问题是我与这些变量有某种关联,我需要以某种方式设置它们。最后但同样重要的是,这里是 get2DFrom3D 方法的输出:
modelview:
1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0
0.0 0.0 1.0 0.0
0.0 0.0 0.0 1.0
projection:
1.0 0.0 0.0 0.0
0.0 1.0 0.0 0.0
0.0 0.0 1.0 0.0
0.0 0.0 0.0 1.0
viewport:
0 0 1209 891
0 0 0 0
0 0 0 0
0 0 0 0
我认为只有视口是正确的,但模型视图和投影矩阵看起来没有加载为它们计算的值。
注意:我目前使用的是 lwjgl 2.9.3。
我找到了解决问题的方法,而且效果很好。这是我的新 get2DFrom3D 方法:
public Vector2f get2DFrom3D(float x, float y, float z)
{
FloatBuffer screen_coords = BufferUtils.createFloatBuffer(4);
IntBuffer viewport = BufferUtils.createIntBuffer(16);
FloatBuffer modelview = BufferUtils.createFloatBuffer(16);
FloatBuffer projection = BufferUtils.createFloatBuffer(16);
Matrix4f modelviewMatrix = new Matrix4f();
Matrix4f transformationMatrix = new Matrix4f();
Matrix4f.mul(transformationMatrix
, Maths.createViewMatrix(camera)
, modelviewMatrix);
modelviewMatrix.store(modelview);
modelview.rewind();
projectionMatrix.store(projection);
projection.rewind();
GL11.glGetInteger(GL11.GL_VIEWPORT, viewport);
boolean result = GLU.gluProject(x, y, z, modelview, projection, viewport, screen_coords);
if (result)
{
Vector2f vector = new Vector2f((int)screen_coords.get(0), (int)(screen_coords.get(1)));
return vector;
}
else
{
return null;
}
}
而不是使用 glGetFloat 方法来获取模型视图和投影矩阵。我改为使用我已经在其他 类 中创建的矩阵,并将这些矩阵作为参数传递。然后,我将矩阵转换为缓冲区,以便我可以使用它们。倒带后,我终于能够从 gluProject 中获取点的正确屏幕坐标。
尽管问题已解决,但我仍然不知道为什么这些行不起作用:
GL11.glGetFloat(GL11.GL_MODELVIEW_MATRIX, modelview);
System.out.println("modelview:");
displayFloatBuffer(modelview);
GL11.glGetFloat(GL11.GL_PROJECTION_MATRIX, projection);