Министерство образования Российской Федерации НОВОСИБИРСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ
___________________...
15 downloads
205 Views
516KB Size
Report
This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Report copyright / DMCA form
Министерство образования Российской Федерации НОВОСИБИРСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ
____________________________________________________________________
ИНТЕРАКТИВНАЯ КОМПЬЮТЕРНАЯ ГРАФИКА Методические указания к лабораторным работам и курсовому проектированию для студентов 3 и 5 курса ФПМИ
Новосибирск 2005
Составители:
к.т.н, доцент к.т.н., доцент д.т.н., проф.
А.В.Чернышев М.Э.Рояк Г.М.Тригубович
Рецензент:
к.т.н., доцент М.Г.Персова
Работа подготовлена на кафедре прикладной математики НГТУ
© Новосибирский государственный технический университет, 2005
ЛАБОРАТОРНАЯ РАБОТА №1 ВВЕДЕНИЕ В ПРОГРАММИРОВАНИЕ С ИСПОЛЬЗОВАНИЕМ OPENGL Цель работы. Ознакомиться с основами использования библиотеки OpenGL. Теоретическая часть. OpenGL является одним из самых популярных прикладных программных интерфейсов (API – Application Programming Interface) для разработки приложений в области двумерной и трехмерной графики. Графический стандарт OpenGL является современным стандартом компьютерной графики. Работа с библиотекой построена по принципу ''клиент-сервер''. Приложение вызывает команды, а библиотека занимается их обработкой. OpenGL имеет большие функциональные возможности в построении реалистичных изображений. Синтаксис команд Все команды (процедуры и функции) библиотеки GL начинаются с префикса gl, все константы – с префикса GL_. Кроме того, в имена команд входят суффиксы, несущие информацию о числе и типе передаваемых параметров. В OpenGL полное имя команды имеет вид: type glCommand_name[1 2 3 4][b s i f d ub us ui][v] (type1 arg1,…,typeN argN)
Имя состоит из нескольких частей: gl имя библиотеки, в которой описана эта функция. Command_name имя команды (процедуры или функции) [1 2 3 4] число аргументов команды [b s i f d ub us ui] тип аргумента: b – GLbyte (аналог char), i – Glint (аналог int), f – GLfloat (аналог float) и т.д. [v] в параметрах используется указатель на массив значений Пример приложения Типичная программа, использующая OpenGL, начинается с создания контекста OpenGL и ассоциирования его с окном, в котором будет происходить отображение. Далее программист может свободно использовать команды и операции OpenGL API. Ниже приведен текст небольшой программы, написанной с использованием библиотеки GLUT. #include <stdlib.h> /* подключаем библиотеку GLUT */ #include /* начальная ширина и высота окна */ GLint Width = 512, Height = 512; const int CubeSize = 200; /* размер куба */
1
/* эта функция управляет всем выводом на экран */ void Display(void) { int left, right, top, bottom; left = (Width - CubeSize) / 2; right = left + CubeSize; bottom = (Height - CubeSize) / 2; top = bottom + CubeSize; glClearColor(0, 0, 0, 1); glClear(GL_COLOR_BUFFER_BIT); glColor3ub(255,0,0); glBegin(GL_QUADS); glVertex2f(left,bottom); glVertex2f(left,top); glVertex2f(right,top); glVertex2f(right,bottom); glEnd(); glFinish(); } /* Функция вызывается при изменении размеров окна */ void Reshape(GLint w, GLint h) { Width = w; Height = h; /* устанавливаем размеры области отображения */ glViewport(0, 0, w, h); /* ортографическая проекция */ glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, w, 0, h, -1.0, 1.0); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } /* Функция обрабатывает сообщения от клавиатуры */ void Keyboard( unsigned char key, int x, int y ) {#define ESCAPE '\033' if( key == ESCAPE ) exit(0); } /* головная программа */ main(int argc, char *argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGB); glutInitWindowSize(Width, Height); glutCreateWindow("Red square example"); glutDisplayFunc(Display); glutReshapeFunc(Reshape); glutKeyboardFunc(Keyboard); glutMainLoop(); }
Библиотека GLUT поддерживает взаимодействие с пользователем с помощью так называемых функций обратного вызова (callback function). Если пользователь подвинул мышь, нажал на кнопку клавиатуры или изменил размеры окна, 2
происходит событие и вызывается соответствующая функция пользователя – обработчик событий. Рассмотрим функцию main данного примера. Она состоит из трех частей – инициализации окна, в котором будет рисовать OpenGL, настройки функций обратного вызова и главного цикла обработки событий. Функция glutInit (&argc, argv) производит начальную инициализацию самой библиотеки GLUT. Команда glutInitDisplayMode (GLUT_RGB) инициализирует буфер кадра и устанавливает полноцветный (непалитровый) режим RGB. glutInitWindowSize (Width, Height) используется для задания начальных размеров окна. Наконец, glutCreateWindow ("Red square example") задает заголовок окна и отображает само окно на экране. Команды glutDisplayFunc (Display), glutReshapeFunc (Reshape), glutKeyboardFunc (Keyboard) регистрируют функции Display(), Reshape() и Keyboard() как функции, которые будут вызваны, соответственно, при перерисовке окна, изменении размеров окна, нажатии клавиши на клавиатуре. Контроль всех событий и вызов нужных функций происходит внутри цикла обработки сообщений в функции glutMainLoop (). Все вызовы команд OpenGL происходят в обработчиках событий. Функция Display отвечает за рисование на экране и состоит из трех шагов: 1. очистка буферов OpenGL; 2. установка положения наблюдателя; 3. преобразование и рисование геометрических объектов. Очистка буферов производится с помощью команд: void glClearColor ( clampf r, clampf g, clampf b, clampf a ) void glClear (bitfield buf) Команда glClearColor устанавливает цвет фона. Команда glClear очищает буферы, а параметр buf определяет буферы,
которые нужно очистить. Типичная программа вызывает команду glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
для очистки буферов цвета и глубины. Каждый рисуемый объект должен быть представлен в виде набора примитивов OpenGL. Примитивы задаются набором вершин. Вершина определяет точку, конец отрезка, угол многоугольника и т.д. С каждой вершиной ассоциируются ее атрибуты. В число основных атрибутов входят положение вершины в пространстве, цвет вершины и вектор нормали. Положение вершины задают функции: void glVertex [2 3 4][s i f d] (type coords) void glVertex[2 3 4][s i f d]v (type *coords)
OpenGL работает с однородными координатами (х, у, z, w). Если координата z не задана, то она считается равной нулю. Если координата w не задана, то она считается равной единице. Для ассоциации с вершинами цветов, нормалей и текстурных координат используются текущие значения соответствующих данных. 3
Для задания текущего цвета вершины используются команды: void glColor [3 4][b s i f] (GLtype components) void glColor[3 4][b s i f]v (GLtype components)
Вершинам можно назначать различные цвета, и, если включен соответствующий режим, то будет проводиться линейная интерполяция цветов по поверхности примитива. Для управления режимом интерполяции используется команда void glShadeModel (GLenum
mode)
вызов которой с параметром GL_SMOOTH включает интерполяцию (установка по умолчанию), а с GL_FLAT – отключает. Определить нормаль в вершине можно, используя команды void glNormal3[b s i f d] (type coords) void glNormal3[b s i f d]v (type coords)
Для правильного расчета освещения необходимо, чтобы вектор нормали имел единичную длину. Командой glEnable(GL_NORMALIZE) можно включить режим, при котором задаваемые нормали будут нормироваться автоматически. Операторные скобки glBegin / glEnd Для задания геометрических примитивов необходимо выделить набор вершин, определяющих этот объект. Для этого служат процедуры glBegin() и glEnd(). void glBegin (GLenum mode) void glEnd (void)
Параметр mode определяет тип примитива, который задается внутри блока, задаваемого процедурами glBegin() и glEnd(), и может принимать следующие значения: GL_POINTS каждая вершина задает координаты некоторой точки. GL_LINES каждая отдельная пара вершин определяет отрезок. GL_LINE_STRIP незамкнутая ломаная. GL_LINE_LOOP замкнутая ломаная. GL_TRIANGLES каждые отдельные три вершины определяют треугольник. GL_TRIANGLE_STRIP каждая следующая вершина задает треугольник вместе с двумя предыдущими. GL_TRIANGLE_FAN треугольники задаются первой вершиной и каждой следующей парой вершин. GL_QUADS каждая четверка вершин определяет четырехугольник. GL_QUAD_STRIP четырехугольник с номером n определяется вершинами с номерами 2n-1, 2n, 2n+2, 2n+1. GL_POLYGON вершины определяют выпуклый многоугольник. Внутри блока можно вызывать только следующие функции: glVertex, glColor, glIndex, glNormal, glTexCoord, glEvalCoord, glEvalPoint, glMaterial. Чтобы нарисовать треугольник с разными цветами в вершинах, достаточно написать: GLfloat BlueCol[3] = {0,0,1}; glBegin(GL_TRIANGLES); glColor3f(1.0, 0.0, 0.0); /* красный */ glVertex3f(0.0, 0.0, 0.0); glColor3ub(0,255,0); /* зеленый */
4
glVertex3f(1.0, 0.0, 0.0); glColor3fv(BlueCol); /* синий */ glVertex3f(1.0, 1.0, 0.0); glEnd();
Варианты заданий. Часть 1. Реализовать простейший графический редактор, позволяющий с помощью мыши рисовать: а) цветные точки (размер и цвет точки задается, например, нажатием клавиш ‘1’-‘9’), б) цветные ломаные (ломаная заканчивается, например, при нажатии Enter; цвет задается для каждой ломаной), в) цветные ломаные (цвет задается для каждой точки ломаной), г) цветные многоугольники (задается цвет каждого многоугольника), д) цветные многоугольники (задается цвет каждой вершины). Часть 2. Реализовать простейший графический редактор, рисующий многоугольники из предопределенного набора. Мышью задается положение многоугольника. Предусмотреть возможность выбора цвета. При рисовании использовать смешение цветов посредством логических операций: а) and и not and, б) or и not or, в) xor и not xor. Контрольные вопросы и задания. 1. Архитектура библиотек OpenGL и организация конвейера. 2. Категории команд (функций) библиотеки. 3. Что такое функция обратного вызова и как функции обратного вызова могут быть использованы для работы с OpenGL? 4. Для чего нужна функция обновления изображения и что она делает? 5. Примитивы и атрибуты в OpenGL. 6. Что такое операторные скобки и для чего они используются в OpenGL? ЛАБОРАТОРНАЯ РАБОТА №2 ЗАДАНИЕ ПОЛИГОНАЛЬНЫХ МОДЕЛЕЙ ОБЪЕКТОВ ТРЕХМЕРНАЯ ВИЗУАЛИЗАЦИЯ С ИСПОЛЬЗОВАНИЕМ OPENGL Цель работы. Ознакомиться с основным способом задания полигональных моделей – методом тиражирования сечений; ознакомиться со средствами трехмерной визуализации в OpenGL (источники света, свойства материалов, текстуры). Теоретическая часть. Для получения двумерного изображения трехмерного объекта необходимо осуществить преобразование системы мировых координат в систему видовых координат. 5
В целом, для отображения трехмерных объектов сцены в окно приложения используется последовательность, показанная на рисунке:
Мировые координаты Модельно-видовая матрица
Модельно-видовое преобразование Видовые координаты
Преобразование проекции и нормализация
Матрица проекции
Нормализованные координаты
Преобразование к области вывода
Параметры области вывода (glViewport)
Оконные координаты Модельно-видовые преобразования К модельно-видовым преобразованиям относят перенос, поворот и изменение масштаба. Для проведения этих операций достаточно умножить на соответствующую матрицу каждую вершину объекта и получить измененные координаты этой вершины: (x’, y’, z’, 1)T = M * (x, y, z, 1)T, где M – матрица модельно-видового преобразования. Перспективное преобразование и проектирование производится аналогично. Сама матрица может быть создана с помощью следующих команд: void glTranslate [f d] (GLtype dx, GLtype dy, GLtype dz) void glRotate [f d] (GLtype angle, GLtype Ux, GLtype Uy, GLtype Uz) void glScale [f d] (GLtype Sx, GLtype Sy, GLtype Sz)
⎡1 0 0 dx ⎤ ⎢0 1 0 dy ⎥ ⎥ glTranlsate*() производит перенос объекта. M Translate = ⎢ ⎢0 0 1 dz ⎥ ⎢ ⎥ ⎣0 0 0 1 ⎦ glRotate*() производит поворот объекта против часовой стрелки на угол angle (измеряется в градусах) вокруг вектора (Ux,Uy,Uz). ⎡ c + (1 − c)u x2 (1 − c)u yu x − su z (1 − c)u z u x − su y 0 ⎤ ⎢ ⎥ 2 (1 c ) u u su c (1 c ) u (1 c ) u u su 0 − + + − − − x y z y z y x ⎥ M Rotate = ⎢ 2 ⎢ (1 − c)u xu z − su y (1 − c )u y u z + su x c + (1 − c)u z 0⎥ ⎢ ⎥ 0 0 0 1 ⎣ ⎦ glScale*() производит масштабирование объекта вдоль вектора (Sx,Sy,Sz).
6
⎡ Sx 0 0 0 ⎤ ⎢ 0 Sy 0 0 ⎥ ⎥ M Scale = ⎢ ⎢ 0 0 Sz 0 ⎥ ⎢ ⎥ ⎣ 0 0 0 1⎦ Все эти преобразования изменяют текущую матрицу, а поэтому применяются к примитивам, которые определяются позже.
Работа с матрицами В OpenGL предусмотрены три типа матриц – видовая, проекций и текстуры. void glMatrixMode (Glenum mode);
Определение текущей матрицы, параметр mode может принимать следующие значения: GL_MODELVIEW – операции применяются к видовой матрице; GL_PROJECTION – операции применяются к матрице проекций; GL_TEXTURE – операции применяются к матрице текстур. void glLoadIdentity();
Замена текущей матрицы на единичную. В OpenGL существуют команды для задания ортографической (параллельной) и перспективной проекций. void glOrtho (Gldouble left, Gldouble right, Gldouble bottom, Gldouble top, Gldouble near, Gldouble far);
Установка матрицы параллельной проекции и объема видимости (рис.1). 2 ⎛ ⎞ 0 0 tx ⎟ right + left ⎜ right − left tx = − ⎜ ⎟ right − left 2 ⎜ ⎟ 0 0 ty ⎟ top + bottom ⎜ top − bottom , ty = − ⎜ ⎟ top − bottom ⎜ ⎟ −2 0 0 tz ⎟ far + near ⎜ far near − tz = − ⎜ ⎟ far − near ⎜ 0 0 0 −1⎠⎟ ⎝ void glFrustum (Gldouble left, Gldouble right, Gldouble bottom, Gldouble top, Gldouble znear, Gldouble zfar);
Создание матрицы перспективы (рис. 2). ⎛ 2 near ⎜ right − left ⎜ ⎜ 0 ⎜ ⎜ ⎜ 0 ⎜ 0 ⎝
0 2 near top − bottom 0 0
⎞ 0⎟ ⎟ ⎟ B 0 ⎟, ⎟ C D⎟ ⎟ −1 0 ⎠ A
right + left top + bottom , B= right − left top − bottom 2 far near far + near , D=− C=− far − near top − bottom A=
7
Задняя секущая плоскость zfar
Задняя секущая Top плоскость far Top
Rigth
Left Bottom
Rigth
Left
Передняя секущая плоскость near
Bottom
Передняя секущая плоскость znear
Рис. 1 Рис. 2 После применения матрицы проекций получаются так называемые усеченные (clipped) координаты (xc, yc, zc, wc)T. Затем находятся нормализованные координаты вершин по формуле: (xn, yn, zn)T = (xc/wc , yc/wc, zc/wc)T void glViewport(Glint X, Glint Y, Glint width, Glint height);
Определение области вывода (прямоугольник в оконной системе координат) с центром в точке ox=X+width/2, oy=Y+height/2 с размерами width, height. Тогда можно найти оконные координаты каждой вершины: (xw, yw, zw)T = ( (width/2) xn+ ox , (height/2) yn+ oy , [(f-n)/2] zn+(n+f)/2 )T При этом целые положительные величины n и f задают минимальную и максимальную глубину точки в окне и по умолчанию равны 0 и 1 соответственно. Глубина каждой точки записывается в буфер глубины (z-буфер), который используется для удаления невидимых линий и поверхностей. Установить значения n и f можно вызовом функции void glDepthRange (GLclampd n, GLclampd f).
Если необходимо изменить положение наблюдателя, что также приводит к изменению модельно-видовой матрицы, то это можно сделать с помощью 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 нужно записывать в обратном порядке, то есть матрица текущего преобразования умножается справа на матрицу нового преобразования. Например, если нужно сначала повернуть объект, а затем передвинуть его, сначала нужно вызвать glTranslate(), потом – glRotate(), а после этого определять сам объект. Тогда матрица полного преобразования будет: M = M Translate M Rotate Модель освещения, свойства материалов В OpenGL используется модель освещения, в которой цвет точки определяется факторами: свойствами материала и текстуры, величиной и направлением нормали в этой точке, а также положением источника света и наблюдателя. При 8
этом закраска граней осуществляется только по методу Гуро, когда цвет в каждом пикселе грани вычисляется при помощи линейной интерполяции цвета по грани. Интенсивность же отраженного света в вершинах граней вычисляется в соответствии с моделью освещения Фонга: F I = I A k A + I D k D ( N , S ) + I S k S ( R ,V ) , где I A - интенсивность фоновой составляющей, k A - коэффициент фоновой составляющей, I D - интенсивность диффузной составляющей, k D - коэффициент диффузной составляющей, N – нормаль к поверхности, S – направление на источник света, I S - интенсивность зеркальной составляющей, k S - коэффициент зеркального отражения, R – направление зеркального отражения, V – направление на наблюдателя, F ∈ [1,200] - степень шероховатости.
Параметры модели Фонга для некоторых материалов: Фоновые коэф. Материал Черная пластмасса Латунь Бронза Хром Медь Золото Олово Серебро Полированное серебро
крас.
зел.
син.
0.0
0.0
0.0
0.3294 0.2125 0.2500 0.1913 0.2473 0.1059 0.1923
0.2235 0.1275 0.2500 0.0735 0.1995 0.0588 0.1923
0.0275 0.0540 0.2500 0.0225 0.0745 0.1137 0.1923
Диффузные коэф. крас.
зел.
син.
Зеркальные коэф. крас.
зел.
син.
Степень шероховатости
0.0100 0.0100 0.0100 0.5000 0.5000 0.5000
32
0.7804 0.7140 0.4000 0.7038 0.7516 0.4275 0.5075
0.8078 0.1667 0.7746 0.0860 0.3661 0.5216 0.5083
28 26 77 13 51 10 51
0.2313 0.2313 0.2313 0.2775 0.2775 0.2775 0.7739 0.7739 0.7739
90
0.5687 0.4284 0.4000 0.2705 0.6065 0.4706 0.5075
0.1137 0.1814 0.4000 0.0828 0.2265 0.5412 0.5075
0.9922 0.3935 0.7746 0.2568 0.6283 0.3333 0.5083
0.9412 0.2719 0.7746 0.1376 0.5558 0.3333 0.5083
Задание глобальных параметров освещения: void glLightModel [i f] (GLenum pname, GLenum param) void glLightModel[i f]v (GLenum pname, const GLtype *params) Параметры модели освещения (glLightModel)
Параметр pname
по умолчанию
Описание Общий рассеянный свет для GL_LIGHT_MODEL_AMBIENT (0.2,0.2,0.2,1.0) всех объектов GL_LIGHT_MODEL_ Положение наблюдателя в FALSE LOCAL_VIEWER видовой системе координат Освещение одной (FALSE) GL_LIGHT_MODEL_TWO_SIDE FALSE или обеих (TRUE) граней 9
Установка нового 3-х или 4-х компонентного значения цвета: void glColor[34][b s i f d] (Gltype components) void glColor[34][b s i f d]v (Gltype components)
Определение свойств материала: Void glMaterial [if](Glenum face, Glenum pname, Glenum param) Void glMaterial [if]v(Glenum face, Glenum pname, Glenum param) Аргумент face определяет, для каких (лицевых / не лицевых) граней, какие свойства (pname) будут заданы (param). Значения face – GL_FRONT, GL_BACK, GL_FRONT_AND_BACK. Параметры материала (glMaterial) по умолчанию Описание Параметр pname
GL_AMBIENT GL_DIFFUSE GL_SPECULAR GL_EMISSION
4 4 4 4
(0.2,0.2,0.2, 1.0) (0.8,0.8,0.8,1.0) (0.0,0.0,0.0,1.0) (0.0,0.0,0.0,1.0)
GL_SHININESS
1
0.0
Рассеянный цвет материала Диффузный цвет материала Зеркальный цвет материала Излучаемый цвет материала Степень зеркального отражения материала из диапазона [0,128]
Определение источника света. void glLight [i f] (Glenum light, Glenum pname, Glenum param) void glLight [i f] (Glenum light, Glenum pname, Glenum param)
Определяют источник с номером light, свойствами pname, и значением param. Параметры источника света (glLight) по умолчанию Описание Параметр pname Интенсивность рассеянного света GL_AMBIENT 4 (0.0,0.0,0.0,1.0) i-го источника Интенсивность GL_DIFFUSE 4 (1.0,1.0,1.0,1.0) диффузного света нулевого источника; (0.0,0.0,0.0,1.0) i-го источника Интенсивность зеркального света GL_SPECULAR 4 (1.0,1.0,1.0,1.0) нулевого источника; (0.0,0.0,0.0,1.0) i-го источника Положение i-ro источника света в GL_POSITION 4 (0.0,0.0,1.0,1.0) мировых координатах Направление действия i-ro GL_SPOT_DIRECTION 3 (0.0,0.0,-1.0) источника света Показатель распределения GL_SPOT_EXPONENT 1 0.0 интенсивности i-ro источника GL_SPOT_CUTOFF 1 180.0 Угол разброса i-ro источника света GL_CONSTANT_ Коэффициент постоянного 1 1.0 ATTENUATION ослабления i-ro источника света GL_LINEAR_ Коэффициент линейного 1 0.0 ATTENUATION ослабления i-ro источника света GL_QUADRAT1C_ Коэффициент квадратичного 1 0.0 ATTENUATION ослабления i-ro источника света 10
Задание параметров вывода void glEnable (GLenum cap) – разрешение режима, заданного сар; void glDisable (GLenum cap) – запрещение режима, заданного сар; Некоторые значения Назначение режима параметра cap GL_ALPHA_TEST Проводится тестирование по цветовому параметру альфа. См. команду glAlphaFunc GL_BLEND Разрешается смешивание поступающих значений RGBA цветов со значениями, находящимися в буфере цветов. См. команду gIBIendFunc GL_CLIP_PLANE i Разрешается геометрическое отсечение в определенной пользователем плоскости GL_COLOR_MATERIAL Для одного или нескольких параметров материала используется значение текущего цвета. См. команду glColorMaterial GL_DEPTH_TEST Разрешается выполнение теста на сравнение параметров глубины объектов (z-буфер) GL_FOG В цвет объекта после наложения текстуры добавляется цвет тумана. См. команду gIFog GL_LIGHTi Включается i-й источник света в общее уравнение оценки освещенности GL_LIGHTING В результирующем цвете вершины используются параметры текущей освещенности.
Для использования освещения сначала надо установить соответствующий режим вызовом команды glEnable(GL_LIGHTNING), а затем включить нужный источник командой glEnable(GL_LIGHTi). Текстурирование Часто возникает потребность накладывать изображение на трехмерные объекты. Для этих целей существуют текстуры. Для того чтобы наложить текстуру на объект, необходимо: 1. Загрузить графический файл в память 2. Создать имя-идентификатор текстуры 3. Сделать его активным 4. Создать саму текстуру в памяти 5. Установить параметры текстуры 6. Установить параметры взаимодействия текстуры с объектом 7. Связать координаты текстуры с объектом Подготовка текстуры Для использования изображения в качестве текстуры необходимо сначала загрузить в память нужное изображение и передать его OpenGL.
11
Считывание графических данных из файла и их преобразование можно проводить с помощью функции, входящей в состав библиотеки GLAUX (надо подключить glaux.lib), которая сама проводит необходимые операции: AUX_RGBImageRec* auxDIBImageLoad (const char *file)
где file – название файла с расширением *.bmp или *.dib. Функция возвращает указатель на область памяти, где хранятся преобразованные данные. Размеры текстуры, как по горизонтали, так и по вертикали должны представлять собой степени двойки. Это требование накладывается для компактного размещения текстуры в текстурной памяти и способствует ее эффективному использованию. Работать только с такими текстурами конечно неудобно, поэтому после загрузки их можно преобразовать с помощью команды void gluScaleImage (GLenum format, GLint widthin, GL heightin, GLenum typein, const void *datain, GLint widthout, GLint heightout, GLenum typeout, void *dataout)
В качестве значения параметра format обычно используется значение GL_RGB или GL_RGBA, определяющее формат хранения информации. Параметры widthin, heightin, widhtout, heightout определяют размеры входного и выходного изображений, а с помощью typein и typeout задается тип элементов массивов, расположенных по адресам datain и dataout. Это может быть тип GL_UNSIGNED_BYTE, GL_SHORT, GL_INT и так далее. Результат своей работы функция заносит в область памяти, на которую указывает параметр dataout. Чем меньше объект, тем меньше должна быть наносимая на него текстура и поэтому вводится понятие уровней детализации текстуры (mipmap). Каждый уровень детализации задает некоторое изображение, которое является уменьшенной в два раза копией оригинала. Эти два этапа создания образа текстуры во внутренней памяти OpenGL можно провести с помощью команды void gluBuild2DMipmaps (GLenum target, GLint components, Glint width,GLint height,GLenum format,GLenum type,const void *data)
где параметр target должен быть GL_TEXTURE_2D. Параметр components определяет количество цветовых компонент текстуры: GL_LUMINANCE одна компонента – яркость GL_RGB красный, синий, зеленый GL_RGBA все компоненты. Параметры width, height, data определяют размеры и расположение текстуры соответственно, а format и type имеют аналогичный смысл, что в gluScaleImage(). При использовании в сцене нескольких текстур, в OpenGL применяется подход, напоминающий создание списков изображений (так называемые текстурные объекты). Сначала с помощью команды void glGenTextures (GLsizei n, GLuint* textures)
надо создать n идентификаторов текстур, которые будут записаны в массив textures. Перед началом определения свойств очередной текстуры следует сделать ее текущей («привязать» текстуру), вызвав команду void glBindTexture (GLenum target, GLuint texture)
где target может принимать значения GL_TEXTURE_1D или GL_TEXTURE_2D, а параметр texture должен быть равен идентификатору той 12
текстуры, к которой будут относиться последующие команды. Для того чтобы в процессе рисования сделать текущей текстуру с некоторым идентификатором, достаточно опять вызвать команду glBindTexture() c соответствующим значением target и texture. Наложение текстуры на объекты Для определения положения точки на текстуре используется параметрическая система координат (s,t), причем значения s и t находятся в отрезке [0,1] Для изменения различных параметров текстуры применяются команды: void glTexParameter [if](GLenum target,GLenum pname,GLenum param) void glTexParameter[if]v(GLenum target, GLenum pname,Glenum*params)
При этом target может принимать значения GL_TEXTURE_1D или GL_TEXTURE_2D, pname определяет, какое свойство меняем, а с помощью param или params устанавливается новое значение. Возможные значения pname: GL_TEXTURE_MIN_FILTER параметр param определяет функцию, которая будет использоваться для сжатия текстуры. При значении GL_NEAREST будет использоваться один (ближайший), а при значении GL_LINEAR четыре ближайших элемента текстуры. GL_TEXTURE_MAG_FILTER аналогичен GL_TEXTURE_MIN_FILTER, только для увеличения (растяжения) текстуры. GL_TEXTURE_WRAP_S параметр param устанавливает значение координаты s, если оно не входит в отрезок [0,1]. При значении GL_ REPEAT целая часть s отбрасывается, и в результате изображение размножается по поверхности. При значении GL_CLAMP используются краевые значения: 0 или 1, что удобно использовать, если на объект накладывается один образ. GL_TEXTURE_WRAP_T аналогично предыдущему, только для координаты t. Для того чтобы определить, как текстура будет взаимодействовать с материалом, из которого сделан объект, используются команды void glTexEnv [i f] (GLenum target, GLenum pname, GLtype param) void glTexEnv[i f]v (GLenum target, GLenum pname, GLtype *params)
Параметр target должен быть равен GL_TEXTURE_ENV, а в качестве pname рассмотрим только одно значение GL_TEXTURE_ENV_MODE, которое наиболее часто применяется. Наиболее часто используемые значения параметра param: GL_MODULATE конечный цвет находится как произведение цвета точки на поверхности и цвета соответствующей ей точки на текстуре. GL_REPLACE в качестве цвета используется цвет точки на текстуре. Следующая программа демонстрирует общий подход к созданию текстур: /* нужное нам количество текстур */ #define NUM_TEXTURES 10 /* идентификаторы текстур */ int TextureIDs[NUM_TEXTURES]; /* образ текстуры */ AUX_RGBImageRec *pImage; … /* 1) получаем идентификаторы текстур */
13
glGenTextures(NUM_TEXTURES,TextureIDs); /* 2) выбираем текстуру для модификации параметров */ glBindTexture(TextureIDs[i]); /* 0sizeY, GL_RGB, GL_UNSIGNED_BYTE, pImage->data); glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, (float)GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (float)GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, (float)GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, (float)GL_REPEAT); glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, (float)GL_REPLACE); /* 5) удаляем исходное изображение.*/ free(Texture); }else Error();
Текстурные координаты Перед нанесением текстуры на объект необходимо установить соответствие между точками на поверхности объекта и на самой текстуре. Задавать это соответствие можно отдельно для каждой вершины или сразу для всех вершин. Первый метод реализуется с помощью команд void glTexCoord[1 2 3 4][s i f d] (type coord) void glTexCoord[1 2 3 4][s i f d]v (type *coord) Чаще всего используются команды вида glTexCoord2*(type s, type t), за-
дающие текущие координаты текстуры. Второй метод реализуется с помощью команд void glTexGen[ifd] (GLenum coord, GLenum pname, GLtype param) void glTexGen[ifd]v(GLenum coord,GLenum pname,const GLtype *params)
Параметр coord определяет, для какой координаты задается формула, и может принимать значение GL_S,GL_T; pname может быть равен одному из следующих значений: GL_TEXTURE_GEN_MODE определяет функцию для наложения текстуры. В этом случае аргумент param принимает значения: GL_OBJECT_LINEAR значение текстурной координаты определяется расстоянием до плоскости, задаваемой с помощью значения pname GL_OBJECT_PLANE. Формула: g=x*xp+y*yp+z*zp+w*wp, где g– текстурная координата (s или p), x, y, z, w – координаты точки объекта. xp, yp, zp, wp – коэффициенты уравнения плоскости. 14
GL_EYE_LINEAR аналогично предыдущему значению, только в формуле используются видовые координаты. GL_SPHERE_MAP позволяет эмулировать отражение от поверхности объекта. Текстура как бы "оборачивается" вокруг объекта. Для данного метода используются видовые координаты и необходимо задание нормалей. GL_OBJECT_PLANE позволяет задать плоскость, расстояние до которой будет использоваться при генерации координат, если установлен режим GL_OBJECT_LINEAR. В этом случае параметр params является указателем на массив из четырех коэффициентов уравнения плоскости. GL_EYE_PLANE аналогично предыдущему значению. Позволяет задать плоскость для режима GL_EYE_LINEAR Для установки автоматического режима задания текстурных координат необходимо вызвать команду glEnable с параметром GL_TEXTURE_GEN_S или GL_TEXTURE_GEN_P.
Практическая часть. Визуализировать трехмерную сцену с возможностями перемещения наблюдателя в любую точку, автоматического вращения сцены. Сцена должна состоять из тела, получаемого путем тиражирования (последовательного перемещения) заданного пользователем двумерного сечения вдоль некоторой траектории и закраски боковой и торцевых поверхностей получаемого тела. Сечение должно быть перпендикулярно траектории тиражирования. Требования к программе. 1. Входные данные – текстовый файл с описанием сечения, пути его тиражирования, положения сечений вдоль пути с углом поворота или коэффициентом масштабирования. 2. Положения сечения задаются длиной пути от начальной вершины в процентах. 3. Нормали в вершинах объекта должны совпадать с нормалями аппроксимируемой поверхности. При визуализации использовать источники света, свойства материалов и текстуры. Варианты заданий. №
Путь
Сечение
1 2 3 4 5 6 7 8 9 10
отрезок отрезок отрезок отрезок отрезок отрезок ломаная ломаная ломаная ломаная
выпуклый многоугольник невыпуклый многоугольник выпуклый многоугольник невыпуклый многоугольник выпуклый многоугольник невыпуклый многоугольник выпуклый многоугольник невыпуклый многоугольник выпуклый многоугольник невыпуклый многоугольник 15
Способ тиражирования сечения без изменения без изменения с поворотом с поворотом с масштабированием с масштабированием без изменения без изменения с поворотом с поворотом
11 12 13
ломаная выпуклый многоугольник ломаная невыпуклый многоугольник окружность невыпуклый многоугольник
с масштабированием с масштабированием без изменения
Контрольные вопросы. 1. Какие системы координат используются в OpenGL? 2. Перечислите виды матричных преобразований в OpenGL. Каким образом происходят преобразования объектов в OpenGL? 3. Перечислите способы изменения положения наблюдателя в OpenGL. 4. Какая последовательность вызовов команд glTranslate(), glRotate() и glScale() соответствует команде gluLookAt(0, 0, -10, 10, 0, 0, 0, -1, 0)? 5. Что такое видовые координаты? Нормализованные координаты?
ЛАБОРАТОРНАЯ РАБОТА №3 ПОСТРОЕНИЕ ИЗОБРАЖЕНИЙ МЕТОДОМ ТРАССИРОВКИ ЛУЧЕЙ
Цель работы. Ознакомиться с основными аспектами метода трассировки лучей. Теоретическая часть. Метод трассировки лучей используется для получения высокореалистичных изображений с учетом отражений и преломлений света. В методе обратной трассировки лучей вычисляются интенсивности лучей, достигших глаза наблюдателя. Для этого отслеживаются лучи, проходящие из глаза наблюдателя через каждый пиксель экрана в сцену. На каждой поверхности сцены, на которую попадает луч, в общем случае формируются отраженный и преломленный лучи. Каждый из таких лучей отслеживается, чтобы определить пересекаемые поверхности. В результате для каждого пикселя строится дерево пересечений. Ветви такого дерева представляют распространение луча в сцене, а узлы - пересечения с поверхностями в сцене. Окончательная закраска определяется прохождением по дереву и вычислением вклада каждой пересеченной поверхности в соответствии с используемыми моделями отражения. Алгоритм трассировки лучей 1. Через каждый пиксель картинной плоскости выпускается луч в сцену и ищется точка его ближайшего пересечения с объектами сцены. Из этой точки выпускаются лучи ко всем источникам света (для определения их видимости), также выпускаются отраженный и преломленный лучи. 2. Для определения световой энергии, приходящей вдоль отраженного и преломленного лучей, каждый из этих лучей трассируется для определения точки ближайшего пересечения. Затем снова может потребоваться трассировка возникающих отраженных и преломленных лучей. 3. Критерии прекращения рекурсии: заданный уровень рекурсии или заданный вес луча.
16
Задание наблюдателя Наблюдатель (камера) задается своими: - положением (точка Eye); - ориентацией (векторы u,v,w); - углом зрения ( θ );
- форматным отношением поля зрения aspect =
W , W-полуширина, а HH
полувысота экрана; - N-расстоянием до экрана. θ Поскольку H = N ⋅ tg , W = H ⋅ aspect , то 2 2c 2r uc = −W + W , vr = − H + H - координаты (r,c)-пикселя. nCols nRows Уравнение луча, проходящего из камеры через (r,c)-пиксель: r (t ) = Eye(1 − t ) + ( Eye + Nw + ucu + vr v) t
r (t ) = Eye + Dirrct , Dirrc = Nw + ucu + vr v При этом: при t