2012-03-29 3 views
0

Я реализую свою собственную матричную математику для приложения OpenGL. Пока что все хорошо, хотя и сложно. Моя последняя проблема, одна из которых мне не удалась получить объяснение или конкретную проблему, указанную мне, связана с моей реализацией glOrtho().Что случилось с моим glOrtho? Отрицательный ноль вместо нуля

В частности, моя версия приводит к тому, что элемент матрицы [14] отрицателен. (-0.000000), а версия, которую я glGet() из OpenGL после использования устаревшего glOrtho(), является нормальным нулем. (0.000000)

Я не знаю, влияет ли это на какие-либо вещи, но меня беспокоит моя математика, не соответствующая.

спецификация OpenGL glOrtho, за ссылки, которые я считаю, что я слежу правильно, и делать математику правильно для: 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 и получил тот же результат. У вас нет доступа к чему-либо ATI или аналогичному тесту.

Отказ от ответственности: Я несколько не знаю, как работают близкие и дальние значения glOrtho, хотя в спецификации указано, что допустимы отрицательные значения.

Должен ли я инициализировать матрицу проекции единичной матрицей или умножить единицу матрицы на перспективную матрицу? Я не ... думаю, мне нужно это сделать, и моя реализация glFrustum, похоже, работает нормально, но это возможно? Я недостаточно разбираюсь в математике, чтобы знать, нужно ли это делать для правильности или нет.

Любые идеи, кто-либо, о том, что я делаю неправильно или недоразумения? Или, если я действительно нашел какую-то странную причуду? Объяснение того, что, если что-либо, используя отрицательный ноль, могло бы повлиять, было бы хорошо, если бы было сказано, что лучший курс - просто пойти с ним, а не попытаться настроить значения из того, что я сейчас получаю?

ответ

1

Не пытайтесь «исправить» - ваш код работает правильно. Думаю, что «странная причуда» красиво его покрывает.

Добавление нуля к чему-либо другому, кроме нуля (что делает матричное умножение), дает точно такой же результат; это даже не считается значительным расхождением.

И, фактически говоря, вы должны ожидать, чтобы встретить несоответствия при сравнении двух разных процедур с плавающей точкой, которые вычисляют один и тот же номинальный результат. Плавающая точка не является точной, поэтому все, что вы делаете по-другому (изменение порядка добавления, например), скорее всего, даст немного другой результат. Следовательно, всякий раз, когда вы сравниваете результаты с плавающей запятой, вам нужно указать допуск.

+0

Спасибо, что так хорошо объяснили свой ответ. Помогло мне больше понять, что происходит и почему. – Azuvector

3

Точность с плавающей запятой внутри CPU и GPU не обязательно одинакова, поэтому следует ожидать крошечных расхождений.

0

Отрицательный нуль и положительный ноль являются математически идентичными значениями с плавающей запятой. Они не равны, но вы получите то же самое в соответствии с IEEE-754.

Вы не должны пытаться совместить равенство с различными вычислениями с плавающей запятой. Если вам нужно проверить математическую матрицу, то, по крайней мере, проверьте ее на диапазон (плюс или минус небольшое количество).

+0

На самом деле, я думаю, что стандарт говорит, что +0 и -0 * равны (насколько это касается сравнения, во всяком случае). – comingstorm

Смежные вопросы