Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

RedBook

.pdf
Скачиваний:
18
Добавлен:
11.06.2015
Размер:
7.43 Mб
Скачать

рисования. Рисунок 3-2 демонстрирует порядок, в котором эти операции производятся вашим компьютером.

Рисунок 3-2. Этапы преобразования вершин

Чтобы задать видовое, модельное или проекционное преобразование, вы заполняете матрицу M размерностью 4x4 элемента. Затем эта матрица множится на координаты каждой вершины, в результате чего и происходит преобразование этих координат v`=Mv. (Помните, что вершина всегда имеет 4 координаты (x, y, z, w), хотя в большинстве случаев w=1, а для двумерных изображений z=0.) Заметьте, что видовые

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

Видовые и модельные преобразования, указанные вами, комбинируются в видовой матрице, применяемой к входящим объектным координатам для получения видовых координат. Если вы задаете дополнительные плоскости отсечения для удаления

определенных объектов со сцены или для создания разрезанного вида объектов эти плоскости используются на следующем шаге. После этого OpenGLприменяет матрицу проекции для получения усеченных координат. Это преобразование определяет объем видимости; объекты вне этого объема полностью или частично отсекаются (отбрасываются) и не рисуются в финальной сцене. После этого производится перспективное деление, то есть, деление координат x, y, z на w, для получения нормализованных координат устройства. В заключении, преобразованные координаты конвертируются в оконные координаты с помощью трансформации порта просмотра. Вы

можете манипулировать размерами порта просмотра для растяжения или сжатия финального изображения.

Вы можете правильно предположить, что для определения того, какие пиксели рисовать на экране, достаточно координат x и y. Однако все преобразования производятся также и над z координатой. Таким образом, в конце процесса преобразований величина соответствующей z координаты верно отражает глубину каждой вершины (исчисляемую в дистанции от экрана). Одно из применений для значений глубины избежать ненужного рисования. Например, предположим, что две вершины имеют равные x и y координаты, но разную глубину. OpenGL может использовать эту информацию для определения того, какие поверхности перекрыты другими поверхностями и, таким образом, не рисовать невидимые поверхности. Кроме того, координата z в некоторых проекционных матрицах при перемножении может влиять на результирующие значения координат x и y.

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

3.1.1 Простой пример: рисуем куб

Пример 3-1 рисует куб, который масштабируется модельной трансформацией. Видовая трансформация позиционирует и наводит камеру на то место, где будет нарисован куб. Проекционная трансформация и трансформация порта просмотра также указаны. После примера следуют разделы, разбирающие пример 3-1. В них дается краткое описание команд трансформаций.

Рисунок 3-3. Трансформированный куб

Пример 3-1. Трансформированный куб. Файл cube.cpp

#include <glut.h>

//Инициализация void init(void)

{

glClearColor(0.0,0.0,0.0,0.0); glShadeModel(GL_FLAT);

}

//Отображение

void display(void)

{

glClear(GL_COLOR_BUFFER_BIT); glColor3f(1.0,1.0,1.0);

//Очистить матрицу glLoadIdentity();

//Видовая трансформация(камера) gluLookAt(0.0,0.0,5.0,0.0,0.0,0.0,0.0,1.0,0.0);

//Модельная трансформация glScalef(1.0,2.0,1.0); glutWireCube(1.0); glFlush();

}

//Изменение размеров окна void reshape(int w, int h)

{

glViewport(0,0,(GLsizei) w, (GLsizei) h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum(-1.0,1.0,-1.0,1.0,1.5,20.0); glMatrixMode(GL_MODELVIEW);

}

int main(int argc, char** argv)

{

glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(500,500); glutInitWindowPosition(100,100); glutCreateWindow("Transformed Cube"); init();

glutDisplayFunc(display);

glutReshapeFunc(reshape);

glutMainLoop(); return 0;

}

3.1.1.1Видовая трансформация

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

В примере 3-1, после инициализации матрицы, видовая трансформация задается командой gluLookAt(). Аргументы этой команды определяют, где находится камера (точка обзора), куда она направлена, и какое направление считать верхним. Значения аргументов, использованные здесь, помещают камеру в точку (0, 0, 5), наводят ее на точку (0, 0, 0) и задают вектор направления вверх как (0, 1, 0). Вектор верхнего направления задает ориентацию камеры.

Если бы gluLookAt() не была вызвана, камера имела бы позицию и ориентацию по умолчанию. По умолчанию камера расположена в начале координат (0, 0, 0),

направлена вдоль отрицательного направления оси z, и вектором верхнего направления имеет (0, 1, 0). Таким образом суммарный эффект от вызова команды gluLookAt() в примере 3-1 заключается в перемещении камеры по оси zна 5 единиц.

3.1.1.2Модельная трансформация

Вы используете модельную трансформацию для позиционирования и ориентирования модели. Например, вы можете поворачивать, переносить или масштабировать модель, а также производить комбинации этих операций. В примере 3-1, использована трансформация glScalef(). Аргументами этой команды являются коэффициенты масштабирования модели по трем осям. Если все три коэффициента равны 1.0 – команда не дает никакого эффекта. В примере 3-1 куб рисуется с удвоенным масштабом по оси y. Таким образом, если бы один из углов куба изначально имел координаты (3.0, 3.0, 3.0), он был бы нарисован в точке (3.0, 6.0, 3.0). Эффект от этого преобразования в примере 3-1 трансформирует куб в параллепипед.

Заметьте, что вместо того, чтобы передвигать камеру, вы могли бы отодвинуть куб от камеры (с помощью модельного преобразования). Такая двойственность природы

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

Также заметьте, что видовые и модельные трансформации включены в функцию display() вместе с вызовом функции glutWireCube(), рисующей куб. Таким образом, display() может использоваться несколько раз для перерисовки содержимого окна, например, если оно было перемещено, и вы уверены, что каждый раз куб рисуется верно, с применением нужных преобразований. Преимущества повторного использования display() перевешивают недостаток, связанный с необходимостью загрузки единичной матрицы до указания преобразований, особенно если иные преобразования могут быть заданы между вызовами display().

3.1.1.3Проекционная трансформация

Определение проекционной трансформации походит на выбор линз для камеры. Вы

можете думать об этом преобразовании как о задающем поле просмотра или объем видимости и, таким образом, определяющем какие объекты лежат внутри этого объема и как они выглядят (до некоторой степени). Это эквивалентно выбору между широкоугольными, нормальными или телефото линзами. С широкоугольными линзами вы можете охватить большее пространство, однако телефото линзы позволяют фотографировать объекты таким образом, как будто они ближе к вам, чем на самом деле. В компьютерной графике вам нет необходимости платить 2000 долларов за 2000

миллиметровые телефото - линзы как только вы включили свою рабочую станцию, все, что вам нужно сделать это указать меньшее число для объема видимости.

В дополнение к решениям об объеме видимости, проекционная трансформация определяет, (как и следует из ее имени) как объекты будут проецироваться на экран. Два основных типа проекций реализовано в OpenGL в явном виде. Вы можете задавать связанные с ними параметры различными способами, применяя несколько специальных команд. Первый из этих типов проекций перспективная проекция соответствует тому, как вы видите в реальной жизни. Перспектива заставляет удаленные от вас объекты выглядеть меньше. Например, если посмотреть на рельсовую дорогу, кажется, что где- то далеко рельсы сходятся, чего на самом деле конечно не происходит. Если вы пытаетесь создать реалистичное изображение, вероятно, вы захотите использовать именно перспективную проекцию, которая в предыдущем примере кода задается командой glFrustum().

Проекции другого типа ортографические переносят объекты на экран без воздействия на их относительный размер. Ортографическая проекция используется в архитектурных приложениях и САПРах (Системах Автоматизированного Проектирования), где результирующее изображение должно скорее отражать реальные размеры объектов, а не то, как они выглядят. Архитекторы создают перспективные изображения для демонстрации того, как конкретное здание или интерьер будут выглядеть с разных точек зрения, но они используют ортографические проекции для создания чертежей.

До вызова glFrustum(), задающего проекционную трансформацию, должны быть сделаны некоторые приготовления. Как показано в функции reshape() примера 3-1, вначале используется команда glMatrixMode() с параметром GL_PROJECTION. В результате текущей матрицей становится проекционная матрица, и все последующие задаваемые преобразования будут влиять именно на нее. Как вы можете заметить, через несколько строк кода команда glMatrixMode() вызывается снова, на этот раз с параметром GL_MODELVIEW. Таким образом, сообщается о том, что с этого момента последующие преобразования будут влиять на видовую матрицу, а не на проекционную.

Заметьте, что в коде используется команда glLoadIdentity() для инициализации текущей проекционной матрицы. В результате только задаваемая проекционная трансформация будет иметь эффект. Теперь может быть вызвана glFrustum() с аргументами, определяющими параметры проекционного преобразования. В предыдущем примере и проекционное преобразование, и преобразование порта просмотра содержатся в функции reshape(), которая вызывается, когда окно создается, а также каждый раз при перемещении или изменении размеров окна. Это имеет смысл, поскольку проецирование (соотношение ширина к высоте объема видимости проекции) и воздействие орта просмотра непосредственно связаны с экраном или, более конкретно с отношением размером окна на экране.

3.1.1.4Трансформация порта просмотра

Вместе проекционное преобразование и преобразование порта просмотра определяет, каким образом изображение будет перенесено на экран компьютера. Проекционное преобразование задает механику того, как будет происходить перенос, преобразование порта просмотра задает форму и размеры доступной области на экране, куда будет перенесено изображение. Поскольку порт просмотра определяет регион, который изображение будет занимать на экране, вы можете думать о трансформации порта

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

Аргументы команды glViewport() (задающей порт просмотра) задают начальную точку доступного экранного пространства внутри окна (в данном примере (0, 0)), а также ширину и высоту доступной области на экране. Все эти величины измеряются в экранных пикселях. Вот почему эта команда должна быть вызвана из reshape(): если изменяется размер окна, размер порта просмотра должен также измениться. Заметьте, что ширина и высота задаются с использованием реальной ширины и высоты окна; достаточно часто вам понадобится задавать порт просмотра именно таким образом, вместо того, чтобы применять абсолютные значения.

3.1.1.5Рисуем сцену

После того, как все необходимые преобразования были заданы, вы можете нарисовать сцену (или снять фотографию). Во время рисования сцены OpenGLпреобразует каждую вершину каждого объекта на сцене с помощью видовых и модельных преобразований.

Далее каждая вершина преобразуется в соответствии с проекционной трансформацией и отсекается, если она лежит вне объема видимости, заданного проекционной трансформацией. Наконец, оставшиеся преобразованные вершины делятся на wи накладываются на порт просмотра.

3.1.2 Команды общего назначения для преобразований

В этом разделе обсуждаются некоторые команды OpenGL, которые вы можете счесть полезными для указания преобразований. Вы уже видели две из этих команд: glMatrixMode() и glLoadIdentity(). Две другие, описанные здесь команды glLoadMatrix*() и glMultMatrix*() позволяют задать любую матрицу любого преобразования непосредственно и умножить на нее текущую матрицу. Более специфические команды преобразований, такие как, gluLookAt() и glScale*(), будут рассмотрены позже.

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

void glMatrixMode (GLenum mode);

Указывает, какая из матриц, а именно видовая, проекционная или текстурная, будет изменена. Аргумент mode может принимать значения GL_MODELVIEW (видовая матрица), GL_PROJECTION (проекционная матрица) или GL_TEXTURE (текстурная матрица). Последующие команды преобразований влияют на указанную матрицу. Заметьте, что в каждый момент времени может быть изменена только одна матрица. По умолчанию видовая матрица является текущей (подлежащей изменению) и все три матрицы являются единичными.

Вы используете команду glLoadIdentity() для очистки текущей матрицы для будущих преобразований, поскольку эти преобразования изменяют текущую матрицу. В

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

void glLoadIdentity (void);

Устанавливает текущую (подлежащую модификации) матрицу в единичную с размерностью 4 x4.

Если вы хотите загрузить в качестве текущей некоторую специфическую матрицу (например, чтобы задать какую-либо особенную проекцию), используйте glLoadMatrix*(). Похожим образом используйте glMultMatrix*() для умножения текущей матрицы на матрицу, переданную в качестве аргумента. Аргументом для обеих

этих команд выступает вектор, содержащий 16 величин (), задающих матрицу M следующим образом:

.

Помните, что вы можете повысить эффективность, применяя дисплейные списки (списки отображения) для наиболее часто применяемых матриц, вместо того, чтобы пересчитывать их каждый раз. (Часто OpenGLреализации должны вычислять обратную

матрицу видовой матрицы для корректного преобразования нормалей и отсекающих плоскостей в видовые координаты.)

Замечание: Если вы программируете на C и объявляете матрицу как m[4][4], то элемент m[i][j] будет соответствовать элементу в i-ом столбце и j-ой строке матрицы преобразования OpenGL. Однако это не совсем обычно для языка C, поскольку по соглашению m[i][j] соответствует элементу в i-ой строке и j-ом столбце. Иными словами в Cпринято хранить матрицы по строкам, но OpenGLпри получении подобного указателя будет трактовать его как матрицу, хранимую по столбцам. Во избежание ошибок объявляйте матрицы в виде m[16].

void glLoadMatrix{fd} (const TYPE *m);Умножает текущую матрицу на матрицу, заданную 16 величинами вектора m и сохраняет результат в качестве текущей матрицы.

Устанавливает 16 величин текущей матрицы в значения, содержащиеся в m.

void glMultMatrix{fd} (const TYPE *m);Умножает текущую матрицу на матрицу, заданную 16 величинами вектора m и сохраняет результат в качестве текущей матрицы.

Умножает текущую матрицу на матрицу, заданную 16 величинами вектора m и сохраняет результат в качестве текущей матрицы.

Замечание: Все перемножения матриц в OpenGL производятся следующим образом. Обозначим текущую матрицу как C, а матрицу, заданную командой glMultMatrix*() или любой командой преобразования как M. После умножения результирующей матрицей всегда является CM. Поскольку в общем случае произведение матриц не коммутативно, порядок перемножения матриц имеет большое значение.

3.2 Видовые и модельные преобразования

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

из них может более естественно соответствовать эффекту от произведенной трансформации, чем другой. Если вы найдете естественный подход для своего конкретного приложения, вам будет намного проще визуализировать необходимые трансформации и затем написать соответствующий код для манипуляций с матрицами. Первая часть этого раздела посвящена того, как следует понимать преобразования. Затем рассмотрим конкретные команды. Пока что мы будем использовать только команды матричных манипуляций, уже виденные вами. Помните о том, что вы должны вызвать команду glMatrixMode() с аргументом GL_MODELVIEWдо того, как производить модельные или видовые преобразования.

3.2.1 Понимание преобразований

Начнем с простого случая включающего всего два преобразования: поворот против часовой стрелки на 45 градусов с центром в начале координат вдоль оси z и перенос

вдоль оси xв ее положительном направлении. Предположим, что объект достаточно мал по сравнению с преобразованием (то есть мы можем увидеть результат преобразования) и, что изначально он находится в начале координат. Если вы сначала повернете объект, а затем перенесете его, он в результате окажется на оси x. Если же вы сначала перенесете его по оси x, а затем повернете вокруг начала координат, объект окажется на линии y=x, как показано на рисунке 3-4. В общем случае порядок преобразования является весьма критичным. Если вы выполняете преобразование A, а затем преобразование B, вы практически во всех случаях получите результат отличный от того, какой получили бы, производя преобразования в обратном порядке.

Рисунок 3-4. Сначала поворачиваем или сначала переносим

Теперь поговорим о порядке, в котором вы задаете серии преобразований. Все видовые и модельные преобразования представлены в виде матриц размерностью 4x4. Каждый

успешный вызов команды glMultMatrix*() или другой команды преобразования умножает текущую видовую матрицу Cна новую (заданную вами явно или неявно) матрицу M, в результате чего текущей матрицей становится CM. В итоге текущая видовая матрица умножается на передаваемые по конвейеру вершины v. Этот процесс означает, что последняя команда преобразования, вызванная в вашей программе, на самом деле будет первой применена к вершинам: CMv. Таким образом, можно смотреть на это как на необходимость задавать матрицы преобразований в обратном порядке. Как и во многих других случаях, однако, как только вы научитесь правильно думать об этом, обратный порядок начнет казаться прямым.

Рассмотрим следующий фрагмент кода, рисующий точку с учетом трех преобразований.

glMatrixMode(GL_MODELVIEW);

glLoadIdentity();

//Применить преобразование N

glMultMatrixf(N);

glMultMatrixf(M);

//Применить преобразование M

glMultMatrixf(L);

//Применить преобразование L

glBegin(GL_POINTS);

//Нарисовать преобразованную вершину v

glVertex3fv(v);

glEnd();

 

В этом коде видовая матрица последовательно содержит матрицы I (единичную), N, NM и NML. Преобразованные вершины будут равны NMLv. Таким образом, процесс трансформации вершин можно записать в виде N(M(Lv)) то есть сначала L умножается на v, затем M на Lv и, наконец, N на MLv. Заметьте, что преобразования действительно применяются к вершинам в порядке обратном к тому, в котором вы их задавали. (На самом деле вершина участвует лишь в одном перемножении, так как матрицы отдельных преобразований в данном примере N, M и Lпредварительно перемножены между собой и получена одна результирующая матрица вида.)

3.2.1.1Фиксированная система координат

Таким образом, если вам нравится думать о преобразованиях в терминах фиксированной координатной системы в которой перемножение матриц влияет на позицию, ориентацию и масштабирование вашей модели вы должны думать о перемножениях как о происходящих в обратном порядке относительно того, в котором они появляются в коде. Если бы вы хотели, чтобы после всех операций объект появился на оси x в простом примере, показанном в левой части рисунка 3-4 (вращение вокруг начала координат и перенос по оси x), первым следовало бы произойти вращение, а затем перенос. Однако, чтобы это сделать, вам следует изменить порядок операций на обратный. В результате код должен выглядеть примерно следующим образом (в нем R обозначает матрицу поворота, а T матрицу переноса):

glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMultMatrixf(T); //Перенос glMultMatrixf(R); //Поворот нарисовать_объект();

3.2.1.2Изменение локальной системы координат

Другой способ рассмотрения матричных перемножений заключается в том, чтобы забыть о фиксированной системе координат, в которой трансформируется модель и вместо этого представить себе локальную систему координат, привязанную к рисуемому объекту. Все операции происходят относительно этой изменяющейся системы координат. При таком подходе оказывается, что матричные преобразования появляются в коде в своем естественном порядке. (Независимо от точки зрения код всегда остается тем же самым, но изменяется то, как вы его осознаете.) Рассматривая пример на рисунке 3-4, представьте себе координатную систему, привязанную к объекту. Операция переноса сдвигает объект и его координатную систему по оси x. Затем поворот совершается вокруг теперь уже перенесенного начала координат. Таким образом, объект поворачивается на месте в своей позиции на оси.

Такой подход следует использовать для приложений, рисующих, например, руку робота, в которой присутствуют точки соединения объектов на плече, локте, запястье и на каждом из пальцев. Для выяснения того, где должны быть кончики пальцев относительно тела, следует начать с плеча, опуститься до запястья и далее, задавая необходимые повороты и переносы в каждой точке соединения. Если думать об этом

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

Этот второй подход, однако, может вызвать проблемы в тех случаях, когда применяется масштабирование, особенно, если оно неравномерное (то есть по разным осям используются разные коэффициенты растяжения/сжатия). После равномерного масштабирования с коэффициентом растяжения/сжатия kперенос на (a, b, c) сдвигает вершину на расстояния (a*k,b*k,c*k) поскольку координатная система растянута или сжата. Неравномерное масштабирование вкупе с поворотами может вообще сделать оси локальной координатной системы неперпендикулярными друг другу.

Как было отмечено выше, обычно вы в своей программе задаете видовые трансформации перед всеми модельными. В этом случае вершина модели сначала преобразуется к выбранной ориентации, а затем преобразуется видовой операцией. Поскольку матричные перемножения должны быть заданы в обратном порядке, видовые команды должны быть заданы первыми. Заметьте, однако, что вы не обязаны задавать видовые или модельные преобразования, если вы удовлетворены тем, что определено по умолчанию. Если видовое преобразование не задано, то «камера» по

умолчанию находится в начале координат и направлена вдоль отрицательного

направления оси z. Если не заданы модельные трансформации модель не двигается и сохраняет свою позицию, ориентацию и размер.

Поскольку команды для выполнения модельных преобразований могут быть использованы для выполнения видовых преобразований, модельные преобразования рассматриваются первыми, несмотря на то, что видовые преобразования должны первыми задаваться. Данный порядок рассмотрения также соответствует тому, как думают многие программисты при планировании своего кода. Часто сначала они пишут весь код, необходимый для композиции сцены, включая команды преобразований для верного расположения и ориентирования объектов сцены относительно друг друга. Далее они решают, где они хотят поместить точку наблюдения и пишут соответствующий код видового преобразования.

3.2.2 Модельные трансформации

Существует три команды OpenGL для модельных преобразований: glTranslate*(), glRotate*() и glScale*(). Как вы можете предположить, эти команды трансформируют объект (или координатную систему в зависимости от того, как вы предпочитаете думать об этом), перенося, поворачивая, увеличивая, уменьшая или отражая его. Все эти команды эквивалентны созданию соответствующей матрицы переноса, поворота

или масштабирования с последующим вызовом glMultMatrix*() с этой матрицей в качестве аргумента. Однако использование этих трех команд может быть быстрее, чем glMultMatrix*() – OpenGL автоматически вычисляет для вас нужные матрицы.

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

3.2.2.1Перенос

void glTranslate{fd} (TYPE x, TYPE y, TYPE z);

Умножает текущую матрицу на матрицу, передвигающую (переносящую) объект на расстояния x, y, z, переданные в качестве аргументов команды, по соответствующим осям (или перемещает локальную координатную систему на те же расстояния).

На рисунке 3-5 изображен эффект команды glTranslate*().

Рисунок 3-5. Перенос объекта

Соседние файлы в предмете Компьютерная Графика