В OpenGL используются как основные три системы координат:
левосторонняя, правосторонняя и оконная. Первые две системы являются
трехмерными и отличаются друг от друга направлением оси z: в
правосторонней она направлена на наблюдателя, а в левосторонней – в
глубь экрана. Расположение осей x и y аналогично описанному выше.
Левосторонняя система используется для задания значений параметрам
команды gluPerspective(), glOrtho(), которые будут рассмотрены ниже,
а правосторонняя или мировая система координат во всех остальных
случаях. Отображение трехмерной информации происходит в двумерную
оконную систему координат.
Для задания различных преобразований объектов сцены в OpenGL
используются операции над матрицами, при этом различают три типа
матриц: видовая, проекций и текстуры. Все они имеют размер 4x4.
Видовая матрица определяет преобразования объекта в мировых
координатах, такие как параллельный перенос, изменение масштаба и
поворот. Матрица проекций задает как будут проецироваться трехмерные
объекты на плоскость экрана (в оконные координаты), а матрица
текстуры определяет наложение текстуры на объект.
Для того, чтобы выбрать, какую матрицу надо изменить,
используется команда
void glMatrixMode(GLenum mode)
вызов которой со значением параметра mode равным GL_MODELVIEW,
GL_PROJECTION, GL_TEXTURE включает режим работы с видовой, проекций
и матрицей текстуры соответственно. Для вызова команд, задающих
матрицы того или иного типа необходимо сначала установить
соответствующий режим.
Для определения элементов матрицы текущего типа вызывается
команда
void glLoadMatrix[f d](GLtype *m)
где m указывает на массив из 16 элементов типа float или double в
соответствии с названием команды, при этом сначала в нем должен быть
записан первый столбец матрицы, затем второй, третий и
четвертый.
Команда
void glLoadIdentity(void)
заменяет текущую матрицу на единичную. Часто нужно сохранить
содержимое текущей матрицы для дальнейшего использования, для чего
используют команды
- void glPushMatrix(void)
- void glPopMatrix(void)
Они записывают и восстанавливают текущую матрицу из стека, причем
для каждого типа матриц стек свой. Для видовых матриц его глубина
равна как минимум 32, а для двух оставшихся типов как минимум 2.
Для умножения текущей матрицы слева на другую матрицу
используется команда
void glMultMatrix[f d](GLtype *m)
где m должен задавать матрицу размером 4x4 в виде массива с
описанным расположением данных. Однако обычно для изменения матрицы
того или иного типа удобно использовать специальные команды, которые
по значениям своих параметров создают нужную матрицу и перемножают
ее с текущей. Чтобы сделать текущей созданную матрицу, надо перед
вызовом этой команды вызвать glLoadIdentity().
В целом, для отображения трехмерных объектов сцены в окно
приложения используется следующая последовательность действий:
Коорди- наты объекта |
=> |
Видовые коорди- наты |
=> |
Усеченные коорди- наты |
=> |
Нормали- зованные коорди- наты |
=> |
Оконные координаты |
Рассмотрим
каждое из этих преобразований отдельно.
Видовое преобразование
К видовым преобразованиям будем относить перенос, поворот и
изменение масштаба вдоль координатных осей. Для проведения этих
операций достаточно умножить на соответствующую матрицу каждую
вершину объекта и получить измененные координаты этой вершины:
(x’, y’, z’, 1)T =M * (x, y, z, 1)T
где M матрица видового преобразования. Перспективное
преобразование и проектирование производится аналогично. Сама
матрица может быть создана с помощью следующих команд:
- void glTranslate[f d](GLtype x, GLtype y, GLtype z)
- void glRotate[f d](GLtype angle, GLtype x, GLtype y,
GLtype z)
- void glScale[f d](GLtype x, GLtype y, GLtype z)
glTranlsate..() производит перенос объекта, прибавляя к
координатам его вершин значения своих параметров.
glRotate..() производит поворот объекта против часовой стрелки на
угол angle (измеряется в градусах) вокруг вектора ( x,y,z ).
glScale..() производит масштабирование объекта (сжатие или
растяжение), домножая соответствующие координаты его вершин на
значения своих параметров.
Все эти преобразования будут применяться к примитивам, описания
которых будут находиться ниже в программе. В случае если надо,
например, повернуть один объект сцены, а другой оставить
неподвижным, удобно сначала сохранить текущую видовую матрицу в
стеке командой glPushMatrix(), затем вызвать glRotate..() с нужными
параметрами, описать примитивы, из которых состоит этот объект, а
затем восстановить текущую матрицу командой glPopMatrix().
Кроме изменения положения самого объекта иногда бывает нужно
изменить положение точки наблюдения, что однако также приводит к
изменению видовой матрицы. Это можно сделать с помощью команды
void gluLookAt (GLdouble eyex,
GLdouble eyey,
GLdouble eyez,
GLdouble centerx,
GLdouble centery,
GLdouble centerz,
GLdouble upx,
GLdouble upy,
GLdouble upz)
где точка ( eyex,eyey,eyez ) определяет точку наблюдения, (
centerx, centery, centerz )задает центр сцены, который будет
проектироваться в центр области вывода, а вектор ( upx,upy,upz )
задает положительное направление оси у, определяя поворот камеры.
Если, например, камеру не надо поворачивать, то задается значение
(0,1,0), а со значением (0,-1,0) сцена будет перевернута.
Фактически, эта команда совершает перенос и поворот объектов
сцены, но в таком виде задавать параметры бывает удобнее.
Проекции
В OpenGL существуют ортографическая (параллельная) и
перспективная проекция. Первый тип проекции может быть задан
командами
- void glOrtho(GLdouble left, GLdouble right, GLdouble
bottom, GLdouble top, GLdouble near, GLdouble far)
- void gluOrtho2D(GLdouble left, GLdouble right, GLdouble
bottom, GLdouble top)
Первая команда создает матрицу проекции в усеченный объем
видимости (параллелограмм видимости) в левосторонней системе
координат. Параметры команды задают точки (left, bottom, -near) и
(right, top, -near), которые отвечают левому нижнему и правому
верхнему углам окна вывода. Параметры near и far задают расстояние
до ближней и дальней плоскостей отсечения по дальности от точки
(0,0,0) и могут быть отрицательными.
Во второй команде, в отличие от первой, значения near и far
устанавливаются равными –1 и 1 соответственно.
Перспективная проекция определяется командой
void gluPerspective(GLdouble angley, GLdouble aspect, GLdouble znear, GLdouble zfar)
которая задает усеченный конус видимости в левосторонней системе
координат. Параметр angley определяет угол видимости в градусах по
оси у и должен находиться в диапазоне от 0 до 180. Угол видимости
вдоль оси x задается параметром aspect, который обычно задается как
отношение сторон области вывода. Параметры zfar и znear задают
расстояние от наблюдателя до плоскостей отсечения по глубине и
должны быть положительными. Чем больше отношение zfar/znear, тем
хуже в буфере глубины будут различаться расположенные рядом
поверхности, так как по умолчанию в него будет записываться ‘сжатая’
глубина в диапазоне от 0 до 1 (см. следующий пункт).
Область вывода
После применения матрицы проекций на вход следующего
преобразования подаются так называемые усеченные (clip) координаты,
для которых значения всех компонент (xc, yc,
zc, wc)T находятся в отрезке
[-1,1]. После этого находятся нормализованные координаты вершин по
формуле:
(xn, yn,
zn)T=(xc/wc,
yc/wc,
zc/wc)T
Область вывода представляет из себя прямоугольник в оконной
системе координат, размеры которого задаются командой:
void glViewPort(GLint x, GLint y, GLint width, GLint height)
Значения всех параметров задаются в пикселах и определяют ширину
и высоту области вывода с координатами левого нижнего угла ( x,y ) в
оконной системе координат. Размеры оконной системы координат
определяются текущими размерами окна приложения, точка
(0,0)находится в левом нижнем углу окна.
Используя параметры команды glViewPort(), вычисляются оконные
координаты центра области вывода (ox, oy) по
формулам ox=x+width/2, oy=y+height/2.
Пусть px=width, py=height, тогда можно
найти оконные координаты каждой вершины:
(xw, yw, zw)T = (
(px/2) xn+ ox , (py/2)
yn+ oy , [(f-n)/2] zn+(n+f)/2
)T
При этом целые положительные величины n и f задают минимальную и
максимальную глубину точки в окне и по умолчанию равны 0 и 1
соответственно. Глубина каждой точки записывается в специальный
буфер глубины (z-буфер), который используется для удаления невидимых
линий и поверхностей. Установить значения n и f можно вызовом
функции
void glDepthRange(GLclampd n, GLclampd f)
Команда glViewPort() обычно используется в функции,
зарегистрированной с помощью команды glutReshapeFunc(), которая
вызывается, если пользователь изменяет размеры окна приложения,
изменяя соответсвующим образом область вывода.
|