我的 glOrtho 有什么问题?负零而不是零

What's wrong with my glOrtho? Negative zero instead of zero

本文关键字:glOrtho 什么 问题 我的      更新时间:2023-10-16

我正在为OpenGL应用程序实现我自己的矩阵数学。到目前为止,情况基本上是好的,尽管很困难。我最近的一个问题是关于glOrtho()的实现,我很难得到解释或具体的问题。

具体来说,我的版本导致矩阵[14]元素为负零。(-0.000000),而在使用不推荐使用的glOrtho()之后,我从OpenGL获得的glGet()版本是正常的零。(0.00000)

我不知道这是否会影响事情,但我对我的数学不匹配感到不安。

glOrtho的OpenGL规范,作为参考,我相信我正确地遵循了它,并正确地计算了:http://www.opengl.org/sdk/docs/man/xhtml/glOrtho.xml

我自己的glOrtho函数:

vec_t* Utils::OrthoMatrix(vec_t* out_matrix, const vec_t& left, const vec_t& right, const vec_t& bottom, const vec_t& top, const vec_t& znear, const vec_t& zfar)
{
    memcpy(out_matrix, zeroMatrix, 16*sizeof(vec_t));
    out_matrix[0] = 2.0f / (right - left);
    out_matrix[5] = 2.0f / (top - bottom);
    out_matrix[10] = -2.0f / (zfar - znear);
    out_matrix[12] = -((right + left) / (right - left));
    out_matrix[13] = -((top + bottom) / (top - bottom));
    out_matrix[14] = -((zfar + znear) / (zfar - znear));
    out_matrix[15] = 1.0f;
    return out_matrix;
}

我的调整大小功能(为了可读性,大幅精简):

void GameLogic::OnResize(int width, int height) // For purposes of this test, width = 640, height = 480.
{
    if(height == 0) // Avoid potential divide-by-zero
        height = 1;
    glViewport(0, 0, width, height);
    Utils::OrthoMatrix(m_orthoMatrix, 0.0f, (GLfloat)width, (GLfloat)height, 0.0f, -100.0f, 100.0f);
    // Setup fixed function OpenGL to compare against.
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(0.0f, (GLfloat)width, (GLfloat)height, 0.0f, -100.0f, 100.0f);
    glMatrixMode(GL_MODELVIEW);
    glLoadIdentity();
}
void GameLogic::Render() // Drastically cut down to illustrate issue.
{
    vec_t modelviewmatrix[16], projectionmatrix[16];
    glGetFloatv(GL_MODELVIEW_MATRIX, modelviewmatrix);
    glGetFloatv(GL_PROJECTION_MATRIX, projectionmatrix);
/*
    At this point, projectionmatrix and m_orthoMatrix are identical, 
    except in the matrix[14] element, which is 0.000000 for projectionmatrix, 
    and -0.000000 for m_orthoMatrix.
*/
}

我不太明白为什么会这样,或者它会产生什么影响?据我所见,数学结果是正确的,所以它应该是负零,但OpenGL正在返回正零。到目前为止,我的最佳猜测是某种司机怪癖,司机为了避免负零而伪造数字?我在两个独立的nVidia GPU上测试了这段代码,得到了相同的结果。无法访问ATI或类似产品进行测试。

免责声明:我对glOrtho的近值和远值是如何工作的有些不了解,尽管规范确实规定了允许负值。

我应该用单位矩阵初始化投影矩阵,还是将单位矩阵乘以透视矩阵?我不。。。我认为我需要这样做,而我的glFrustum实现似乎在没有这样做的情况下运行良好,但也许就是这样?我对数学理解不够好,不知道是否应该这样做以确保正确性。

有人认为我做错了什么或误解了什么吗?或者,如果我真的发现了某种奇怪的怪癖?如果有人建议最好的方法是使用负零,而不是试图根据我目前得到的值来调整值,那么解释使用负零可能会产生什么效果也会很好?

CPU和GPU内部的浮点精度不一定相同,因此可能会出现微小差异。

不要试图"修复"它——您的代码工作正常。我觉得"怪癖"很好地掩盖了这一点。

将零与除零之外的任何东西相加(这就是矩阵乘法的作用)会产生完全相同的结果;这甚至不算是一个显著的差异。

而且,实际上,当比较计算相同标称结果的两个不同浮点过程时,您应该预计会遇到差异。浮点是不精确的,所以任何不同的操作(例如,更改加法顺序)都可能产生稍微不同的结果。因此,无论何时比较浮点结果,都需要指定公差。

负零和正零在数学上是相同的浮点值。它们不等于,但根据IEEE-754,你们会得到同样的结果。

您根本不应该试图将等式与不同的浮点计算进行匹配。如果你需要检查你的矩阵数学,那么至少要根据一个范围(加上或减去一些小数字)来测试它。