我正在为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实现似乎在不这样做的情况下就可以正常工作,但是也许就是这样吗?我对数学不太了解,无法知道是否应该这样做以确保正确性。
关于我做错或误解的任何想法,有人吗?或者,如果我确实发现了某种奇怪的怪癖?如果建议最好的方法是仅使用它,而不是尝试根据我目前所获得的值进行调整,那么对使用负零的影响(如果有的话)的解释也将是很好的。
最佳答案
不要尝试“修复”它-您的代码可以正常工作。我认为“奇怪的怪癖”很好地涵盖了它。
将零加到除零以外的任何值上(这是矩阵乘法的结果),得到的结果完全相同;这甚至不算是重大差异。
而且,实际上,在比较计算相同标称结果的两个不同浮点过程时,您应该期望遇到差异。浮点数并不精确,因此您做任何不同的操作(例如,更改加法顺序)都可能会产生稍微不同的结果。因此,每当比较浮点结果时,都需要指定一个公差。