Повторяйте последовательность операций с матрицами GL вручную - PullRequest
1 голос
/ 06 февраля 2012

Я портирую игрушечную кодовую базу GL ES 1.1 на GL ES 2.0.Встроенных матричных операций просмотра модели нет, поэтому я пытаюсь заменить замену вызовов glScalef, glTranslatef, glRotatef на операции с «текущей матрицей» 4x4.

Однакомоя математическая математика немного отрывочна, и что-то происходит с порядком умножения и строкой по сравнению с основной нотацией столбца и т. д., и мне бы понравилось, если бы кто-то мог быстро обрисовать семантику, которую я должен добавить сюда.

Например, предполагая, что я начинаю с матрицы тождеств, а затем (в коде ES 1.1) выполняю в следующем порядке:

glTranslate(A);
glRotate(B);
glTranslate(C);

... какую математику мне нужно делать с моей "текущей матрицей""чтобы воспроизвести эту функциональность в итоговой матрице представления модели, которую я отправляю в шейдер?Я попытался сохранить матрицу и для каждой операции создать новую матрицу, которая представляет ее, и умножить ее на текущую.Результат, однако, неверен, и я думаю, что есть кое-что, чего я не понимаю до / после умножения, -много и т. Д.

Кто-нибудь хочет сказать несколько слов о теории здесь?Благодарю.(Я хотел бы понять основы, прежде чем сделать его суперэффективным.)

(Это: Реализация фиксированной функции Эффективность конвейера в OpenGL ES 2.0? задает аналогичный вопрос, ноответ говорит о том, как сделать его более эффективным, и на самом деле не учит меня математической эквивалентности.)

Ответы [ 2 ]

2 голосов
/ 06 февраля 2012

По сути, вы ищете замену стека матрицы opengl для ваших преобразований.

Предполагая, что вы используете c / c ++, я предлагаю взглянуть на библиотеку GLM: http://glm.g -truc.net /

Это библиотека только для заголовков, простая в использовании и идеальная замена для стека матрицы pre-opengl es 2.0.Он даже предоставляет функциональность для устаревших функций glu, таких как gluOrtho () и gluPerspective ().Матрицы Glm могут быть легко переданы в ваш шейдер, так как они задуманы с учетом шейдеров.

Вам придется внести несколько изменений в свой код;например, преобразование ваших собственных определений вершин / матриц в glm :: vec3 / glm :: mat4.

Вот пример того, как я создаю свою матрицу mvp, которую я передаю вершинному шейдеру: в этом случае класс actorInstanceимеет несколько атрибутов, таких как положение (в мире) и вращение, определенные как glm :: vec3's.Матрицы построенной модели, модели / вида и модели / вида / проекции являются собственностью класса:

void CActorInstance::update(glm::mat4 viewMatrix, glm::mat4 projectionMatrix)
{

    // act according to class behavior
    this->actorClass->act(&input, &world, &direction, &rotation);

    // calculate the translation matrix
    glm::mat4 translate = glm::mat4();
    translate = glm::translate( glm::mat4(), world);

    // calculate the rotation matrix   
    glm::mat4 rotateX = glm::rotate( glm::mat4(1.0f), rotation.x, glm::vec3(1,0,0));
    glm::mat4 rotateY = glm::rotate( glm::mat4(1.0f), rotation.y, glm::vec3(0,1,0));
    glm::mat4 rotateZ = glm::rotate( glm::mat4(1.0f), rotation.z, glm::vec3(0,0,1));
    glm::mat4 rotate = rotateX * rotateY * rotateZ;

    // calculate the model matrix
    mMatrix = translate * rotate;

    // calculate the model/view matrix
    mvMatrix = viewMatrix * mMatrix;

    // calculate the model/view/projection matrix
    mvpMatrix = projectionMatrix * mvMatrix;
};

Очевидно, что матрица mvp для каждого объекта обновляется в каждом кадре в соответствии с положением и поворотом объекта.ViewMatrix и projectionMatrix передаются из класса моей камеры.Затем эта матрица используется для визуализации меша:

    void CMesh::renderMesh(GLuint program, glm::mat4 *mvp)
    {
        glUseProgram(program);

        int mvpLocation = glGetUniformLocation(program, "mvpMatrix");
        int texLocation = glGetUniformLocation(program, "baseMap");
        glUniformMatrix4fv( mvpLocation, 1, GL_FALSE, glm::value_ptr(*mvp));

// rendering code ommitted


    };

Надеюсь, это поможет:)

EDIT : предложения по реализации стека матриц

stl::stack<glm::mat4> matrixStack; // the matrix stack
matrixStack.push_back(glm::mat4()); // push an identity matrix on the stack

И это ваша glLoadIdentity () ...

1 голос
/ 06 февраля 2012

Я пытался сохранить матрицу, и для каждой операции делал новый матрицу, которая представляет это, и умножая это на текущую.

Ну, это именно так, как это делается. Ничего особенного.

Соответствующие матрицы для звонков на glRotate, glTranslate и glScale (а также glOrtho , glFrustum, gluLookAt и gluPerspective, конечно) довольно легко построить, как видно из ссылок.

Вы просто должны умножить вправо соответствующую матрицу преобразования T на текущей матрице M:

M' = M * T

потому что мы (или старый OpenGL, который вы хотите тиражировать) хотим, чтобы последнее преобразование, вызванное перед рисованием, было применено к объекту в первую очередь.

Тогда вы также должны быть согласны с хранилищем вашей матрицы (основной ряд или основной столбец), независимо от того, для чего вы рассчитываете. Но так как вы используете OpenGL, было бы неплохо использовать хранилище на главной колонке, поскольку оно позволяет вам легче загружать их в GLSL (хотя и без использования флага транспонирования), лучше работает с векторизованными SIMD-инструкциями (как SSE в x86) и более того, лучше работает с другими библиотеками, разработанными для OpenGL (которые используют матрицы столбцов по тем же причинам). Вы должны быть согласованы только с хранилищем и не путать его с различными вызовами функций.

...