Содержание

WebGL2Fundamentals.org

Fix, Fork, Contribute

WebGL2 Матрицы против математических матриц

Эта статья является отступлением от различных статей, которые говорят о матрицах, в частности статьи, которая вводит матрицы, но также статьи, которая вводит 3D, статьи о перспективной проекции, и статьи о камерах.

В программировании в общем строка идет слева направо, столбец идет вверх и вниз.

стол·бец

/ˈkäləm/

существительное

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

    синонимы: колонна, столб, шест, вертикаль, …

  2. вертикальное деление страницы или текста.

строка

/rō/

существительное

  • горизонтальная линия записей в таблице.

Мы можем видеть примеры в нашем программном обеспечении. Например, мои текстовые редакторы показывают Строки и столбцы, строки являются другим словом для строки в этом случае, поскольку столбец уже занят

Обратите внимание в нижней левой области строка состояния показывает строку и столбец.

В программном обеспечении для работы с электронными таблицами мы видим, что строки идут поперек

А столбцы идут вниз.

Итак, когда мы создаем матрицу 3x3 или 4x4 в JavaScript для WebGL, мы делаем их так

const m3x3 = [
  0, 1, 2,  // строка 0
  3, 4, 5,  // строка 1
  6, 7, 8,  // строка 2
];

const m4x4 = [
   0,  1,  2,  3,  // строка 0 
   4,  5,  6,  7,  // строка 1
   8,  9, 10, 11,  // строка 2
  12, 13, 14, 15,  // строка 3
];

Ясно следуя соглашениям выше, первая строка m3x3 - это 0, 1, 2, а последняя строка m4x4 - это 12, 13, 14, 15

Как мы видим в первой статье о матрицах, чтобы сделать довольно стандартную WebGL 3x3 2D матрицу перевода, значения перевода tx и ty идут в позиции 6 и 7

const some3x3TranslationMatrix = [
   1,  0,  0,
   0,  1,  0,
  tx, ty,  1,
];

или для матрицы 4x4, которая вводится в первой статье о 3D, перевод идет в позиции 12, 13, 14, как в

const some4x4TranslationMatrix = [
   1,  0,  0,  0,
   0,  1,  0,  0,
   0,  0,  1,  0,
  tx, ty, tz,  1,
];

Но есть проблема. Математические соглашения для матричной математики обычно делают вещи в столбцах. Математик написал бы матрицу перевода 3x3 так

и матрицу перевода 4x4 так

Это оставляет нас с проблемой. Если мы хотим, чтобы наши матрицы выглядели как математические матрицы, мы можем решить написать матрицу 4x4 так

const some4x4TranslationMatrix = [
   1,  0,  0,  tx,
   0,  1,  0,  ty,
   0,  0,  1,  tx,
   0,  0,  0,  1,
];

К сожалению, делать это так имеет проблемы. Как упоминалось в статье о камерах, каждый из столбцов матрицы 4x4 часто имеет значение.

Первый, второй и третий столбцы часто считаются осями x, y и z соответственно, а последний столбец - это позиция или перевод.

Одна проблема в том, что в коде было бы не весело пытаться получить эти части отдельно. Хотите ось Z? Вам пришлось бы делать это

const zAxis = [
  some4x4Matrix[2],
  some4x4Matrix[6],
  some4x4Matrix[10],
];

Ух!

Итак, способ, которым WebGL, и OpenGL ES, на котором основан WebGL, обходит это, заключается в том, что он называет строки “столбцами”.

const some4x4TranslationMatrix = [
   1,  0,  0,  0,   // это столбец 0
   0,  1,  0,  0,   // это столбец 1
   0,  0,  1,  0,   // это столбец 2
  tx, ty, tz,  1,   // это столбец 3
];

Теперь это соответствует математическому определению. Сравнивая с примером выше, если мы хотим ось Z, все, что нам нужно сделать, это

const zAxis = some4x4Matrix.slice(8, 11);

Для тех, кто знаком с C++, сам OpenGL требует, чтобы 16 значений матрицы 4x4 были последовательными в памяти, поэтому в C++ мы могли бы создать структуру или класс Vec4

// C++
struct Vec4 {
  float x;
  float y;
  float z;
  float w;
};

и мы могли бы создать матрицу 4x4 из 4 из них

// C++
struct Mat4x4 {
  Vec4 x_axis;
  Vec4 y_axis;
  Vec4 z_axis;
  Vec4 translation;
}

или просто

// C++
struct Mat4x4 {
  Vec4 column[4];
}

И это просто казалось бы работающим.

К сожалению, это выглядит совсем не как математическая версия, когда вы фактически объявляете одну статически в коде.

// C++
Mat4x4 someTranslationMatrix = {
  {  1,  0,  0,  0, },
  {  0,  1,  0,  0, },
  {  0,  0,  1,  0, },
  { tx, ty, tz,  1, },
};

Или обратно к JavaScript, где у нас обычно нет чего-то вроде C++ структур.

const someTranslationMatrix = [
   1,  0,  0,  0,
   0,  1,  0,  0,
   0,  0,  1,  0,
  tx, ty, tz,  1,
];

Итак, с этим соглашением называть строки “столбцами” некоторые вещи проще, но другие могут быть более запутанными, если вы математик.

Я поднимаю все это, потому что эти статьи написаны с точки зрения программиста, а не математика. Это означает, что как и каждый другой одномерный массив, который обрабатывается как двумерный массив, строки идут поперек.

const someTranslationMatrix = [
   1,  0,  0,  0,  // строка 0
   0,  1,  0,  0,  // строка 1
   0,  0,  1,  0,  // строка 2
  tx, ty, tz,  1,  // строка 3
];

точно так же, как

// изображение смайлика
const dataFor7x8OneChannelImage = [
    0, 255, 255, 255, 255, 255,   0,  // строка 0
  255,   0,   0,   0,   0,   0, 255,  // строка 1
  255,   0, 255,   0, 255,   0, 255,  // строка 2
  255,   0,   0,   0,   0,   0, 255,  // строка 3
  255,   0, 255,   0, 255,   0, 255,  // строка 4
  255,   0, 255, 255, 255,   0, 255,  // строка 5
  255,   0,   0,   0,   0,   0, 255,  // строка 6
    0, 255, 255, 255, 255, 255,   0,  // строка 7
]

и поэтому эти статьи будут ссылаться на них как на строки.

Если вы математик, вы можете найти это запутанным. Мне жаль, что у меня нет решения. Я мог бы назвать то, что явно является строкой 3, столбцом, но это также было бы запутанно, поскольку это не соответствует никакому другому программированию.

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

Есть предложения или замечания? Создайте issue на GitHub.
comments powered by Disqus