Ответ 1
Давайте начнем с основ.
Обычно вы хотите преобразовать ваши локальные вершины треугольника с помощью следующих шагов:
local-space coords-> world-space coords -> view-space coords -> clip-space coords
В стандарте GL первые 2 преобразования выполняются через GL_MODELVIEW_MATRIX
, третий выполняется через GL_PROJECTION_MATRIX
Эти преобразования модельного представления для многих интересных преобразований, которые мы обычно хотим применить (скажем, переводить, масштабировать и вращать, например), могут быть выражены как вектор-матричное умножение, когда мы представляем вершины в однородные координаты. Как правило, вершина V = (x, y, z)
представлена в этой системе как (x, y, z, 1)
.
Ok. Скажем, мы хотим преобразовать вершину V_local через перевод, затем поворот, затем перевод. Каждое преобразование может быть представлено в виде матрицы *, назовем их T1, R1, T2.
Мы хотим применить преобразование к каждой вершине: V_view = V_local * T1 * R1 * T2
. Матричное умножение является ассоциативным, мы можем вычислить раз и навсегда M = T1 * R1 * T2
.
Таким образом, нам нужно только передать M в программу вершин и вычислить V_view = V_local * M
. В итоге типичный вершинный шейдер умножает положение вершин на одну матрицу. Вся работа по вычислению этой матрицы - это перемещение вашего объекта из локального пространства в пространство клипа.
Хорошо... Я просмотрел ряд важных деталей.
Во-первых, то, что я описал до сих пор, действительно только охватывает преобразование, которое мы обычно хотим делать в пространстве представления, а не в пространстве клипов. Однако аппаратное обеспечение ожидает, что выходное положение вершинного шейдера будет представлено в этом специальном пространстве клипов. Трудно объяснить координаты клип-пространства без значительной математики, поэтому я оставлю это, но важный бит заключается в том, что преобразование, которое приводит вершины к этому пространству клипа, обычно может быть выражено как однотипное матричное умножение. Это то, что вычисляются старые gluPerspective, glFrustum и glOrtho.
Во-вторых, это то, что вы применяете к позициям вершин. Математика для преобразования нормалей несколько отличается. Это потому, что вы хотите, чтобы нормаль оставалась перпендикулярной поверхности после преобразования (для справки она требует умножения на обратную транспозицию модельного представления в общем случае, но во многих случаях это может быть упрощено)
В-третьих, вы никогда не отправляете 4-D координаты в вершинный шейдер. В общем, вы проходите трехмерные. OpenGL преобразует эти трехмерные координаты (или 2-D, btw) в 4-D, чтобы вершинный шейдер не добавлял дополнительную координату. он расширяет каждую вершину, чтобы добавить 1 как координату w
.
Итак... чтобы собрать все это вместе, для каждого объекта вам нужно вычислить те магические матрицы M на основе всех преобразований, которые вы хотите применить к объекту. Внутри шейдера вам необходимо умножить каждую позицию вершин на эту матрицу и передать ее в вывод вершинного шейдера. Типичный код более или менее (используется старая номенклатура):
mat4 MVP;
gl_Position=MVP * gl_Vertex;
* фактические матрицы можно найти в Интернете, особенно на страницах руководства для каждой из этих функций: rotate, translate, scale, perspective, ortho