Миграция с фиксированной функции на GLSL OpenGL: как мне изменить матрицу вида (lookAt) и матрицу перспектив? - PullRequest
0 голосов
/ 29 мая 2018

Я пытаюсь перенести мой конвейер рендеринга OpenGL с фиксированной точки на современный OpenGL.Мой 3D-конвейер с фиксированной точкой хорошо работает годами.Теперь, когда я переключаюсь на GLSL, окончательная проекция и ориентация объекта выглядят как «полностью отраженные или поменялись местами».Я исключил все другие причины (например, не удалось установить матричную униформу и т. Д.), Так как я могу видеть, что 3D-сцена время от времени визуализируется путем случайного перетаскивания моей мыши для панорамирования камеры.Поэтому вопрос сводится к следующему:

  • Функция, которая генерирует матрицу вида (моя функция getViewMat (pos, lookat, upaxis)) *
  • Функция, которая генерирует матрицу проекции перспективы(моя функция getPerspectiveMat (fov, aspect, nearZ, farZ))

Поскольку эти две функции раньше генерировали правильную матрицу вида / проекции для конвейера с фиксированной точкой, теперь мне интересно, могу ли я / как это сделатьизменить их так, чтобы сгенерированные матрицы работали для конвейера шейдеров?

Существует несколько потоков переполнения стека предполагает, что для конвейера шейдеров нам нужно вручную перевернуть значение Z для матрицы проекции, но как насчетматрица вида?Большое спасибо за любые предложения.

Обновление: Код Soure

/*
    Matrix4f has class members "float m00, m01, m02, m03, m10, m11, ..., m33" representing
    a row-dominant 4x4 matrix, when passed to GLSL, I have remembered to transpose them
*/
void Matrix4f::_getPerspectiveByFov(float fov, float aspectRatio, float nearZ, float farZ, int matrixType)
{
    float halfFov   = MathUtil::degToRad(fov) * 0.5f;
    float width, height;
    //We use the small side out of width and height as the base size, then calculate the other side by aspect ratio.
    float _tanFOV = (float)tan(halfFov);
    if(aspectRatio < 1.f)//width is smaller
    {
        width   = 2.f * nearZ * _tanFOV;
        height  = width / aspectRatio;
    }
    else    //height is smaller
    {
        height  = 2.f * nearZ * _tanFOV;
        width   = height * aspectRatio;
    }

    /*
    Formula from OpenGL reference, see function "glFrustum".
        |w      0       0       0|
        |0      h       0       0|
        |0      0       -C      D|
        |0      0       1       0|

    w = 2.f * nearZ / width
    h = 2.f * nearZ / height
    C = -(farZ + nearZ) / (farZ - nearZ)
    D = -2.f * farZ * nearZ / (farZ - nearZ);
    */
    float w = 2.f * nearZ / width;  // Is equal to: [ 1.f / tan(fov*0.5f) ]
    float h = 2.f * nearZ / height; // Is equal to: [ 1.f / tan(fov*0.5f) / aspectRatio ]
    float C = -(farZ + nearZ) / (farZ - nearZ);
    float D = -2.f * farZ * nearZ / (farZ - nearZ);

    //-----------------------
    m00 = w;
    m01 = 0.f;
    m02 = 0.f;
    m03 = 0.f;

    m10 = 0.f;
    m11 = h;
    m12 = 0.f;
    m13 = 0.f;

    m20 = 0.f;
    m21 = 0.f;
    m22 = -C;
    m23 = D;

    m30 = 0.f;
    m31 = 0.f;
    m32 = 1.f;
    m33 = 0.f;
}

void Matrix4f::_getLookAt(Vector3f& pos, Vector3f& lookat, Vector3f& upAxis)
{
    //Note _forward, _right, _up are working vector of type Vector3f

    _up.set(upAxis);
    _forward.sub(lookat, pos);
    _forward.normalize();
    _right.cross(_up, _forward);
    _right.normalize();
    _up.cross(_forward, _right);
    _up.normalize();

    m00 = _right.x;
    m10 = _right.y;
    m20 = _right.z;

    m01 = _up.x;
    m11 = _up.y;
    m21 = _up.z;

    m02 = _forward.x;
    m12 = _forward.y;
    m22 = _forward.z;

    // Locate the camera
    m03 = pos.x;
    m13 = pos.y;
    m23 = pos.z;

    m30 = 0.f;
    m31 = 0.f;
    m32 = 0.f;

    m33 = 1.f;
}

1 Ответ

0 голосов
/ 30 мая 2018

не видя, что вы делаете в Вершинный шейдер мы можем только догадываться.Однако Вы можете использовать те же матрицы в новом OpenGL, что и в старом.Единственная матрица, которой у вас, вероятно, нет, - gluPerspective, так что вы можете реализовать ее самостоятельно (если у вас больше нет glu.h).Я делаю это так:

void glPerspective(double fovy,double aspect,double zNear,double zFar)
    {
    double per[16],f;
    for (int i=0;i<16;i++) per[i]=0.0;
    // original gluProjection
//  f=divide(1.0,tan(0.5*fovy*deg))
//  per[ 0]=f/aspect;
//  per[ 5]=f;
    // corrected gluProjection
    f=divide(1.0,tan(0.5*fovy*deg*aspect));
    per[ 0]=f;
    per[ 5]=f*aspect;
    // z range
    per[10]=divide(zFar+zNear,zNear-zFar);
    per[11]=-1.0;
    per[14]=divide(2.0*zFar*zNear,zNear-zFar);
    glLoadMatrixd(per);
//  zNear=divide(-per[11],per[10]);     // get znear from perspective projection matrix
    }

Это более или менее имитирует gluPerspective, но оно исправило неточный tan, что вызывало проблемы при объединении нескольких фрустримов вместе.В закомментированных строках показано, как вычислить исходный gluPerspective (также с tan восстановленным), а в последнем комментарии показано, как получить znear из матрицы (для трассировщиков лучей)

Грубого вместо glLoadMatrixd(per); васиспользуйте per, как вам нужно ... (например, отправьте как uniform)

Теперь, чтобы реализовать lookat, вы просто создаете матрицу самостоятельно.См .:

Таким образом, вы просто вычисляете векторы X,Y,Z и O исходную позицию

Z = -forward
X = +right
Y = +up
O = +camera_position - znear

и подайте их в вашу матрицу в нужных местах ...

Теперь, если ваша lookat - это позиция целевого объекта, чем

Z = normalize(camera_position-lookat)
Y = up
X = cross(Y,Z)

Не уверен, если Xдолжно быть + или - просто попробуйте, и если сцена зеркальная, отмените ее.

...