Координаты отображаемых объектов (примитивов) задаются в мировой системе координат (МСК). В ней же над объектами под воздействием видовой матрицы выполняются заданные действия, например аффинные преобразования. Система координат, в которую попадают вершины объектов после воздействия видовой матрицы, называется системой координат наблюдателя (СКН). В ней рассчитываются цвета объектов и выполняются заданные (например, командой fglClipPlane) отсечения. Далее под воздействием матрицы проецирования координаты СКН переводятся в нормированные координаты (НК). Диапазон их изменения - [-1.0, 1.0]. С окном вывода связывается оконная система координат (ОСК), в которой осуществляется вывод объектов. Непосредственно перед выводом нормированные координаты преобразовываются в оконные.
Схема преобразования координат приведена на рис. 1.
Рис. 1. Схема преобразования координат
С окном вывода, задаваемого на экране монитора, связана физическая система координат (ФСК), определяемая техническими средствами. Начало ФСК - левый верхний угол экрана. Ось абсцисс направлена слева направо; ось ординат - сверху вниз (рис. 2).
Рис. 2. Физическая и оконная системы координат
Единицы измерения координат - пиксели экрана, поэтому физические координаты целочисленные. Наименьшие координаты пикселя xmin = 0 и ymin = 0. Наибольшие координаты определяются установленным разрешением. Так, при разрешении 800×600 пикселей наибольшие координаты пикселя xmax = 799 и ymax = 599. Используемый при задании координат тип данных - INTEGER(4).
В ФСК задаются координаты верхнего левого угла окна OpenGL графических данных и его размеры в пикселях, например:
call fauxInitPosition(10, 10, 500, 400) ! 10,10 - координаты верхнего левого угла окна вывода; 500, 400 - размеры окна OpenGL
Вывод графических данных осуществляется в экранно-ориентированную прямоугольную область окна OpenGL. Такая область называется видовым портом. С ним связана ОСК. Начало ОСК находится в нижнем левом углу видового порта (см. рис. 2). Задаваемые относительно начала ОСК координаты называются оконными.
Однако в окне OpenGL можно задать и другое расположение видового порта и изменить его размеры, применив команду
CALL fglViewport(x, y, width, height)
x, y - координаты нижнего левого угла видового порта относительно нижнего левого угла окна OpenGL; значение по умолчанию - (0, 0). Тип координат - INTEGER(4).
width, height - ширина и высота видового порта; по умолчанию равны соответствующим размерам окна OpenGL. Тип параметров - INTEGER(4).
При необходимости в окне OpenGL можно создать несколько видовых портов.
fglViewport задает преобразование координат области вывода, переводящие нормированные координаты xnd, ynd в оконные координаты xw, yw. Преобразования выполняются по формулам:
где width и height - ширина и высота видового порта в пикселях; x, y - координаты нижнего левого угла видового порта в окне OpenGL; [a] - целая часть числа a.
Информацию об ОСК можно извлечь, вызвав fglGetIntegerv с параметром GL_VIEWPORT или GL_MAX_VIEWPORT_DIMS.
При вызове fglViewport возникнет ошибка:
Пример:
call fglViewport(10, 5, 300, 200)
Этот вызов задает видовой порт размером в 300×200 пикселей, начало координат которого отстоит от нижнего левого угла окна OpenGL по оси x на 10 пикселей и по оси y - на 5.
Изначально объекты задаются в МСК и имеют присущие им геометрические размеры. Ориентация осей координат в МСК приведена на рис. 3, а.
Рис. 3. Куб в мировой и оконной системах координат: а - куб в пространстве; б - ортографическая проекция; в - изометрия
Базис МСК с такой ориентацией осей является правосторонним
В OpenGL точка задается в однородных координатах [2], то есть так, как это принято в проективной геометрии. Для описания точки используется четверка координат (x, y, z, w). Заметим, что это позволяет применить единый матричный подход ко всем видам аффинных преобразований.
Переход из мировой в оконную систему координат можно выполнить, придерживаясь такой последовательности:
call fglClear(gl_color_buffer_bit)
Проецирование - это отображение трехмерного объекта на плоскость при помощи прямых, проходящих через характерные точки объекта, например через его вершины.
Если все проецирующие прямые выходят из одной точки, то проецирование называется центральным, или перспективным, а точка, из которой выходят лучи, называется центром проецирования (рис. 4).
Рис. 4. Центральное проецирование
Плоскость, на которую выполняется проецирование, называется плоскостью проекций. В машинной графике у нее есть иное название - картинная плоскость.
Наибольший угол между проецирующими лучами называется углом зрения. Чтобы получить наиболее выразительную перспективную проекцию, угол зрения следует выбирать в диапазоне от 20° до 40°.
Если же центр проецирования находится на бесконечно большом расстоянии от плоскости проекций, проецирующие лучи параллельны друг другу, и поэтому проецирование называется параллельным.
Если проецирующие лучи вдобавок перпендикулярны плоскости проекций, то проецирование называется прямоугольным, или ортографическим.
В черчении при создании чертежей объектов используются их ортографические (прямоугольные) проекции (ОП) на три плоскости: фронтальную, горизонтальную и профильную (рис. 5).
Рис. 5. Ортографическое (прямоугольное) проецирование
Для получения ОП в OpenGL текущая матрица преобразования координат умножается на матрицу ортографического проецирования, что обеспечивается следующим вызовом:
CALL fglOrtho(left, right, bottom, top, near, far)
Фактически выполнение fglOrtho устанавливает в СКН область видимости графических данных (рис. 6).
Рис. 6. Задание трехмерной области видимости
left, right, bottom, top, near и far - координаты углов параллелепипеда, ограничивающего область видимости. Все параметры имеют тип REAL(8).
Используется следующая матрица ортографического проецирования:
где
После выполнения преобразования проецирования формируется трехмерная область видимости с ортогональным базисом Sx Sy Sz:
Координаты центра области видимости:
Формируемый базис является левосторонним (в отличие от базиса МСК, который является правосторонним); после преобразования ортографического проецирования координаты любых точек внутри преобразованной трехмерной области видимости находятся в диапазоне от -1 до 1. То есть преобразованная область видимости представляет собой куб со стороной, равной двум.
Напомним, что координаты, полученные в результате преобразования проецирования, называются нормированными.
При работе с плоскими изображениями окно вывода в МСК можно также задать командой
CALL fgluOrtho2D(left, right, bottom, top)
Действие команды аналогично вызову
CALL fglOrtho(left, right, bottom, top, -1, 1)
Для полноты восприятия 3D-объекта его располагают его перед одной из плоскостей проекций так, чтобы он был виден сразу с трех сторон: спереди, сверху и слева. А затем выполняется параллельное проецирование объекта на выбранную плоскость проекций (рис. 7).
Рис. 7. Аксонометрическая проекция 3D-объекта
Если проецирующие лучи перпендикулярны плоскости проекций, то проецирование называется аксонометрическим, а плоскость проекций - аксонометрической плоскостью проекций. В противном случае мы имеем дело с косоугольным проецированием.
Свяжем картинную плоскость, как это принято в машинной графике, с системой координат x0y. Положительное направление оси z ориентировано от находящегося перед картинной плоскостью наблюдателя.
Различают три вида аксонометрического проецирования: изометрию, диметрию и триметрию.
Изометрия получается, если в СКН объект повернуть на угол ψ вокруг оси y, затем выполнить его поворот на угол φ вокруг оси x, а вслед выполнить параллельное проецирование объекта на плоскость проекций x0y. Оба поворота выполняются против часовой стрелки. Углы поворота определяются из соотношений
sin2φ = 1 / 3; sin2ψ = 1/ 2.
Матрица изометрического проецирования isoplane, получаемая в результате умножения матриц поворота вокруг осей x и y, может быть задана следующим образом:
real(4), dimension(4, 4) :: isoplane
sf = sqrt(1.0 / 3.0); cf = sqrt(2.0 / 3.0) ! sinφ и cosφ
sp = sqrt(1.0 / 2.0); cp = sqrt(1.0 / 2.0) ! sinψ и cosψ
! isoplane - матрица изометрического проецирования
isoplane = reshape((/ cp, sf * sp, 0.0, 0.0, &
0.0, cp, 0.0, 0.0, &
sp, -sf * cp, 0.0, 0.0, &
0.0, 0.0, 0.0, 1.0 /), &
shape = (/ 4, 4 /))
. . .
call fglMatrixMode(gl_projection) ! Текущей является матрица проецирования
call fglLoadIdentity( )
call fglLoadMatrixf(loc(isoplane)) ! Матрица isoplane загружена как матрица проецирования
Однако изометрия в чистом виде будет получена лишь в том случае, если затем процедурой fglOrtho задается кубическая, а не в виде произвольного прямоугольного параллелепипеда, область видимости, например, такая:
call fglOrtho( dble(-200.0), dble(300.0), & ! Задаем кубическую область видимости
dble(-200.0), dble(300.0), & ! с длиной ребра куба равной 500.0
dble(-200.0), dble(300.0))
!
! Вывод изометрической проекции куба
. . .
Результирующая матрица преобразований из мировых в нормированные координаты равна произведению M×I×O, где М - видовая матрица, I - матрица изометрического проецирования, О - матрица ортографического проецирования, задающая кубическую область видимости. В свою очередь, видовая матрица M может быть произведением матриц, отвечающих за аффинные преобразования.
Изометрическая проекция куба, приведенного на рис. 3, а, отображена на рис. 3, в.
Центральное (перспективное) проецирование можно интерпретировать так: первоначально объект подвергается деформации, а затем выполняется его ортографическое проецирование.
Рассмотрим куб, приведенный на рис. 3, а. Деформируем его так, чтобы продолжения его ребер, параллельных оси z, сходились в точке, расположенной на оси z и называемой точкой схода (рис. 8, а).
Рис. 8. Перспективные проекции куба: а - одноточечная; б - двухточечная
Тогда мы получим одноточечную перспективную проекцию куба. Если же добавить еще одну точку схода, но теперь уже на оси x (рис. 8.10, б), то будет получена двухточечная проекция куба. Трехточечная проекция получается при наличии третьей точки схода.
В OpenGL текущая матрица преобразования координат умножается на матрицу одноточечного перспективного проецирования в результате вызова
CALL fglFrustum(left, right, bottom, top, near, far)
Все параметры имеют тип REAL(8). Геометрический смысл параметров такой же, как и у одноименных параметров fglOrtho, с той лишь разницей, что near и far должны быть больше нуля. Команда создает матрицу
Второй способ задать перспективное преобразование - это использовать команду
CALL fgluPerspective(fovy, aspect, znear, zfar)
fovy - область видимости (в градусах) в направлении оси y (tg(fovy / 2) = top / near).
aspect - параметр, задающий область видимости в направлении оси x. Задается как отношение ширины (x) и высоты (y) области видимости.
Смысл znear и zfar такой же, что и параметров near и far команды fglFrustum. Значения znear и zfar всегда положительны и zfar > znear.
Вызов fgluPerspective равнозначен вызову fglFrustum с параметрами
left = -right, bottom = -top, tg(fovy / 2) = top / near, aspect = right / top.
Перспективное преобразование задается в СКН. Величина отношения aspect должна соответствовать заданному видовому порту; например, если aspect = 2, то отношение x и y размеров видового порта тоже следует задать равным двум. Это обеспечит вывод изображения без искажений.
В результате выполнения fgluPerspective текущая матрица преобразования координат умножается на матрицу перспективного преобразования, задаваемую этой командой. Чтобы заменить существующую матрицу на матрицу перспективного преобразования, сгенерированную fgluPerspective, следует прежде выполнить fglLoadIdentity.
Задача 1. Вывести куб, применив первоначально fglFrustum, а затем fgluPerspective.
program cubeProjections ! Выполняемый файл создается
use opengl ! как консоль-приложение
use msfwin
integer(4) :: result, w = 300, h = 200
call fauxInitDisplayMode(ior(aux_single, aux_rgb))
call fauxInitPosition(0, 0, w, h)
result = fauxInitWindow("Перспективная проекция куба"C)
call fglClearColor(0.5, 0.5, 0.5, 0.0) ! Цвет фона - темно-серый
call fglShadeModel(gl_flat) ! Вывод без интерполяции цветов
call fglPolygonMode(gl_front_and_back, gl_line)
call fglLineWidth(2.0) ! Задаем ширину линии - ребра куба
call fglMatrixMode(gl_modelview) ! Текущей является видовая матрица
call fglTranslatef(0.0, 0.0, -100.0) ! Переместим объект в области видимости
do i = 1, 2 ! Цикл задания команд fglFrustum и fgluPerspective
call fglClear(gl_color_buffer_bit) ! Заполняем окно цветом фона
call fglMatrixMode(gl_projection) ! Текущей стала матрица проецирования
call fglLoadIdentity( ) ! Инициализация матрицы проецирования
if(i == 1) then ! fglFrustum задает перспективное проецирование
call fglFrustum(dble(-200.0), dble(300.0), &
dble(-200.0), dble(300.0), &
dble(50.0), dble(300.0))
else ! Теперь зададим перспективное
call fgluPerspective(161.1, 1.0, 50.0, 300.0) ! проецирование командой fgluPerspective
end if
call cube( ) ! Вывод куба
call sleep(2500) ! Задержка на 2500 мс
end do
call fauxMainLoop(null) ! Оставим окно открытым
contains
subroutine cube( )
use opengl
call fglBegin(gl_quad_strip) ! Вывод боковых граней
call fglColor3f(0.0, 1.0, 1.0) ! Бирюзовый цвет
call fglVertex3f(0.0, 0.0, 100.0) ! 1 - номер вершины куба
call fglVertex3f(0.0, 100.0, 100.0) ! 2
call fglVertex3f(100.0, 0.0, 100.0) ! 3
call fglVertex3f(100.0, 100.0, 100.0) ! 4
call fglVertex3f(100.0, 0.0, 0.0) ! 5
call fglVertex3f(100.0, 100.0, 0.0) ! 6
call fglVertex3f(0.0, 0.0, 0.0) ! 7
call fglVertex3f(0.0, 100.0, 0.0) ! 8
call fglVertex3f(0.0, 0.0, 100.0) ! 1
call fglVertex3f(0.0, 100.0, 100.0) ! 2
call fglEnd( ) ! Заканчиваем вывод боковых граней
call fglBegin(gl_quads) ! Вывод нижней и верхней граней
call fglColor3f(1.0, 0.0, 1.0) ! Фиолетовый цвет для нижней грани
call fglVertex3f(0.0, 0.0, 0.0) ! 1 - номер вершины куба
call fglVertex3f(100.0, 0.0, 0.0) ! 3
call fglVertex3f(100.0, 0.0, 100.0) ! 5
call fglVertex3f(0.0, 0.0, 100.0) ! 7
call fglColor3f(1.0, 0.0, 0.0) ! Красный цвет для верхней грани
call fglVertex3f(0.0, 100.0, 0.0) ! 2
call fglVertex3f(100.0, 100.0, 0.0) ! 4
call fglVertex3f(100.0, 100.0, 100.0) ! 6
call fglVertex3f(0.0, 100.0, 100.0) ! 8
call fglEnd( ) ! Заканчиваем вывод верхней грани
call fglPointSize(8.0) ! Размер точки
call fglBegin(gl_points) ! Вывод начала координат
call fglColor3f(1.0, 1.0, 0.0) ! Желтый цвет - смесь красного и зеленого
call fglVertex2f(0.0, 0.0)
call fglEnd( ) ! Заканчиваем вывод начала координат
call fglFlush( ) ! Отображаем примитивы на экране
end subroutine cube
end program cubeProjections ! Результат приведен на рис. 9
Рис. 9. Перспективные проекции куба: а - преобразование fglFrustum; б - преобразование fgluPerspective
Поскольку в fglFrustum параметры znear и zfar должны иметь положительный знак, то заданный подпрограммой cube куб не попадает в устанавливаемую fglFrustum область видимости. Перемещение куба в эту область выполняется fglTranslatef, вызывающей его сдвиг на -100 вдоль оси z. Величина смещения должна превышать znear. В результате выполнения fglTranslatef текущая матрица преобразования координат, а таковой в примере является видовая матрица, умножается на матрицу переноса, задаваемую fglTranslatef.
Задача 2. Вывести двухточечную перспективную проекцию куба.
OpenGL не содержит команд двухточечного проецирования. Однако можно создать, а затем загрузить матрицу преобразования двухточечного или трехточечного проецирования и использовать ее, так же как и в случае изометрического проецирования, совместно с командой fglOrtho, задающей, например, кубическую область видимости.
Матрицы двухточечного и трехточечного преобразований проецирования имеют вид:
где a, b и c - координаты главных точек схода, размещенных соответственно на осях x, y и z (см. рис. 9).
В нижеследующей программе зададим a = c = -2.0. Чтобы разместить главные точки схода на осях координат (в нашем случае на осях x и z), центр кубической области видимости (задается fglOrtho) следует расположить в начале координат СКН.
program cube2Points ! Выполняемый файл создается
use opengl ! как консоль-приложение
use msfwin
integer(4) :: result , w = 400, h = 400
real(4), dimension(4, 4) :: perspective2 ! Матрица двухточечного проецирования
perspective2 = reshape((/ 1.0, 0.0, 0.0, 1.0 / 2.0, &
0.0, 1.0, 0.0, 0.0, &
0.0, 0.0, 1.0, 1.0 / 2.0, &
0.0, 0.0, 0.0, 1.0 /), &
shape = (/ 4, 4 /))
call fauxInitDisplayMode(ior(aux_single, aux_rgb))
call fauxInitPosition(0, 0, w, h)
result = fauxInitWindow("Двухточечная перспективная проекция куба"C)
call fglClearColor(0.5, 0.5, 0.5, 0.0) ! Цвет фона - темно-серый
call fglShadeModel(gl_flat) ! Вывод без интерполяции цветов
call fglPolygonMode(gl_front_and_back, gl_line)
call fglClear(gl_color_buffer_bit) ! Заполняем окно цветом фона
call fglMatrixMode(gl_projection) ! Текущей является матрица проецирования
call fglLoadMatrixf(loc(perspective2)) ! Преобразование двухточечного проецирования
call fglOrtho( dble(-200.0), dble(200.0), & ! Кубическая область видимости
dble(-200.0), dble(200.0), & ! с центром в начале СКН
dble(-200.0), dble(200.0))
call cube( ) ! Вывод куба
call fauxMainLoop(null) ! Оставим окно открытым
contains
subroutine cube( )
! Текст подпрограммы cube см. выше
end subroutine cube
end program cube2Points ! Результат приведен на рис. 10
Рис. 10. Двухточечная перспективная проекция куба
При проецировании 3D-объекта на плоскость можно дополнительно задать:
Все это выполняется имитирующей камеру командой
CALL fgluLookAt(eyex, eyey, eyez, centerx, centery, centerz, upx, upy, upz)
eyex, eyey, eyez - координаты расположения наблюдателя (точки, из которой выполняется наблюдение).
centerx, centery, centerz - центр сцены.
upx, upy, upz - направление вектора, вдоль которого в видовом порте ориентируется ось y.
Тип всех параметров - REAL(8).
Команда fgluLookAt предназначена для формирования видовой матрицы. Создаваемая матрица переводит начало координат в точку наблюдения, а наблюдаемую точку на отрицательную часть оси z, выполняя это так, что при использовании стандартной матрицы проецирования центр сцены проецируется в центр видового порта; направление, заданное вектором (upx, upy, upz), после проецирования совпадает с положительным направлением оси y. Причем вектор (upx, upy, upz) не должен быть параллелен линии, проведенной от точки наблюдения (eyex, eyey, eyez) до наблюдаемой точки (centerx, centery, centerz).
В результате выполнения fgluLookAt формируется матрица, на которую умножается текущая матрица преобразования координат. Текущей следует установить видовую матрицу.
Пример. Вывести подпрограммой cube куб, разместив его центр в центре видового порта и ориентировав его ось вдоль вектора (1, 2, 1).
program cubeLookAt ! Выполняемый файл создается как консоль-приложение
use opengl
use msfwin
integer(4) :: result
real(4) :: sf, cf, sp, cp
real(4), dimension(4, 4) :: isoplane
sf = sqrt(1.0 / 3.0); cf = sqrt(2.0 / 3.0); sp = sqrt(1.0 / 2.0); cp = sqrt(1.0 / 2.0)
! isoplane - матрица изометрического проецирования
isoplane = reshape((/ cp, sf * sp, 0.0, 0.0, &
0.0, cp, 0.0, 0.0, &
sp, -sf * cp, 0.0, 0.0, &
0.0, 0.0, 0.0, 1.0 /), &
shape = (/ 4, 4 /))
call fauxInitDisplayMode(ior(aux_single, aux_rgb))
call fauxInitPosition(0, 0, 500, 500)
result = fauxInitWindow("Изменение ориентации изометрической проекции"C)
call fglClearColor(1.0, 1.0, 1.0, 0.0) ! Цвет фона - ярко-белый
call fglClear(gl_color_buffer_bit) ! Заполняем окно цветом фона
call fglShadeModel(gl_flat) ! Вывод без интерполяции цветов
call fglPolygonMode(gl_front_and_back, gl_line)
call fglMatrixMode(gl_modelview) ! Текущей является видовая матрица
call fgluLookAt( 50.0_8, 50.0_8, 50.0_8, & ! Центр наблюдения
0.0_8, 0.0_8, -30.0_8, & ! Точка наблюдения
1.0_8, 2.0_8, 1.0_8) ! Ориентация оси y
call fglMatrixMode(gl_projection) ! Текущей является матрица проецирования
call fglLoadMatrixf(loc(isoplane)) ! Матрица isoplane загружена как матрица проецирования
call fglOrtho( dble(-300.0), dble(300.0), & ! Кубическая область видимости
dble(-300.0), dble(300.0), &
dble(-300.0), dble(300.0))
call cube( ) ! Вывод куба
call fauxMainLoop(null) ! Оставим окно открытым
contains
subroutine cube( )
! Текст подпрограммы cube см. выше
end subroutine cube
end program cubeLookAt ! Результат приведен на рис. 11
Рис. 11. Взгляд из камеры
Аффинные преобразования координат (поворот, перемещение и масштабирование) выполняются над объектом в МСК. Преобразования выполняются в результате умножения координат точек, задающих вершины объекта, на видовую матрицу, имеющую вид:
Иными словами, элементы видовой матрицы, как, впрочем, и любой иной матрицы OpenGL, размещаются в памяти по столбцам - так, как это принято в Фортране.
Видовую матрицу можно изменить. Однако прежде ее необходимо сделать текущей. Это происходит после вызова
call fglMatrixMode(gl_modelview) ! Текущей стала видовая матрица
В свою очередь, видовая матрица может быть:
call fglLoadIdentity( )
real(4), dimension(4, 4) :: matr
matr = reshape((/ 0.3, -0.5, 0.1, 0.0, &
0.2, -0.4, 0.2, 0.0, &
0.1, -0.3, 0.3, 0.0, &
0.0, 0.0, 0.0, 1.0 /), &
shape = (/ 4, 4 /))
call fglMatrixMode(gl_modelview) ! Текущей стала видовая матрица
call fglLoadMatrixf(loc(matr)) ! Матрица matr загружена как видовая матрица
real(4), dimension(4, 4) :: rx, ry
sf = sqrt(1.0 / 3.0); cf = sqrt(2.0 / 3.0)
sp = sqrt(1.0 / 2.0); cp = sqrt(1.0 / 2.0)
rx = reshape((/ 1.0, 0.0, 0.0, 0.0, &
0.0, cf, -sf, 0.0, &
0.0, sf, cf, 0.0, &
0.0, 0.0, 0.0, 1.0 /), &
shape = (/ 4, 4 /))
ry = reshape((/ cp, 0.0, sp, 0.0, &
0.0, 1.0, 0.0, 0.0, &
-sp, 0.0, cp, 0.0, &
0.0, 0.0, 0.0, 1.0 /), &
shape = (/ 4, 4 /))
. . .
call fglMatrixMode(gl_modelview) ! Теперь видовая матрица является текущей
call fglMultMatrixf(loc(rx)) ! Умножаем текущую матрицу на матрицу rx
call fglMultMatrixf(loc(ry)) ! Умножаем текущую матрицу на матрицу ry
call fglRotatef(ay, 0.0, 1.0, 0.0) ! Поворот на угол ay против часовой стрелки
Например, умножение на матрицу
обеспечит вызов
call fglScalef(0.5, 0.5, 0.7) ! Масштабирование объекта
Например, умножение на матрицу
вызовет перенос объекта на 10 единиц вдоль оси x:
call fglTranslatef(10.0, -30.5, 20.7) ! Перенос объекта вдоль оси x
Задача. Задать в МСК куб и отобразить его на экране в различных ориентациях. Ориентацию куба изменять в результате его двух последовательных поворотов на заданный угол: первый поворот выполнять вокруг оси x, а второй - вокруг оси y. Первоначально куб ориентирован так, как это показано на рис. 3, а. Там же приведена и нумерация его вершин.
program cubeRotate ! Выполняемый файл создается
use opengl ! как консоль-приложение
use msfwin
integer(4) :: result, w = 500, h = 500
call fauxInitDisplayMode(ior(aux_single, aux_rgb))
call fauxInitPosition(0, 0, w, h)
result = fauxInitWindow("Вращение куба"C)
call fglPolygonMode(gl_front_and_back, gl_line) ! Выводим ребра куба
call fglClearColor(0.5, 0.5, 0.5, 0.0) ! Цвет фона - темно-серый
call fglShadeModel(gl_flat) ! Вывод без интерполяции цветов
call fglLineWidth(2.0) ! Толщина линий - 2 пикселя
call fglMatrixMode(gl_projection) ! Текущей стала матрица проецирования
call fglLoadIdentity( ) ! Инициализация матрицы проецирования
call fglOrtho(dble(-200.0), dble(300.0), & ! Задаем область видимости (матрицу
dble(-200.0), dble(300.0), & ! ортографического проецирования)
dble(-300.0), dble(300.0))
call fglMatrixMode(gl_modelview) ! Текущей стала видовая матрица
do i = 0, 90, 10 ! i - угол поворота против часовой стрелки
call fglClear(gl_color_buffer_bit) ! Заполняем окно цветом фона
call fglLoadIdentity( ) ! Видовая матрица равна матрице идентичности
call fglRotatef(real(i), 1.0, 0.0, 0.0) ! Вращение против часовой стрелки вокруг оси x
call fglRotatef(real(i), 0.0, 1.0, 0.0) ! Вращение против часовой стрелки вокруг оси y
!
! Вывод куба. При выводе координаты куба умножаются на видовую матрицу
! и матрицу проецирования, а затем преобразовываются в оконные координаты
call cube( )
call sleep(2500) ! Задержка на 2500 мс
end do
call fauxMainLoop(null) ! Оставим окно открытым
end program cubeRotate
subroutine cube( )
! Текст подпрограммы cube см. выше
end subroutine cube ! Результаты приведены на рис. 12
Рис. 12. Куб после поворотов вокруг осей x и y на заданный угол: а -30°; б - 70°
Если же после выполнения преобразований в МСК часть куба не попадет в объем вывода, то она будет отсечена. Причем в местах пересечения ребер куба с гранями области видимости будут созданы новые вершины и сформированы и выведены линии пересечения граней куба с гранями области видимости. Так, если задать область видимости
call fglOrtho(dble(-100.0), dble(200.0), & ! Задаем область видимости
dble(-100.0), dble(200.0), &
dble(-100.0), dble(200.0))
и выполнить в МСК поворот куба вокруг осей x и y на 45°, то получится приведенное на рис. 13 изображение, содержащее треугольную грань, сформированную в результате решения задачи отсечения.
Рис. 13. Дополнительная треугольная грань - результат отсечения
В приведенной выше программе cubeRotate выполняется ортографическое проецирование, что обеспечивается fglOrtho. Пример ортографической проекции куба при углах поворота вокруг осей координат, равных нулю, приведен на рис. 3, б. На практике, однако, вывод 3D-объектов выполняется, как правило, с применением либо аксонометрического, либо перспективного проецирования.