Python 中的 OpenGL 透视矩阵
OpenGL Perspective Matrix in Python
我正在尝试在 python 中构建透视变换矩阵以用于 pyOpenGL。我的视图和模型转换工作正常,但是当我应用我的投影转换时,我得到一个空白屏幕(应该在从 (0,0,+1) 观察的原点看到一个三角形)。
我已经查看了数学,据我所知转换应该有效,所以我需要第二双眼睛来帮助找到问题。
def perspective(field_of_view_y, aspect, z_near, z_far):
fov_radians = math.radians(field_of_view_y)
f = math.tan(fov_radians/2)
a_11 = 1/(f*aspect)
a_22 = 1/f
a_33 = (z_near + z_far)/(z_near - z_far)
a_34 = -2*z_near*z_far/(z_near - z_far)
# a_33 = -(z_far + z_near)/(z_far - z_near)
# a_34 = 2*z_far*z_near/(z_far - z_near)
perspective_matrix = numpy.matrix([
[a_11, 0, 0, 0],
[0, a_22, 0, 0],
[0, 0, a_33, a_34],
[0, 0, -1, 0]
]).T
return perspective_matrix
projection_matrix = perspective(45, 600/480, 0.1, 100)
mvp_matrix = projection_matrix * view_matrix * model_matrix
我正在转置矩阵,因为我相当确定 numpy 存储矩阵转置到 OpenGL 需要它的方式。我试过在不转置的情况下发送矩阵,它对输出没有(可见的)影响。
这是顶点着色器:
#version 330 core
layout(location = 0) in vec3 position;
uniform mat4 MVP;
void main()
{
vec4 p = vec4(position, 1.0);
gl_Position = MVP * p;
}
有人可以确定我的转型可能存在的问题吗?
编辑: 我已经获取输出矩阵并手动完成计算。应用透视划分后,平截头体边缘上的所有点都出现在 NDC 框上,近点和远点的 z 值分别转换为 -1、+1(由于舍入误差,精度较低)。对我来说,这表明我的数学是正确的,问题出在别处。这是输出矩阵:
[ 1.93137085 0. 0. 0. ]
[ 0. 2.41421356 0. 0. ]
[ 0. 0. -1.002002 -1. ]
[ 0. 0. 0.2002002 0. ]
既然你说你是从 glm::perspective 开始工作的,那么让我们分析一下你的代码并与之进行比较。有一个严重的不一致:
glm::perspective
assert(aspect != valType(0));
assert(zFar != zNear);
#ifdef GLM_FORCE_RADIANS
valType const rad = fovy;
#else
valType const rad = glm::radians(fovy);
#endif
valType tanHalfFovy = tan(rad / valType(2));
detail::tmat4x4<valType> Result(valType(0));
Result[0][0] = valType(1) / (aspect * tanHalfFovy);
Result[1][1] = valType(1) / (tanHalfFovy);
Result[2][2] = - (zFar + zNear) / (zFar - zNear);
Result[2][3] = - valType(1);
Result[3][2] = - (valType(2) * zFar * zNear) / (zFar - zNear);
return Result;
注意以下行:
Result[2][2] = - (zFar + zNear) / (zFar - zNear);
将其与您的等效项进行比较:
a_33 = (z_near + z_far)/(z_near - z_far)
注意整个语句前面有一个负号(-
)。你的版本没有这个。
我已经解决问题了,发布信息以防以后有人遇到类似问题。
在构建模型、视图和投影矩阵时,我引入了行主矩阵和列主矩阵的混合。引入这些是因为 numpy 和 OpenGL 需要不同格式的矩阵。当单独操作时,这些矩阵之所以有效,是因为它们可以很容易地用 numpy 进行转置以产生正确的结果。
合并矩阵时出现问题。结果是变换以不一致且无意义的顺序应用,并且所有点都被绘制在屏幕之外。这隐藏了透视矩阵中的错误和复杂的调试。
解决方案是确保所有矩阵在存储数据的方式上保持一致(所有行主要或所有列主要)并且在发送到 OpenGL 之前进行一次转置。
我正在尝试在 python 中构建透视变换矩阵以用于 pyOpenGL。我的视图和模型转换工作正常,但是当我应用我的投影转换时,我得到一个空白屏幕(应该在从 (0,0,+1) 观察的原点看到一个三角形)。
我已经查看了数学,据我所知转换应该有效,所以我需要第二双眼睛来帮助找到问题。
def perspective(field_of_view_y, aspect, z_near, z_far):
fov_radians = math.radians(field_of_view_y)
f = math.tan(fov_radians/2)
a_11 = 1/(f*aspect)
a_22 = 1/f
a_33 = (z_near + z_far)/(z_near - z_far)
a_34 = -2*z_near*z_far/(z_near - z_far)
# a_33 = -(z_far + z_near)/(z_far - z_near)
# a_34 = 2*z_far*z_near/(z_far - z_near)
perspective_matrix = numpy.matrix([
[a_11, 0, 0, 0],
[0, a_22, 0, 0],
[0, 0, a_33, a_34],
[0, 0, -1, 0]
]).T
return perspective_matrix
projection_matrix = perspective(45, 600/480, 0.1, 100)
mvp_matrix = projection_matrix * view_matrix * model_matrix
我正在转置矩阵,因为我相当确定 numpy 存储矩阵转置到 OpenGL 需要它的方式。我试过在不转置的情况下发送矩阵,它对输出没有(可见的)影响。
这是顶点着色器:
#version 330 core
layout(location = 0) in vec3 position;
uniform mat4 MVP;
void main()
{
vec4 p = vec4(position, 1.0);
gl_Position = MVP * p;
}
有人可以确定我的转型可能存在的问题吗?
编辑: 我已经获取输出矩阵并手动完成计算。应用透视划分后,平截头体边缘上的所有点都出现在 NDC 框上,近点和远点的 z 值分别转换为 -1、+1(由于舍入误差,精度较低)。对我来说,这表明我的数学是正确的,问题出在别处。这是输出矩阵:
[ 1.93137085 0. 0. 0. ]
[ 0. 2.41421356 0. 0. ]
[ 0. 0. -1.002002 -1. ]
[ 0. 0. 0.2002002 0. ]
既然你说你是从 glm::perspective 开始工作的,那么让我们分析一下你的代码并与之进行比较。有一个严重的不一致:
glm::perspective
assert(aspect != valType(0));
assert(zFar != zNear);
#ifdef GLM_FORCE_RADIANS
valType const rad = fovy;
#else
valType const rad = glm::radians(fovy);
#endif
valType tanHalfFovy = tan(rad / valType(2));
detail::tmat4x4<valType> Result(valType(0));
Result[0][0] = valType(1) / (aspect * tanHalfFovy);
Result[1][1] = valType(1) / (tanHalfFovy);
Result[2][2] = - (zFar + zNear) / (zFar - zNear);
Result[2][3] = - valType(1);
Result[3][2] = - (valType(2) * zFar * zNear) / (zFar - zNear);
return Result;
注意以下行:
Result[2][2] = - (zFar + zNear) / (zFar - zNear);
将其与您的等效项进行比较:
a_33 = (z_near + z_far)/(z_near - z_far)
注意整个语句前面有一个负号(-
)。你的版本没有这个。
我已经解决问题了,发布信息以防以后有人遇到类似问题。
在构建模型、视图和投影矩阵时,我引入了行主矩阵和列主矩阵的混合。引入这些是因为 numpy 和 OpenGL 需要不同格式的矩阵。当单独操作时,这些矩阵之所以有效,是因为它们可以很容易地用 numpy 进行转置以产生正确的结果。
合并矩阵时出现问题。结果是变换以不一致且无意义的顺序应用,并且所有点都被绘制在屏幕之外。这隐藏了透视矩阵中的错误和复杂的调试。
解决方案是确保所有矩阵在存储数据的方式上保持一致(所有行主要或所有列主要)并且在发送到 OpenGL 之前进行一次转置。