【问题标题】:OpenGL Perspective Matrix in PythonPython中的OpenGL透视矩阵
【发布时间】:2023-04-02 17:22:01
【问题描述】:

我正在尝试在 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.        ]

【问题讨论】:

  • 600/480 总是会返回一个1。让它600.0/480.0。不过,这不应该是空白屏幕的原因。
  • 600/480 = 1.25,当我在 python 中运行它时。
  • 您检查过perspective 函数的结果吗?它会返回您所期望的吗?你从哪里得到函数的代码?
  • 我猜我们正在使用不同版本的python(我使用的是3.4)stackoverflow.com/questions/21316968/…。所有这些都是无关紧要的,因为它不会导致问题。

标签: python opengl matrix perspectivecamera


【解决方案1】:

既然你说你是从 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)

请注意,整个语句前面有一个负号 (-)。你的版本没有这个。

【讨论】:

  • 我注意到两个矩阵之间的差异并检查了这个,但这不是问题。同样在更改符号以匹配我的剪辑空间坐标后,从 (-1,+1) 移动到 (+3,+1)。我认为问题出在其他地方。
  • 好的,这就是问题所在,由于某种原因,当我早些时候检查时,没有明显的影响。我猜还有什么问题,我在摆弄我的代码时改变了它(我仍然不知道它是什么或它是如何修复它的)。手指交叉我不会再打破它(现在是这样的时候,我很感谢我有 git)。
  • 这不可能是原因,因为它们完全相同。减号应用于分母。
【解决方案2】:

我已经解决了问题,发布信息以防将来有人遇到类似问题。

在构建模型、视图和投影矩阵时,我引入了行主矩阵和列主矩阵的混合。引入这些是因为 numpy 和 OpenGL 需要不同格式的矩阵。单独操作时,这些矩阵很有效,因为它们可以很容易地用 numpy 转置以产生正确的结果。

合并矩阵时出现问题。结果是以不一致且毫无意义的顺序应用转换,并且所有点都被画出屏幕。这隐藏了透视矩阵中的错误和复杂的调试。

解决方案是确保所有矩阵在存储数据的方式上保持一致(所有主要行或所有主要列),并且在发送到 OpenGL 之前发生一次转置。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多