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

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

 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, предполагается, что каждая matrix поставляется в основном порядке столбца. Если транспонирование GL_TRUE, предполагается, что каждая matrix поставляется в основном порядке строки.

Почему моя matrix, которая, как представляется, имеет большое значение, должна быть передана OpenGL в качестве столбца?

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

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

Матрицы OpenGL имеют такую ​​же компоновку памяти, что и матрицы directx .

 xx xy xz 0 yx yy yz 0 zx zy zz 0 px py pz 1 

или

 { xx xy xz 0 yx yy yz 0 zx zy zz 0 px py pz 1 } 
  • x, y, z – 3-компонентные векторы, описывающие матричную систему координат (локальная система координат в пределах относительно глобальной системы координат).

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

Это означает, что matrix перевода должна быть выложена в памяти следующим образом:

 { 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.

Колонка-майор против рядового знака – это чисто условное соглашение. Обратите внимание, что пост-умножение с основными matrixми столбцов дает тот же результат, что и предварительное умножение на основные матрицы. Спецификация 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 } 

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

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

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

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

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

Эта ссылка содержит некоторые полезные обсуждения: http://steve.hollasch.net/cgindex/math/matrix/column-vec.html

  • Зачем использовать softmax в отличие от стандартной нормализации?
  • Как эта побитовая операция проверяет мощность 2?
  • Как округлить до ближайшего 0,5?
  • Вычисление ограничивающей frameworks на некотором расстоянии от координаты lat / long в Java
  • Плавно соединяющие центры
  • Использование atan2 для нахождения угла между двумя векторами
  • Алгоритм для обнаружения пересечения двух прямоугольников?
  • Простой алгоритм пересечения многоугольников
  • Операции с плавающей запятой в C-ассоциативном?
  • Проецирование 3D-точек на двумерную плоскость
  • Метод оценки математических выражений в Java
  • Давайте будем гением компьютера.