close

Вход

Забыли?

вход по аккаунту

код для вставкиСкачать
КОМПЬЮТЕРНАЯ ГРАФИКА С
ИСПОЛЬЗОВАНИЕМ OPENGL
Методические указания к лабораторным работам для студентов 3 курса
ФПМИ
Предварительная версия от 10.03
Новосибирск
2015
1
ЛАБОРАТОРНАЯ РАБОТА №1
ВВЕДЕНИЕ В ПРОГРАММИРОВАНИЕ С ИСПОЛЬЗОВАНИЕМ
OPENGL
Цель работы.
Ознакомиться с основами использования библиотеки OpenGL.
Теоретическая часть.
OpenGL (Open Graphics Library, Открытая Графическая Библиотека) –
это популярный программный интерфейс (API – Application Programming
Interface) к графической аппаратуре. Работа с библиотекой построена по
принципу «клиент-сервер»: приложение вызывает команды, а библиотека
занимается их обработкой.
Библиотека OpenGL была разработана как обобщенный аппаратнонезависимый интерфейс. По этой причине сама OpenGL не включает
функций для работы с окнами (мышкой, клавиатурой, и т.п.) и задания
высокоуровневых описаний сложных моделей – для этих целей
используются такие надстройки над OpenGL, как GLU (OpenGL Utility
Library) и GLUT (OpenGL Utility Toolkit)
Синтаксис команд
Все команды (процедуры и функции) библиотеки GL начинаются с
префикса gl, все константы – с префикса GL_. Кроме того, в имена команд
входят суффиксы, несущие информацию о числе и типе передаваемых
параметров.
Рассмотрим некоторые варианты на примере команды задания белого
цвета glColor3ub (255, 255, 255):
Параметр
Описание
Варианты
имя библиотеки, в которой glu (GLU)
gl
описана
функция
Color glut (GLUT)
(в данном случае: OpenGL)
aux (GLAUX)
функция задания цвета
Color
количество передаваемых
1,2,4
3
аргументов
тип передаваемых аргументов i – целый, 4 байта
ub
(в данном случае: целый,
f – вещественный, 4 байта
беззнаковый, 1 байт)
если в типе указан параметр v,
255, 255, 255 список аргументов
(в данном случае: типа ub)
то список аргументов
представляет собой векторную
величину (массив аргументов)
2
Задание геометрических примитивов
Для задания геометрических примитивов необходимо выделить набор
вершин, определяющих этот объект. Для этого служат процедуры glBegin(*)
и glEnd().
Тип примитива задается параметром процедуры glBegin(*) и может
принимать значения, представленные в следующей таблице:
GL_POINTS
каждая вершина задает координаты точки
GL_LINES
каждая отдельная пара вершин определяет отрезок
GL_LINE_STRIP
вершины определяют незамкнутую ломаную
GL_LINE_LOOP
вершины определяют замкнутую ломаную
GL_TRIANGLES
каждая отдельная
треугольник
GL_TRIANGLE_STRIP
каждая следующая вершина вместе
предыдущими задает треугольник
GL_TRIANGLE_FAN
первая вершина и каждая следующая пара задают
треугольник
GL_QUADS
каждая отдельная
четырехугольник
GL_QUAD_STRIP
каждая следующая пара вершин вместе с предыдущей
парой задает четырехугольник
GL_POLYGON
вершины определяют выпуклый многоугольник
тройка
четверка
вершин
вершин
определяет
с
двумя
определяет
Пример кода для задания разноцветного треугольника ABC с
использованием различных типов данных:
GLubyte blue[3] = {0, 0, 255};
GLfloat coord[] = {2, 1};
glColor3f (1.0, 0.0, 0.0); /* задаем красный цвет в
glBegin (GL_TRIANGLES);
glVertex2f (0.0, 0.0);
/* задаем координаты A
glColor3ub (0, 255, 0);
/* задаем зеленый цвет
glVertex2i (1, 2);
/* задаем координаты B
glColor3ubv (blue);
/* задаем синий цвет в
glVertex2fv (coord);
/* задаем координаты C
glEnd();
A */
*/
в B */
*/
C */
*/
3
Структура консольного приложения
Будем рассматривать построение консольного приложения при помощи
библиотеки GLUT. Эта библиотека обеспечивает единый интерфейс для
работы с окнами вне зависимости от платформы, поэтому описываемая ниже
структура приложения остается неизменной для операционных систем
Windows, Linux, и других.
Функции GLUT могут быть классифицированы на несколько групп по
своему назначению, рассмотрим основные:
1. Инициализация:
 Начальная инициализация самой библиотеки GLUT:
glutInit(&argc, argv)
 Инициализация буфера кадра (определение режима
RGB,
включение двойной буферизации):
glutInitDisplayMode (GLUT_RGB | GLUT_DOUBLE)
2. Управление окнами:
 Определение размеров окна (например, 512 на 512):
glutInitWindowSize (512, 512)
 Создание окна и определение заголовка:
glutCreateWindow ("Пример приложения на GLUT")
3. Регистрация вызываемых (callback) функций (т.е. функций обратного
вызова) для реакции на нажатие клавиш (Keyboard, Mouse),
изменения размера окна (Reshape) и необходимости обновления окна
(Display):
glutKeyboardFunc (Keyboard)
glutMouseFunc
(Mouse)
glutDisplayFunc (Display)
glutReshapeFunc (Reshape)
4. Контроль всех событий и вызов нужных функций:
 цикл обработки сообщений:
glutMainLoop ()
 принудительный вызов функции обновления окна:
glutPostRedisplay ()
4
Пример приложения с использованием библиотек GLUT и STL
В данном примере рисуется множество точек, задаваемых кликом
левой клавиши мыши. По правому клику меняется цвет всех точек, а по
центральному – их позиции.
Для хранения множества точек используется контейнер vector из
библиотеки STL (Standard Template Library, Библиотека Стандартных
Шаблонов)
/* подключаем контейнер vector из библиотеки STL */
#include <vector>
/* подключаем библиотеки OpenGL и GLUT */
#include "glut.h"
#pragma comment(lib, "opengl32.lib")
#pragma comment(lib, "glut.lib")
/* начальная ширина и высота окна */
GLint Width = 512, Height = 512;
/* начальный цвет точек */
GLubyte ColorR = 255;
GLubyte ColorG = 255;
GLubyte ColorB = 255;
/* определяем контейнер вершин */
struct type_point
{
GLubyte x; GLubyte y;
type_point (GLubyte _x, GLubyte _y) { x=_x; y=_y; }
}
vector <type_point> Points;
/* Функция управляет всем выводом на экран */
void Display(void)
{
/* очищаем буфер кадра */
glClearColor ( 0, 0, 0, 1 );
glClear ( GL_COLOR_BUFFER_BIT );
/* задаем общий цвет точек */
glColor3ub (ColorR, ColorG, ColorB);
/* задаем общий цвет точек – красный */
glBegin ( GL_POINTS );
for ( int i=0; i<Points.size(); i++ )
glVertex2ub( Points[i].x, Points[i].y);
glEnd();
/* завершаем подготовку буфера кадра и передаем его для
вывода на экран */
glFinish();
5
}
/* Функция вызывается при изменении размеров окна */
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 )
{
/* выход из программы при нажатии на клавишу ESC */
if( key == '\033') exit(0);
}
/* Функция обрабатывает сообщения от мыши */
void Mouse ( int button, int state, int x, int y )
{
type_point p;
/* каждый левый клик – новая точка */
if ( button==GLUT_LEFT_BUTTON && state==GLUT_DOWN )
{
type_point p (x, Height - y);
Points.push_back (p);
}
/* каждый правый клик – смена цвета точек */
if ( button==GLUT_RIGHT_BUTTON && state==GLUT_DOWN )
{
ColorR /= 2;
ColorG /= 2;
ColorB /= 2;
}
/* каждый средний клик – сдвиг точек */
if ( button==GLUT_MIDDLE_BUTTON && state==GLUT_DOWN )
{
for ( int i=0; i<Points.size(); i++ )
{
Points[i].x += 10;
Points[i].y += 10;
6
}
}
/* принудительный вызов функции обновления окна */
glutPostRedisplay();
}
/* головная программа */
main ( int argc, char *argv[] )
{
/* инициализация */
glutInit ( &argc, argv );
glutInitDisplayMode ( GLUT_RGB );
/* создание окна */
glutInitWindowSize ( Width, Height );
glutCreateWindow ( "Рисуем точки" );
/* регистрация функций обратного вызова */
glutDisplayFunc(Display);
glutReshapeFunc(Reshape);
glutKeyboardFunc(Keyboard);
glutMouseFunc(Mouse);
/* Запуск цикла обработки сообщений */
glutMainLoop();
}
Практическая часть.
1. Отобразить в окне множество примитивов (вершины
которых
задаются кликами мыши) в соответствии с вариантом задания.
2. Для завершения текущего множества примитивов и начала нового
зарезервировать специальную клавишу (пробел, правый клик, …).
3. Для последнего (текущего) множества предоставить возможность
изменения цвета, координат и размера точек (вершин).
4. Использовать контейнер vector из библиотеки STL для хранения набора
примитивов и множества вершин каждого примитива. Для хранения
координат и цвета вершин завести соответствующий тип данных с
использованием класса struct (или написать свой).
5. Для повышения уровня сложности нужно:
1) предусмотреть возможность изменения не только координат и
цвета, но и размера вершин, режимов сглаживания, шаблона
закрашивания;
2) предоставить возможность изменения параметров не только
текущего набора примитивов, но и произвольного;
7
3) предоставить возможность изменения параметров произвольного
примитива в текущем наборе;
4) использовать меню.
Варианты заданий.
1. Множество точек (GL_POINTS).
2. Множество ломанных (GL_LINES).
3. Множество ломанных (GL_LINE_STRIP).
4. Множество ломанных (GL_LINE_LOOP).
5. Множество треугольников (GL_TRIANGLES).
6. Множество треугольников (GL_TRIANGLE_STRIP).
7. Множество треугольников (GL_TRIANGLE_FAN).
8. Множество четырехугольников (GL_QUADS).
9. Множество четырехугольников (GL_QUAD_STRIP).
10.Множество полигонов (GL_POLYGON).
Контрольные вопросы и задания.
1. Архитектура библиотек OpenGL и организация конвейера.
2. Категории команд (функций) этих библиотек.
3. Функции обратного вызова.
4. Примитивы и атрибуты.
5. Контейнер vector.
8
ЛАБОРАТОРНАЯ РАБОТА №2
РАСТЕРИЗАЦИЯ
Цель работы.
Ознакомиться с принципами растеризации и наложения цветов и
текстур.
Теоретическая часть.
Включение (разрешение) и выключение (запрещение) ряда операций
(таких, как использование освещения, текстурирования, сглаживания и т.п.)
выполняется командами glEnable(*) и glDisable(*), в качестве параметра
которых выступает константа-идентификатор этих операций.
Векторные и растровые изображения
Изображение бывает векторными и растровыми.
Растровые изображения представляют собою набор пискелей (pixel –
picture element), т.е. «наименьший элемент поверхности визуализации,
которому может быть независимым образом заданы цвет, интенсивность
и другие характеристики изображения». Пиксель – это также наименьшая
единица растрового изображения монитора и других графических систем
вывода информации. Соответственно, чем больше разрешение изображение
(количество пискселей по горизонтали и вертикали), тем более качественным
оно получается.
Векторные же изображения задаются функциями (отрезок, окружность,
прямоугольник, ...) с такими параметрами, как цвет заливки, толщина и цвет
контура и т.п. В результате, качество векторного изображения не ухудшается
при изменении масштаба. Соответственно, для вывода векторного
изображения на экран, оно должно быть сначала растеризовано (переведено в
растровый формат).
Для вывода отрезка или кривой воспользуемся алгоритмом Брезенхема
(Bresenham), при необходимости сглаживания (антиэлайсинга) – алгоритмом
Ву (Xiaolin Wu).
Заливку (закрашивание) многоугольника будем осуществлять только
простейшим методом углов. Идея метода заключается в том, что сумма всех
углов, образованных рассматриваемой точкой и вершинами многоугольника
равна 360° только в том случае, когда эта точка находится внутри.
Логические операции над цветами
Для разрешения или запрещения использования логических операций
над цветами используется параметр GL_COLOR_LOGIC_OP.
9
Выбор конкретной логической операции задается параметром функции
glLogicOp ( * ):
Логическая операция
Действие над цветами s и d
GL_AND_REVERSE
s & !d
GL_AND_INVERTED
!s & d
GL_OR_REVERSE
s | !d
GL_OR_INVERTED
!s | d
GL_AND
s & d
GL_NAND
!(s & d)
GL_OR
s | d
GL_NOR
!(s | d)
GL_XOR
s ^ d
GL_EQUIV
!(s ^ d)
Расшифровка обозначений приведена в следующей таблице:
Знак
|
&
Варианты названий
OR
AND
ИЛИ
И
Битовая операция
СЛОЖЕНИЕ
0Ι0=0
0Ι1=1
1Ι0=1
1Ι1=1
УМНОЖЕНИЕ
0&0=0
0&1=0
1&0=0
1&1=1
^
XOR
ИСКЛЮЧАЮЩЕЕ
ИЛИ
ВЫЧИТАНИЕ
0^0=0
0^1=1
1^0=1
1^1=0
!
NOT
НЕ
ОТРИЦАНИЕ
!0=1
!1=0
10
Текстурирование
Текстура – это графическое изображение (обычно в виде двумерной
картинки в формате bmp), используемое для нанесения изображения на
объект, составленный из множества примитивов. Целью применения текстур
является повышение реалистичности изображения за счет экономии
вычислительных ресурсов.
Пиксели текстуры называют текселями (texel – texture element
элемент текстуры). Но, как видно из названия, в общем случае тексели не
обязательно являются пикселями изображения (например, тексели можно
рассматривать как карту высот при Bump Mapping)
Принятый в OpenGL формат хранения изображений отличается от
стандартного формата Windows DIB только тем, что компоненты (R,G,B) для
каждой точки хранятся в прямом порядке, а не в обратном и выравнивание
задается программистом.
В общем случае необходимо выполнить следующие этапы наложения
текстур:
1. Выбрать изображение в нужном формате (желательно bmp)
2. Загрузить изображение в память.
3. Установить параметры учета текстур:
3.1.
3.2.
3.3.
3.4.
3.5.
Сгенерировать массив текстур.
Выбрать активную текстуру.
Установить режим выравнивание текстур.
Определить параметры сжатия/растяжения и дублирования.
Задать режим учета параметров материала.
4. Привязать текстуру к примитиву.
5. Разрешить использование текстур (GL_TEXTURE_2D)
Далее рассмотрим только основные функции и параметры.
Для загрузки текстур можно использовать команды различных
библиотек:
Функция
Библиотека
Формат изображения
auxDIBImageLoad
GLAux
bmp
FreeImage_GetFileType
FreeImage
различный
ilLoad
DevIL
различный
LoadImage
Windows
bmp
fread
Windows
несжатый bmp 24 бита
11
Эти функции должны вернуть следующие параметры текстуры, которые
будут использоваться далее:
width – ширина изображения
height – высота изображения
pixels – указатель на массив текселей
Для установления параметров учета двумерных текстур используются
следующие функции:
1) Генерация массива текстур (в данном примере – из одной):
glGenTextures ( 1, &tex)
2) Выбор активной (текущей) текстуры с идентификатором tex:
glBindTexture ( GL_TEXTURE_2D, tex)
3) Выравнивание текстуры (если разрешение текстуры не кратно
степени двойки) и расчет уровней детализации (для случаев, когда
текстура заметно больше самого примитива):
gluBuild2DMipmaps ( GL_TEXTURE_2D, 3, width, height,
GL_RGB, GL_UNSIGNED_BYTE, pixels)
4) Задание параметров растяжения/сжатия по линейному закону и
разрешение дублирования:
glTexParameterf ( GL_TEXTURE_2D,
GL_TEXTURE_MIN_FILTER, GL_LINEAR )
glTexParameterf ( GL_TEXTURE_2D,
GL_TEXTURE_ MAG_FILTER, GL_LINEAR )
glTexParameterf ( GL_TEXTURE_2D,
GL_TEXTURE_ WRAP_S, GL_REPEAT)
glTexParameterf ( GL_TEXTURE_2D,
GL_TEXTURE_ WRAP_T, GL_REPEAT)
Для ускорения обработки текстуры можно вместо значения
GL_LINEAR использовать GL_NEAREST – тогда вместо четырех
соседних точек будет использоваться только ближайшая.
Для запрета дублирования (замощения) значение GL_REPEAT
нужно заменить на GL_CLAMP.
5) В том случае, когда примитиву был указан материал, то учет
материала при расчете может заблокирован:
glTexEnvi ( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
GL_REPLACE )
Если вместо значения GL_REPLACE указать GL_MODULATE, тогда
цвета соответствующих точек примитива и текстуры перемножатся.
12
Для привязывания текстуры к примитиву необходимо установить
соответствие между его вершинами и точками (x,y) на самой текстуре:
glTexCoord2f ( x, y )
Пример кода для задания квадрата с текстурой из файла “texture.bmp”:
AUX_RGBImageRec* bmp = auxDIBImageLoad(“texture.bmp”);
width = bmp >sizeX;
height = bmp >sizeY;
pixels = bmp >data;
glGenTextures (1, &tex) ;
glBindTexture (GL_TEXTURE_2D, tex);
gluBuild2DMipmaps (GL_TEXTURE_2D, 3, width, height, GL_RGB,
GL_UNSIGNED_BYTE, pixels);
glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
glEnable (GL_TEXTURE_2D);
glBegin (GL_QUAD);
glTexCoord2f(0,0);
glTexCoord2f(0,1);
glTexCoord2f(1,0);
glTexCoord2f(1,1);
glEnd();
glVertex2i(10,10);
glVertex2i(10,90);
glVertex2i(90,10);
glVertex2i(90,90);
Модельно-видовые преобразования
К модельно-видовым преобразованиям относят перенос, поворот и
изменение масштаба. Соответствующие команды OpenGL имеют вид:
1. Сдвиг по вектору (dx, dy, dz):
glTranslatef ( dx, dy, dz )
2. Поворот на угол angle вокруг оси Ox, Oy или Oz:
glRotatef ( angle, ox, oy, oz )
3. Масштабирование вдоль осей в sx, sy и sz раз:
glScalef ( sx, sy, sz )
Эти преобразования изменяют текущую систему координат, которая
определяется модельно-видовой матрицей. Для того, чтобы сохранить или
восстановить текущее состояние модельно-видовой матрицы можно
использовать команды glPushMatrix() и glPopMatrix(). Команда
glLoadIdentity() восстанавливает исходное (единичное) состояние матрицы.
В том случае, когда требуется применить модельно-видовые
преобразования не для всех объектов, а только для части, необходимо перед
их заданием:
1. Сохранить текущее состояние.
2. Применить нужное модельно-видовое преобразование.
3. Вернуть исходное состояние.
13
Практическая часть.
1. В соответствии с заданием отобразить объекты, вершины которых
определяются кликами мыши.
2. Предусмотреть возможность изменения цвета и текстуры данного
объекта и применение модельно-видовых преобразований.
3. Вывести на экране крупную сетку условных пикселей и растеризовать
на ней заданные объекты.
4. Предусмотреть включение и выключение логических операций
смешивания цветов (в соответствии с вариантом задания) и объяснить
полученный результат.
5. Для повышения уровня сложности нужно:
1) реализовать алгоритм сглаживания;
2) реализовать дополнительные логические операции;
3) добавить новый объект - круг;
4) использовать меню.
Варианты заданий.
1. Объекты: треугольники. Операции: AND и NOT AND.
2. Объекты: выпуклые четырехугольники. Операции: AND и NOT AND.
3. Объекты: выпуклые многоугольники. Операции: AND и NOT AND.
4. Объекты: треугольники. Операции: OR и NOT OR.
5. Объекты: выпуклые четырехугольники. Операции: OR и NOT OR.
6. Объекты: выпуклые многоугольники. Операции: OR и NOT OR.
7. Объекты: треугольники. Операции: XOR и NOT XOR.
8. Объекты: выпуклые четырехугольники. Операции: XOR и NOT XOR.
9. Объекты: выпуклые многоугольники. Операции: XOR и NOT XOR.
Контрольные вопросы и задания.
1. Векторные и растровые изображения.
2. Алгоритмы растеризации.
3. Текстурирование.
4. Модельно-видовые преобразования.
5. Логические операции над цветами.
14
1/--страниц
Пожаловаться на содержимое документа