我的 glOrtho 怎么了?负零而不是零
Posted
技术标签:
【中文标题】我的 glOrtho 怎么了?负零而不是零【英文标题】:What's wrong with my glOrtho? Negative zero instead of zero 【发布时间】:2012-03-29 05:25:16 【问题描述】:我正在为一个 OpenGL 应用程序实现我自己的矩阵数学。到目前为止,事情基本上都很好,虽然很困难。我最近的一个问题,一个我没有得到解释或指出给我的具体问题的运气,与我的 glOrtho() 实现有关。
具体来说,我的版本导致 matrix[14] 元素为负零。 (-0.000000),而我在使用已弃用的 glOrtho() 后从 OpenGL 获得的 glGet() 版本是正常的零。 (0.000000)
我不知道这是否会影响任何事情,但我对我的数学不匹配感到不安。
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 实现似乎可以正常工作,但也许就是这样?我不太了解数学,不知道是否应该这样做以确保正确性。
任何想法,任何人,关于我做错了什么或误解?或者如果我确实发现了某种奇怪的怪癖?如果建议最好的方法是顺其自然,而不是尝试根据我目前得到的值调整值,那么使用负零可能会产生什么效果(如果有的话)的解释也会很好?
【问题讨论】:
【参考方案1】:CPU 和 GPU 内部的浮点精度不一定相同,因此会出现微小的差异。
【讨论】:
【参考方案2】:不要试图“修复”它——您的代码工作正常。我认为“奇怪的怪癖”很好地涵盖了它。
将零添加到零以外的任何值(这是矩阵乘法所做的)会产生完全相同的结果;这甚至不能算作重大差异。
而且,实际上,您应该预计在比较两个计算相同名义结果的不同浮点过程时会遇到差异。浮点数不是精确的,所以你做任何不同的事情(例如改变加法的顺序)可能会产生稍微不同的结果。因此,无论何时比较浮点结果,都需要指定容差。
【讨论】:
感谢您很好地解释了您的答案。帮助我更多地了解发生了什么以及为什么。【参考方案3】:负零和正零在数学上是相同的浮点值。它们不相等,但根据 IEEE-754,你会得到相同的结果。
您根本不应该尝试用不同的浮点计算来匹配相等性。如果您需要检查您的矩阵数学,那么至少要针对一个范围(加上或减去一些小数字)对其进行测试。
【讨论】:
实际上,我认为标准上说 +0 和 -0 是 相等的(就比较而言,无论如何)。以上是关于我的 glOrtho 怎么了?负零而不是零的主要内容,如果未能解决你的问题,请参考以下文章