Почему этот расчет матрицы перспективной проекции не дает правильного результата?

Я не могу понять это. У меня есть приложение OpenGL, которое я конвертирую из старого фиксированного конвейера функций в программируемый конвейер и избавляюсь от устаревших функций, которые я использовал... Я не лучший, когда дело доходит до математики, и матрицы для меня в новинку.

Тем не менее, моя матрица ModelView работает нормально, но я не могу заставить правильно работать матрицу Perspective.

Я имею в виду, что я могу использовать устаревшие функции с фиксированной функцией, получить значение матрицы и сопоставить его с вычисленными значениями, которые я сгенерировал... ModelView? Без проблем. Перспектива? Это не совпадает, и я не понимаю, почему.

Между этими двумя методами можно переключаться, комментируя препроцессор #define USEPROJMATRIX.


typedef float vec_t;

const static vec_t identityMatrix[16] = { 1.0, 0.0, 0.0, 0.0, 
                                          0.0, 1.0, 0.0, 0.0, 
                                          0.0, 0.0, 1.0, 0.0, 
                                          0.0, 0.0, 0.0, 1.0 };

const static vec_t zeroMatrix[16] = { 0.0, 0.0, 0.0, 0.0,
                                      0.0, 0.0, 0.0, 0.0,
                                      0.0, 0.0, 0.0, 0.0,
                                      0.0, 0.0, 0.0, 0.0 };

const double pi = 3.1415926535897932384626433832795;

float Utils::Radians(const float& degrees)
{
    return degrees * (pi / 180);
}

vec_t* Utils::FrustumMatrix(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) // Replaced glFrustum()
{
    memcpy(out_matrix, zeroMatrix, 16*sizeof(vec_t));

    out_matrix[0] = (2.0 * znear) / (right - left);
    out_matrix[5] = (2.0 * znear) / (top - bottom);
    out_matrix[8] = (right + left) / (right - left);
    out_matrix[9] = (top + bottom) / (top - bottom);
    out_matrix[10] = -((zfar + znear) / (zfar - znear));
    out_matrix[11] = -1.0;
    out_matrix[14] = -((2.0 * zfar * znear) / (zfar - znear));

    return out_matrix;
}

vec_t* Utils::PerspectiveMatrix(vec_t* out_matrix, const vec_t& yFOVDegrees, const vec_t& aspectRatio, const vec_t& znear, const vec_t& zfar) // Replaces gluPerspective()
{
    vec_t range, left, right, bottom, top;

    range = tan(Radians(yFOVDegrees / 2)) * znear;
    left = -range * aspectRatio;
    right = range * aspectRatio;
    bottom = -range;
    top = range;

    return FrustumMatrix(out_matrix, left, right, bottom, top, znear, zfar);
}

#define USEPROJMATRIX
void GameLogic::OnResize(int width = 640, int height = 480)
{
    glViewport(0, 0, width, height);
    glMatrixMode(GL_PROJECTION);
#ifndef USEPROJMATRIX
    glLoadMatrixf(identityMatrix);
    gluPerspective(45.0f, (GLfloat)width / (GLfloat)height, 1.0f, 1000.0f);
#else
    vec_t pMatrix[16];
    memcpy(pMatrix, identityMatrix, sizeof(vec_t) * 16);
    Utils::PerspectiveMatrix(pMatrix, 45.0f, (GLfloat)width / (GLfloat)height, 1.0f, 1000.0f);
    glLoadMatrixf(pMatrix);
#endif

    vec_t projectionmatrix[16];
    glGetFloatv(GL_PROJECTION_MATRIX, projectionmatrix);

    /* Matrix calculation results in projectionmatrix equalling this:
       1.8106601, 0.00000000, 0.00000000, 0.00000000, 
       0.00000000, 2.4142134, 0.00000000, 0.00000000, 
       0.00000000, 0.00000000, -1.0020020, -1.0000000,
       0.00000000, 0.00000000, -2.0020020, 0.0000000
    */
    /* GL calculation
       1.8106601, 0.00000000, 0.00000000, 0.00000000,
       0.00000000, 2.4142137, 0.00000000, 0.00000000,
       0.00000000, 0.00000000, -1.0020020, -1.0000000,
       0.00000000, 0.00000000, -2.0020020, 0.00000000
    */

    glMatrixMode(GL_MODELVIEW);
    glLoadMatrixf(identityMatrix);
}

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

изменить Исправлена ​​глупая ошибка согласно ответу Никола Боласа. Однако это все еще не работает должным образом. Значения в комментарии также были обновлены. edit2 Приведенный выше код теперь работает нормально, вопрос решен. Глупые ошибки с моей стороны.


person Azuvector    schedule 01.01.2012    source источник


Ответы (1)


Это то, что вы используете в своем вызове gluPerspective:

(GLfloat)width / (GLfloat)height

Это то, что вы используете в своем вызове Utils::PerspectiveMatrix:

width / height

Первый производит значение с плавающей запятой. Второй выдает целое число. Я предполагаю, что вы хотели первого.

person Nicol Bolas    schedule 01.01.2012
comment
Это действительно была глупая ошибка с моей стороны. Однако проблема остается. Цифры до сих пор не совпадают. Я полагаю, что небольшое несоответствие элемента проекцииmatrix[5] является просто ошибкой округления или используемыми значащими цифрами числа пи, но проекцияmatrix[15] совершенно неверна. - person Azuvector; 01.01.2012
comment
Аннн, бля. Нашел проблему. Неправильно инициализировал мою матрицу. Вопрос исправлен, чтобы исправить код, спасибо, что указали на очевидное, что я был слишком слеп, чтобы видеть. :) - person Azuvector; 01.01.2012