Путаница между C++ и OpenGL для заказа матрицы (по строкам против столбцах)



я полностью запутался в матричных определениях. У меня есть матричный класс, который содержит float[16] который я предположил, что это row-major, основываясь на следующих наблюдениях:



float matrixA[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };
float matrixB[4][4] = { { 0, 1, 2, 3 }, { 4, 5, 6, 7 }, { 8, 9, 10, 11 }, { 12, 13, 14, 15 } };


matrixA и matrixB оба имеют одинаковую линейную компоновку в памяти (т. е. все числа в порядке). Согласно http://en.wikipedia.org/wiki/Row-major_order это указывает на основной макет строки.



matrixA[0] == matrixB[0][0];
matrixA[3] == matrixB[0][3];
matrixA[4] == matrixB[1][0];
matrixA[7] == matrixB[1][3];


таким образом, matrixB[0] = строке 0, matrixB[1] = строка 1 и др. Опять же, это указывает на основной макет строки.



моя проблема / путаница возникает, когда я создаю матрицу перевода, которая выглядит так:



1, 0, 0, transX
0, 1, 0, transY
0, 0, 1, transZ
0, 0, 0, 1


который выложен в памяти как,{ 1, 0, 0, transX, 0, 1, 0, transY, 0, 0, 1, transZ, 0, 0, 0, 1 }.



тогда, когда я звоню glUniformMatrix4fv, мне нужно установить флаг транспонирования в GL_FALSE, указывая, что он является основным столбцом, иначе преобразования, такие как translate / scale и т. д., не применяются правильно:




если транспонировать GL_FALSE, предполагается, что каждая матрица поставляется в
колонка основного порядка. Если транспонировать GL_TRUE, предполагается, что каждая матрица
поставьте в заказе майора строки.




почему моя матрица, которая кажется строкой-мажором, должна быть передана OpenGL как столбец-мажор?

813   3  

3 ответов:

матричная нотация, используемая в документации opengl, не описывает макет в памяти для матриц OpenGL

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

OpenGL матрицы имеют тот же макет памяти, что и матрицы directx.

x.x x.y x.z 0
y.x y.y y.z 0
z.x z.y z.z 0
p.x p.y p.z 1

или

{ x.x x.y x.z 0 y.x y.y y.z 0 z.x z.y z.z 0 p.x p.y p.z 1 }
  • x, y, z-3-компонентные векторы, описывающие матричную систему координат (локальную систему координат внутри относительно глобальной системы координат).

  • p-3-компонентный вектор, описывающий начало координат матрицы.

что означает, что матрица преобразования должна быть заложена в памяти вот так:

{ 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, transX, transY, transZ, 1 }.

оставим это, а остальное должно быть легко.

- - - цитата из старого OpenGL faq--


9.005 несколько столбцов матриц в OpenGL или строкам?

для целей программирования матрицы OpenGL представляют собой 16-значные массивы с базовыми векторами, расположенными последовательно в памяти. Компоненты перевода занимают 13-й, 14-й и 15-й элементы 16-элементной матрицы, где индексы пронумерованы от 1 до 16, как описано в разделе 2.11.2 спецификации OpenGL 2.1.

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

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


чтобы суммировать ответы SigTerm и dsharlet: обычный способ преобразования вектора в GLSL-умножить вектор на матрицу преобразования:

mat4 T; vec4 v; vec4 v_transformed; 
v_transformed = T*v;

для того, чтобы это работало, OpenGL ожидает макет памяти T быть, как описано SigTerm,

{1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, transX, transY, transZ, 1 }

который также называется "колонка майор". Однако в вашем коде шейдера (как указано в ваших комментариях) вы правильно умножили вектор на преобразование матрица:

v_transformed = v*T;

который дает только правильный результат, если T транспонируется, т. е. макет

{ 1, 0, 0, transX, 0, 1, 0, transY, 0, 0, 1, transZ, 0, 0, 0, 1 }

(т. е. основных строк'). Поскольку вы уже предоставили правильный макет для вашего шейдера, а именно row major, не было необходимости устанавливать transpose флаг glUniform4v.

Вы имеете дело с двумя отдельными проблемами.

во-первых, ваши примеры имеют дело с памятью. Ваш массив [4][4] является основным строком, потому что вы использовали соглашение, установленное c многомерными массивами, чтобы соответствовать вашему линейному массиву.

второй вопрос-это вопрос соглашения о том, как вы интерпретируете матрицы в своей программе. glUniformMatrix4fv используется для установки параметра шейдера. Вычисляется ли ваше преобразование для строки вектор или вектор-столбец преобразование зависит от того, как вы используете матрицу в коде шейдера. Поскольку вы говорите, что вам нужно использовать векторы столбцов, я предполагаю, что ваш шейдерный код использует матрицу A и вектор-столбец x вычислить x' = A x.

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

эта ссылка имеет некоторые хорошие дальнейшие обсуждения:http://steve.hollasch.net/cgindex/math/matrix/column-vec.html

Comments

    Ничего не найдено.