Опорный порядок матричных преобразований
Скажем, у меня есть синий 3D-бокс (где верхняя сторона красного цвета).
- Теперь я вызываю glScalef (1, 10, 1).
- Затем я вызываю glRotatef (90, 0, 1, 0).
- Затем я выношу куб.
Я ожидал увидеть красную сторону, обращенную и вытянутую к экрану (вдоль оси Y модели).
Но что я вижу:
Красная сторона обращена к экрану (как и ожидалось).
Но растяжение происходит на оси Y пространства вида (а не на модели).
Я знаю, что если я задаю масштаб вдоль оси Z, тогда я получу правильный результат.
Но моя путаница в том, что я думал, что масштабирование по оси Y, а затем поворот коробки, даст мне правильный результат.
Что мне не хватает?
Ответы
Ответ 1
OpenGL считывает свои матрицы в так называемом column major
порядке. В результате каждая последующая операция представляет собой предварительное умножение всех операций перед ним, а не пост-умножение. Таким образом, каждый последующий вызов операции OpenGL (glScale, glTranslate, glRotate) - это первая вещь, которая влияет на объект, и она идет в обратном порядке от того, как вы ее пишете.
Итак, вам нужно изменить порядок умножения:
glRotatef(90, 0, 1, 0); // Notice how this is the first operation ...
// ... but will be applied after
glScalef(1, 10, 1); // This will be applied first, but is the last operation
// Zany, right?
По правде говоря, он чувствует себя менее интуитивным, когда вы пишете программы и используете компьютер, чтобы указать вещи в обратном порядке. Но графические боги, которые будут решаться так, как они хотят, чтобы стек матрицы OpenGL вел себя (вместе с HLSL, GLSL и другими системами: см. Ссылку выше о порядке упорядочения столбцов).
Ответ 2
Если у вас есть массив, который представляет собой матрицу 4x4 следующим образом:
float mat[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
и вы загружаете это в матрицу OpenGL, OpenGL увидит первые 4 поплавков в качестве первого столбца матрицы, а второй 4 - как второй столбец, а третий 4 - как третий столбец матрицы и т. и др.
Итак, каждые 4 поплавка, OpenGL видит в качестве другого столбца. Это известно как порядок столбцов.
Он хранит данные в столбцах. Если вам пришлось перенести матрицу с столбцом, она закончилась бы как матрица строк и наоборот.
Поскольку у вас есть матрица с столбцом, вам также нужно использовать векторы столбцов, что означает, что ваш порядок умножения будет следующим: M * v.
Чтобы доказать это самому себе, возьмите простую матрицу 2x2 с вектором столбца 2x1, умножьте на M * v. Пусть K = транспонирование (M) и r = вектор строки (1x2).
Тогда
M * v= r * K
В нижней строке, как только вы используете основную нотацию столбца или строки в своем коде, вы должны придерживаться ее.