Реализация gluLookAt и gluPerspective - PullRequest
1 голос
/ 14 ноября 2011

Я написал небольшой 2D движок в opengl в процессе создания игры.Я использую OpenGL ES 2, и код компилируется и работает на iOS и Mac OSX.

Теперь я расширяю его для поддержки 3D и у меня возникают проблемы с настройкой камеры.
IЯ проверил код сто раз, и я не могу найти, в чем проблема, поэтому, возможно, кто-то, имеющий опыт в этом, может дать идею.

Это код, который я имею: я публикую частькода, где я думаю, что проблема может быть, но если нужно что-то еще, просто спросите меня.

Matrix4 _getFrustumMatrix(float left, float right, float bottom, float top, float near, float far){
    Matrix4 res = Matrix4(2.0 * near / (right - left), 0, 0, 0,
                           0, 2.0 * near / (top - bottom), 0, 0,
                           (right + left) / (right - left), (top + bottom) / (top - bottom), -(far + near) / (far - near), -1.0,
                           0,0, -2.0 * far * near / (far - near), 0);

    return res;
}

Matrix4 _getPerspectiveMatrix(float near, float far, float angleOfView){
    static float aspectRatio = float(SCREENW)/float(SCREENH);
    float top = near * tan(angleOfView * 3.1415927 / 360.0);
    float bottom = -top;
    float left = bottom * aspectRatio;
    float right = top * aspectRatio;

    return _getFrustumMatrix(left, right, bottom, top, near, far);    
}

Matrix4 _getLookAtMatrix(Vector3 eye, Vector3 at, Vector3 up){
    Vector3 forward, side;
    forward = at - eye;
    forward.normalize();
    side = forward ^ up;
    side.normalize();
    up = side ^ forward;

    Matrix4 res = Matrix4(side.x, up.x, -forward.x, 0,
                          side.y, up.y, -forward.y, 0,
                          side.z, up.z, -forward.z, 0,
                          0, 0, 0, 1);
    res.translate(Vector3(0 - eye));
    return res;
}

void Scene3D::_deepRender(){    
    cameraEye = Vector3(10,0,40);
    cameraAt = Vector3(0,0,0);
    cameraUp = Vector3(0,1,0);

    MatrixStack::push();

    Matrix4 projection = _getPerspectiveMatrix(1, 100, 45);    
    Matrix4 view = _getLookAtMatrix(cameraEye, cameraAt, cameraUp);    

    MatrixStack::set(projection * view);

    Space3D::_deepRender();

    MatrixStack::pop();    
}

Нарисованный объект - это представление осей, где x = красный, y = зеленый, z =синий, и он расположен в (0,0,0).

Если я поставлю глаз на (0,0,40), все будет выглядеть как положено: eye at (0,0,40)

Если я положуглаз в (10,0,40), то объект не рисуется в середине экрана, как это должно быть.eye at (10,0,40)

Это метод Matrix4 :: translate:

void Matrix4::translate(const Vector3& v) {
    a14 += a11 * v.x + a12 * v.y + a13 * v.z;
    a24 += a21 * v.x + a22 * v.y + a23 * v.z;
    a34 += a31 * v.x + a32 * v.y + a33 * v.z;
    a44 += a41 * v.x + a42 * v.y + a43 * v.z;
}

РЕДАКТИРОВАТЬ: Чтобы добавить некоторую информацию:

Использование _getLookAtMatrix ()с этими параметрами:

cameraEye = Vector3(40,40,40);
cameraAt = Vector3(0,0,0);
cameraUp = Vector3(0,1,0);

Должна ли я дать мне эквивалентную матрицу для этого?

Matrix4 view;
view.setIdentity();
view.translate(Vector3(0,0,-69.2820323)); // 69.2820323 is the length of Vector3(40,40,40)
view.rotate(45, Vector3(1,0,0));
view.rotate(-45, Vector3(0,1,0));

По крайней мере, эти преобразования имеют смысл для меня, и полученное изображение выглядит так, как я должен ожидать,Но эта матрица по сравнению с той, которую я получаю с помощью _getLookAtMatrix (), сильно отличается:

view:

0.707106769,    -0.49999997,    0.49999997,     0,
0,              0.707106769,    0.707106769,    0, 
-0.707106769,   -0.49999997,    0.49999997,     0, 
0,              0,              -69.2820358,    1

_getLookAtMatrix (cameraEye, cameraAt, cameraUp):

0.707106769,    0,              -0.707106769,   0, 
-0.408248276,   0.816496551,    -0.408248276,   0, 
0.577350259,    0.577350259,    0.577350259,    0, 
-35.0483475,    -55.7538719,    21.520195,      1

1 Ответ

2 голосов
/ 21 ноября 2011

У вас, кажется, есть серьезные несоответствия в порядке в вашем классе матрицы.

Например, я предположил, что ваш конструктор Matrix4 принимает аргументы (элементы матрицы) в качестве основного столбца, иначе ваши функции не будут соответствовать ссылочным реализациям glFrustum и gluLookAt и вы получите полностью испорченные результаты.

И код вашей функции translate также выглядит правильно, так как он должен изменить последний столбец матрицы, которые являются элементами (a14, a24, a34 и a44).

Но ваша распечатка из матрицы view предполагает, что translate фактически изменяет последнюю строку, если только вы не распечатаете матрицу в основном столбце и, следовательно, не транспонированы. Но в этом случае печать _ getLookAtMatrix предполагает, что конструктор Matrix4 принимает свои аргументы в порядке основной строки, что действительно делает недействительными другие элементы.

Конечно, все это также зависит от того, как вы отправляете матрицы в OpenGL и как вы используете их в вершинном шейдере (я полагаю, ES 2.0, иначе вам не понадобится ваша собственная матричная библиотека). Если вы действительно используете ES 1, то вам нужно отправлять матричные элементы в OpenGL в основном порядке столбцов, но перевод должен быть в последнем столбце, а не в последней строке.

Но независимо от того, какое соглашение вы используете, внутри вашего матричного кода определенно есть серьезное несоответствие. Но не видя всего класса Matrix4, вершинного шейдера и кода, в который вы загружаете матрицы в OpenGL, трудно сказать, где это несоответствие.

...