Открыть Электронные книги
Категории
Открыть Аудиокниги
Категории
Открыть Журналы
Категории
Открыть Документы
Категории
С. Н. Баранов, С. Г. Толкач
Учебное пособие
Красноярск
СФУ
2018
УДК 004.92(07)
ББК 32.973я73
Б241
Р е ц е н з е н т ы:
Пак Н. И., доктор педагогических наук, профессор, заведующий
кафедрой информатики и информационных технологий в образовании
Красноярского государственного педагогического университета
им. В.П. Астафьева;
Исаев С. В., кандидат технических наук, доцент, заместитель дирек-
тора по научной работе ИВМ СО РАН – ОП ФИЦ КНЦ СО РАН
Баранов, С. Н.
Б241 Основы компьютерной графики : учеб. пособие / С. Н. Баранов,
С. Г. Толкач. – Красноярск : Сиб. федер. ун-т, 2018. – 88 с.
ISBN 978-5-7638-3968-5
3
Компьютерная графика ‒ область деятельности, в которой изо-
бражения создаются с помощью компьютерных технологий. Компью-
терная графика используется в научной деятельности для иллюстри-
рования результатов экспериментов, построения графиков, диаграмм
и чертежей. С развитием компьютерных технологий расширяются и
сферы применения компьютерной графики.
Настоящее учебное пособие предназначено для ознакомления
студентов с основами компьютерной графики. В пособии рассмотре-
ны основные функции графической библиотеки OpenGL, подробно
описаны примеры создания приложений, использования графических
примитивов, установки различных параметров и т. д. Пособие содер-
жит иллюстрации результатов работы программ, которые демонстри-
руют различные функции графической библиотеки OpenGL.
Все примеры выполнены в среде разработки Visual Studio 2015
на языке программирования C++.
В первой главе идет речь о библиотеке OpenGL. Приводятся
примеры создания приложений с помощью библиотеки «glaux.h» или
библиотеки «glut.h». Далее обозначаются основные функции уста-
новки цвета, приведено описание графических примитивов.
Во второй главе даны простейшие геометрические преобразова-
ния и демонстрируются примеры установки перспективных проекций,
работы с камерой, обработки нажатия клавиш клавиатуры и измене-
ния положения камеры.
В третьей главе представлены алгоритмы построения графиков
алгебраических функций и их производных, алгоритмы построения
функций, заданных в параметрическом виде. Рассмотрены примеры
вывода графиков функций от двух переменных в трехмерном про-
странстве. Также приведены функции установки освещения, алгорит-
мы наложения текстур на графические примитивы и алгоритмы при-
менения списков отображения для оптимизации работ приложения.
4
В четвертой главе приведены примеры использования трехмер-
ных объектов из библиотеки «glaux.h», а также примеры построения
3D-сцены из своих 3D-объектов. Далее следуют иллюстрации основ-
ных геометрических фракталов и рассмотрены алгоритмы построения
фракталов с помощью графических примитивов.
В завершение представлены примеры практических работ, кото-
рые должны быть выполнены для закрепления пройденного материала.
Настоящее пособие поможет успешно освоить основные алго-
ритмы и понятия компьютерной графики и позволит применять
функции библиотеки OpenGL для создания графических приложений
с использованием простейших примитивов, текстур и геометрических
преобразований.
5
OpenGL (Open Graphics Library ‒ открытая графическая библио-
тека, графическое API) ‒ спецификация, определяющая независимый
от языка программирования платформонезависимый программный
интерфейс для написания приложений, использующих двухмерную и
трехмерную компьютерную графику.
Библиотека OpenGL была разработана как независимый от аппа-
ратного обеспечения интерфейс, поэтому не содержит функций для
создания окон или для обработки пользовательского ввода. Для этих
операций должны применяться средства той операционной системы, в
которой создается приложение. По тем же причинам в OpenGL нет
высокоуровневых функций для описания моделей трехмерных объек-
тов. При обращении к библиотеке OpenGL необходимо пользоваться
набором геометрических примитивов – точек, линий и многоугольни-
ков – и с их помощью создавать более сложные объекты.
Основные графические операции, которые выполняет OpenGL
для вывода изображения на экран:
• конструирует фигуры из геометрических примитивов (прими-
тивами в OpenGL являются точки, линии, полигоны, битовые
карты и изображения);
• позиционирует объекты в трехмерном пространстве и выбира-
ет точку наблюдения для осмотра полученной композиции;
• вычисляет цвета для всех объектов; цвета могут быть опреде-
лены приложением, получены из расчета условий освещенно-
сти, вычислены при помощи текстур, наложенных на объекты
или из любой комбинации этих факторов;
• преобразует математическое описание объектов и ассоцииро-
ванной с ними цветовой информации в пиксели на экране.
6
Этот процесс называется растеризацией (или растровой раз-
верткой).
Рассмотрим пример приложения, созданного в Visual Studio
2015, с использованием библиотеки «glaux.h». Необходимо создать
пустой проект, имеющий тип Консольное приложение Win32, далее
нужно скопировать в директорию с исходниками файлы GLAUX.H и
GLAUX.LIB, после чего добавить в проект файл исходного кода и
внести в него текст из примера 1.
Пример 1. Первое приложение с использованием библиоте-
ки «glaux.h»
#include "glaux.h"
using namespace std;
// подключение предкомпилированных библиотек
#pragma comment (lib, "opengl32.lib")
#pragma comment (lib, "glu32.lib")
#pragma comment (lib, "glaux.lib")
// подключение библиотеки legacy_stdio_definitions
// для Visual Studio 2015 и выше
#pragma comment(lib, "legacy_stdio_definitions.lib")
// функция вызывается при изменении размеров окна
void CALLBACK resize(int width, int height)
{
// установка области вывода
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION); //выбор матрицы проекции
glLoadIdentity(); // сброс текущей матрицы преобразований
// установка перспективы
gluPerspective(45.0, (GLfloat)width / height, 1.0, 100.0);
// установка камеры
gluLookAt(0, 0, 5, 0, 0, 0, 0, 1, 0);
glMatrixMode(GL_MODELVIEW); // выбор матрицы отображения
glEnable(GL_DEPTH_TEST); // установка теста глубины
}
// функция вызывается при рисовании
void CALLBACK display(void)
{ // очистка цвета и глубины
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); // сброс текущей матрицы преобразований
// начало рисования примитива "четырехугольник"
glBegin(GL_QUADS);
glVertex3d(–1, –1, 0); // задание вершины примитива
glVertex3d(–1, 1, 0); // задание вершины примитива
glVertex3d(1, 1, 0); // задание вершины примитива
7
glVertex3d(1, –1, 0); // задание вершины примитива
glEnd(); // окончание рисования примитива
// обмен переднего и заднего буферов, вывод на экран
auxSwapBuffers();
}
// основная функция программы
void main()
{ // задание позиции и размеров окна
auxInitPosition(0, 0, 800, 600);
// установка режима отображения
auxInitDisplayMode(AUX_RGB | AUX_DEPTH | AUX_DOUBLE);
auxInitWindow(L"Glaux Template"); // инициализация окна
auxIdleFunc(display); // задание функции рисования
// задание функции изменения размеров окна
auxReshapeFunc(resize);
glClearColor(0, 0, 0, 0.5);// задание цвета очистки экрана
// задание параметра очистки буфера глубины
glClearDepth(1.0);
auxMainLoop(display); // вызов основного цикла приложения
}
8
проект, имеющий тип Консольное приложение Win32, далее добавить
в проект файл исходного кода и внести в него текст из примера 2.
Пример 2. Приложение с использованием библиотеки «glut.h»
#include <GL/glut.h>
void display(void)
{ // Очистить экран
glClear(GL_COLOR_BUFFER_BIT);
// Нарисовать белый полигон (квадрат) с углами
// в (0.25, 0.25, 0.0) и (0.75, 0.75, 0.0)
glColor3f(1.0, 1.0, 1.0);
glBegin(GL_POLYGON);
glVertex3f(0.25, 0.25, 0.0);
glVertex3f(0.75, 0.25, 0.0);
glVertex3f(0.75, 0.75, 0.0);
glVertex3f(0.25, 0.75, 0.0);
glEnd();
glFlush();
}
// Установить начальные характеристики окна, открыть окно с
заголовком //«hello». Зарегистрировать дисплейную функцию об-
ратного вызова
// Войти в главный цикл
int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB);
glutInitWindowSize(250, 250);
glutInitWindowPosition(100, 100);
glutCreateWindow(“hello”);
init();
glutDisplayFunc(display);
glutMainLoop();
return 0;
}
9
В аддитивной цветовой модели задаются три основных цвета, а
любой другой цвет представляется как взвешенная сумма трех основ-
ных цветов. Широко известная цветовая модель RGB является адди-
тивной цветовой моделью (сокращенно от Red, Green, Blue ‒ красный,
зеленый, синий).
Другая модель смешения цветов ‒ субтрактивная цветовая мо-
дель, или модель CMYK (CMY), использующая в качестве первичных
составляющих цвета Cyan, Magenta, Yellow (голубой, пурпурный,
желтый), которые являются дополнительными к Red, Green, Blue.
Связь между значениями (R, G, B) и (C, M, Y) для одного и того же
цвета выражается формулой:
R C 1
G M 1
B Y 1
.
На рис. 2 демонстрируются примеры получения некоторых цве-
тов в указанных цветовых моделях.
10
ры задают красный, зеленый и синий компоненты цвета соответст-
венно.
Пример 3. Задание разных цветов
glColor3f(0.0,0.0,0.0); черный
glColor3f(1.0,0.0,0.0); красный
glColor3f(0.0,1.0,0.0); зеленый
glColor3f(1.0,1.0,0.0); желтый
glColor3f(0.0,0.0,1.0); синий
glColor3f(1.0,0.0,1.0); фиолетовый
glColor3f(0.0,1.0,1.0); голубой
glColor3f(1.0,1.0,1.0); белый
11
Для каждой вершины можно указывать от двух до четырех ко-
ординат и задавать тип, используемый для описания значения коор-
динаты (short, int, float, double).
Существует несколько разных версий этой функции:
12
• GL_POLYGON – граница простого выпуклого полигона.
На рис. 4 и 5 представлены все виды примитивов, которые мож-
но нарисовать с помощью функции glBegin().
13
Приведем перечень команд, которые допускается использовать
между glBegin() и glEnd():
glVertex*() – установка координат вершины;
glColor*() – установка текущего цвета;
glIndex*() – установка текущего цветового индекса;
glNormal*() – установка координат вектора нормали;
glTexCoord*() – установка координат текстуры;
glMultiTexCoord*ARB() – установка координат текстуры при
мультитекстурировании;
glEdgeFlag*() – контроль рисования ребер;
glMaterial*() – установка свойств материала;
glArrayElement() – выделение данных из массива вершин;
glEvalCoords*(), glEvalPoint*() – генерация координат;
glCallList(), glCallLists() – выполнение списка ото-
бражения.
В примере 5 рассмотрен вывод примитива «Точки» с заданием
размеров точек, сглаживанием и установкой цвета. На рис. 6 пред-
ставлен результат выполнения программы.
Пример 5. Задание рисования примитива «Точки»
glPointSize(20); // установка размера точки
glEnable(GL_POINT_SMOOTH); // включение сглаживания точки
glEnable(GL_BLEND); // включение наложения цветов
// задание функции наложения
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBegin(GL_POINTS); // начало примитива «точки»
glColor3d(1, 1, 1); // установка цвета
glVertex2f(0.0, 0.0); // установка вершины
glColor3d(1, 0, 0); // установка цвета
glVertex2f(0.0, 3.0); // установка вершины
glColor3d(0, 1, 0); // установка цвета
glVertex2f(4.0, 3.0); // установка вершины
glColor3d(0, 0, 1); // установка цвета
glVertex2f(6.0, 1.5); // установка вершины
glVertex2f(4.0, 0.0); // установка вершины
glEnd(); // окончание примитива «точки»
16
В примере 8 реализована функция рисования окружности с ис-
пользованием примитива «Линии». Для использования тригономет-
рических функций подключается библиотека математических функ-
ций <math.h>.
Пример 8. Функция рисования окружности
#include <math.h>
void DrawCircle(GLdouble x, GLdouble y, GLdouble z, GLdouble
radius, GLdouble r, GLdouble g, GLdouble b)
// передаются координаты центра, радиус и цвет окружности
{
glColor3d(r, g, b);
int n = 60;
glBegin(GL_LINE_LOOP);
for (int i = 0; i<n; i++)
glVertex3d(x + radius*sin(i * 2 * 3.14 / n),
y + radius*cos(i * 2 * 3.14 / n), z);
glEnd();
}
17
Результаты работы программ из примеров 8 и 9 приведены на
рис. 9.
18
На практике довольно часто возникают задачи, требующие реа-
лизации передвижений или преобразований изображений. Рассмот-
рим типы базовых преобразований, позволяющих осуществлять такие
действия.
Преобразование плоскости называется аффинным, если оно вза-
имно-однозначно и образом любой прямой линии является прямая
линия.
Преобразование называется взаимно-однозначным, если разные
точки переходят в разные точки и в каждую точку переходит какая-
либо точка. На рис. 10 и 11 проиллюстрированы примеры аффинных
преобразований.
19
В OpenGL применяются следующие виды преобразований:
• сжатие/растяжение,
• поворот,
• параллельный перенос,
• отражение.
Каждое из приведенных преобразований имеет простой и нагляд-
ный геометрический смысл. Любое преобразование всегда можно пред-
ставить как последовательное исполнение простейших преобразований.
Функция glTranslate() вносит дополнительное смещение в
текущую матрицу. Эта функция имеет три параметра: x, y, z – коор-
динаты вектора сдвига. Она принимает следующие формы:
glTranslated(GLdouble x, GLdouble y, GLdouble z);
glTranslatef(GLfloat x, GLfloat y, GLfloat z);
20
кущую матрицу преобразований на единичную матрицу. Обычно она
используется в начале формирования кадра.
Функции glPushMatrix() и glPopMatrix() предназначены
для помещения матриц в стек и извлечения из него.
Пример 10. Рисование куба, состоящего из сетки
// функция рисования сетки из линий заданного цвета
void DrawGrid(GLdouble r, GLdouble g, GLdouble b)
{
GLdouble dx = 1;
for (int i = -10; i <= 10; i++)
DrawLine(vertex3{ i*dx, -10, 0 },
vertex3{ i*dx, 10, 0 },
color3{ r, g, b });
}
21
Рис. 12. Сеточный куб
22
tom, top ‒ координаты для нижней и верхней горизонтальных плоско-
стей отсечения. Параметры zNear, zFar ‒ расстояния до ближней и
дальней плоскостей отсечения в глубину. Оба расстояния должны
быть положительными (см. рис. 14).
23
Рассмотрим функцию установки камеры:
void gluLookAt(GLdouble eyex, GLdouble eyey, GLdouble eyez,
GLdouble atx, GLdouble aty, GLdouble atz, GLdouble upx,
GLdouble upy, GLdouble upz);
24
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity(); // сброс текущей матрицы преобразований
ex = rz*sin(anglez);
ez = rz*cos(anglez);
gluLookAt(ex, ey, ez, ax, ay, az, 0, 1, 0);
// рисование кадра
auxSwapBuffers(); // обмен буфера, вывод на экран
}
// описание функций нажатия клавиш клавиатуры
void CALLBACK PressKeyA(void) // шаг по кругу
{
anglez += 0.1;
}
void CALLBACK PressKeyD(void) // шаг по кругу
{
anglez –= 0.1;
}
void CALLBACK PressKeyW(void) // шаг вперед
{
rz –= 1;
}
void CALLBACK PressKeyS(void) // шаг назад
{
rz += 1;
}
void CALLBACK PressKeyQ(void) // шаг вверх
{
ey += 1;
}
void CALLBACK PressKeyE(void) // шаг вниз
{
ey –= 1;
}
// основная функция программы
void main()
{
// инициализация OpenGL
auxKeyFunc(AUX_w, PressKeyW);
auxKeyFunc(AUX_s, PressKeyS);
auxKeyFunc(AUX_a, PressKeyA);
auxKeyFunc(AUX_d, PressKeyD);
auxKeyFunc(AUX_q, PressKeyQ);
auxKeyFunc(AUX_e, PressKeyE);
25
auxMainLoop(display); // вызов основного цикла приложения
}
// рисование кадра
auxSwapBuffers(); // обмен буфера, вывод на экран
}
// описание функций нажатия клавиш клавиатуры
void CALLBACK PressKeyD(void) // шаг вправо
{
float dx, dz, a = 3.14 / 2;
float cx_ = (aX – eX)*cos(a) – (aZ – eZ)*sin(a);
26
float cz_ = (aX – eX)*sin(a) + (aZ – eZ)*cos(a);
dx = cx_*moveK; dz = cz_*moveK;
eX = eX + dx; aX = aX + dx;
eZ = eZ + dz; aZ = aZ + dz;
}
void CALLBACK PressKeyA(void) // шаг влево
{
float dx, dz;
float a = –3.14 / 2;
float cx_ = (aX – eX)*cos(a) – (aZ – eZ)*sin(a);
float cz_ = (aX – eX)*sin(a) + (aZ – eZ)*cos(a);
dx = cx_*moveK;
dz = cz_*moveK;
eX = eX + dx; aX = aX + dx;
eZ = eZ + dz; aZ = aZ + dz;
}
void CALLBACK PressKeyW(void) // шаг вперед
{
float dx, dz;
dx = (aX – eX)*moveK;
dz = (aZ – eZ)*moveK;
eX = eX + dx;
aX = aX + dx;
eZ = eZ + dz;
aZ = aZ + dz;
}
void CALLBACK PressKeyS(void) // шаг назад
{
float dx, dz;
dx = –(aX – eX)*moveK;
dz = –(aZ – eZ)*moveK;
eX = eX + dx;
aX = aX + dx;
eZ = eZ + dz;
aZ = aZ + dz;
}
void CALLBACK PressKeyE(void) // поворот направо
{
float a = 3.14 / 180 * 2;
float cx_ = (aX – eX)*cos(a) – (aZ – eZ)*sin(a);
float cz_ = (aX – eX)*sin(a) + (aZ – eZ)*cos(a);
aX = cx_ + eX; aZ = cz_ + eZ;
}
void CALLBACK PressKeyQ(void)// поворот налево
{
27
float a = –3.14 / 180 * 2;
float cx_ = (aX – eX)*cos(a) – (aZ – eZ)*sin(a);
float cz_ = (aX – eX)*sin(a) + (aZ – eZ)*cos(a);
aX = cx_ + eX; aZ = cz_ + eZ;
}
void CALLBACK PressKeyZ(void)// шаг вверх
{
eY += 1; aY += 1;
}
void CALLBACK PressKeyX(void) // шаг вниз
{
eY –= 1; aY –= 1;
}
// основная функция программы
void main()
{ // инициализация OpenGL
auxKeyFunc(AUX_w, PressKeyW); auxKeyFunc(AUX_s, PressKeyS);
auxKeyFunc(AUX_a, PressKeyA); auxKeyFunc(AUX_d, PressKeyD);
auxKeyFunc(AUX_q, PressKeyQ); auxKeyFunc(AUX_e, PressKeyE);
auxKeyFunc(AUX_z, PressKeyZ); auxKeyFunc(AUX_x, PressKeyX);
auxMainLoop(display); // вызов основного цикла приложения
}
28
В данном параграфе рассмотрим пример вывода графиков функ-
ций с помощью простейших геометрических примитивов.
Пример 13. Рисование графика функций
void DrawLine(float x1, float y1, float x2, float y2)
{
glLineWidth(2);
glColor3d(1, 1, 1);
glBegin(GL_LINES);
glVertex2d(x1, y1);
glVertex2d(x2, y2);
glEnd();
}
float f(float x)
{
return (sin(x));
}
void DrawOs()
{
glPushMatrix();
double dx = 2;
DrawLine(–10 * dx, 0, 10 * dx, 0);
DrawLine(0, –10 * dx, 0, 10 * dx);
for (int i = –10; i <= 10; i++)
{
DrawLine(i*dx, 0.1*dx, i*dx, –0.1*dx);
DrawLine(0.1*dx, i*dx, –0.1*dx, i*dx);
}
glPopMatrix();
}
void DrawFunc()
{
29
float x, x1 = –10, x2 = 10, dx = (x2 – x1) / n;
int n = 100;
DrawOs();
glPointSize(3);
glBegin(GL_POINTS); // рисование точек
// glBegin(GL_LINE_STRIP); // рисование линий
glColor3f(1, 0, 0);
for (x = x1; x <= x2; x += dx)
glVertex3f(x, f(x), 0);
glEnd();
}
31
// Вычисление производной функции
void CalcDFuncMas(float **mas, float **dmas, float dx)
{
for (int i = 0; i<masSize; i++)
{
dmas[0][i] = mas[0][i];
if (i<masSize – 1)
dmas[1][i] = (mas[1][i + 1] – mas[1][i]) / dx;
else
dmas[1][i] = (mas[1][i] – mas[1][i – 1]) / dx;
}
}
// Вычисление интеграла функции
float CalcFFuncMas(float **mas, int n, float dx)
{
float res = 0;
for (int i = 0; i<n – 1; i++)
res += (mas[1][i + 1] + mas[1][i]) / 2 * dx;
return res;
}
32
Пример 15. Вывод функции, заданной в параметрическом
виде
void DrawFuncParam(){
float t1 = 0, t2 = 4 * 3.14, dt = 0.01;
float t = t1, x, y; float xScale = 3, yScale = 3;
DrawOs();
glBegin(GL_LINE_STRIP);
glColor3f(1, 1, 1);
while (t<t2){
x = sin(2 * t); y = cos(3 * t);
glVertex3f(x * xScale, y * yScale, 0);
t += dt;
} glEnd();
}
33
Рис. 22. График функции x = 16*sin(t)*sin(t)*sin(t); y = 13*cos(t)–5*cos(2*t)–
2*cos(3*t)–cos(4*t)
34
DrawOs();
glRotated(90, 0, 1, 0);
DrawOs();
glPointSize(2);
glBegin(GL_POINTS); // рисование точек
glColor3f(1, 0, 0);
for (x = x1; x <= x2; x += dx)
for (y = y1; y <= y2; y += dy)
{
glVertex3f(x, f2(x, y), y);
}
glEnd();
for (x = x1; x <= x2; x += dx)
{
glBegin(GL_LINE_STRIP); // рисование линий
for (y = y1; y <= y2; y += dy)
glVertex3f(x, f2(x, y), y);
glEnd();
}
for (y = y1; y <= y2; y += dy)
{
glBegin(GL_LINE_STRIP); // рисование линий
for (x = x1; x <= x2; x += dx)
glVertex3f(x, f2(x, y), y);
glEnd();
}
for (x = x1; x <= x2; x += dx)
for (y = y1; y <= y2; y += dy)
{
// рисование полигонов
DrawQuad(vertex3{ x, f2(x, y), y },
vertex3{ x + dx, f2(x + dx, y), y },
vertex3{ x + dx, f2(x + dx, y + dy),
y + dx },
vertex3{ x, f2(x, y + dx), y + dy },
color3{ 0, 0, 1 });
}
}
35
Рис. 23. Рисование графика функций точками
36
3.2. Установка освещения
37
GLfloat light_position1[] = { –9.0,–9.0,5.0,0.0 };
glLightfv(GL_LIGHT0, GL_POSITION, light_position1);
glLightfv(GL_LIGHT0, GL_DIFFUSE, light1);
GL_LIGHT0, GL_LIGHT1, …, GL_LIGHT7 – источники света
// включение источника света
glEnable(GL_LIGHT0);
// включение освещения
glEnable(GL_LIGHTING);
// выключение освещения
glDisable(GL_LIGHTING);
39
Как видно из примера, добавленный источник синего света бу-
дет направлен на левую сторону сферы. Результаты работы данной
программы продемонстрированы на рис. 28.
40
OpenGL поддерживает одно- и двумерные текстуры и различные
способы наложения текстуры. Функция glTexImage2D() определяет
двумерную текстуру. Рассмотрим эту функцию подробнее.
glTexImage2D(GL_TEXTURE_2D, 0, 3, texture1–>sizeX,
texture1–>sizeY, 0, GL_RGB, GL_UNSIGNED_BYTE, texture1–>data);
41
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR);
// создание текстуры
glTexImage2D(GL_TEXTURE_2D, 0, 3, texture1–>sizeX,
texture1–>sizeY, 0,GL_RGB, GL_UNSIGNED_BYTE, texture1–>data);
}
42
четырехугольник. На рис. 31 проиллюстрирован пример наложения
текстуры с произвольными текстурными координатами.
43
glTexImage2D(GL_TEXTURE_2D, 0, 3, txt–>sizeX, txt–>sizeY, 0,
GL_RGB, GL_UNSIGNED_BYTE, txt–>data);
delete txt;
}
Важные замечания:
• для правильной загрузки текстуры из файла необходимо, что-
бы размеры картинки, находящейся в файле, в пикселах были
кратны степени 2. Например, картинка может быть размером
256 на 256 пикселов;
• текстурные координаты изменяются в пределах от 0 до 1, и в
левом нижнем углу находится начало координат внутри тек-
стуры (рис. 30, 31).
44
Функция glGenLists(n) создает место для n списков и воз-
вращает указатель на первый из них.
Функция glNewList(GLuint list, GLenum mode) марки-
рует начало списка отображения. Первый параметр – место хране-
ния списка, на которое указывает переменная list. Второй пара-
метр – режим создания списка, он может принимать одно из двух
значений GL_COMPILE или GL_COMPILE_AND_EXECUTE. Ис-
пользуя значение GL_COMPILE, OpenGL создаст список в памяти,
но команды при этом не выполнятся. Используя значение
GL_COMPILE_AND_EXECUTE, OpenGL создаст список в памяти
и выполнит его команды первый раз на этапе создания. Функция
glEndList() маркирует конец списка отображения.
Функция glCallList(GLuint list) исполняет список ото-
бражения, заданный аргументом list. Команды в списке исполняются
в том порядке, в котором они сохранялись, таким же образом, как ес-
ли бы они выполнялись вне списка.
Пример 23. Создание списка отображения
GLvoid BuildLists()
{
GLuint quad;
box = glGenLists(2); // создаем два списка
quad = box + 1;
// Новый откомпилированный список
glNewList(quad, GL_COMPILE);
glBegin(GL_QUADS);
glTexCoord2f(0, 0);
glVertex3f(0, 0, 0);
glTexCoord2f(0, 1);
glVertex3f(0, 1, 0);
glTexCoord2f(1, 1);
glVertex3f(1, 1, 0);
glTexCoord2f(1, 0);
glVertex3f(1, 0, 0);
glEnd(); // Закончили рисование четырехугольников
glEndList(); // Закончили создание списка
45
glCallList(quad);
glTranslated(0, 0, 1);
glCallList(quad);
glRotated(90, 0, 1, 0);
glCallList(quad);
glTranslated(0, 0, 1);
glCallList(quad);
glTranslated(0, 1, –1);
glRotated(90, 1, 0, 0);
glBindTexture(GL_TEXTURE_2D, texture[1]);
glCallList(quad);
glTranslated(0, 0, 1);
glCallList(quad);
glPopMatrix();
glDisable(GL_TEXTURE_2D);
glEndList(); // Закончили создание списка box
}
46
Пример 24. Вызов списка отображения
GLvoid DrawPyramide()
{
glPushMatrix();
int n = 5; int m = 5;
int mas[6][3] = { { 1,0,0 },{ 0,1,0 },{ 0,0,1 },
{ 1,1,0 },{ 0,1,1 },{ 1,0,1 } };
for (int j = 0; j <= n; j++)
{
for (int i = –m; i <= m; i++)
for (int k = –m; k <= m; k++)
{
glPushMatrix();
glTranslated(i, j, k);
glColor3d(mas[m][0], mas[m][1], mas[m][2]);
glCallList(box);
glPopMatrix();
}
m––;
}
glPopMatrix();
}
47
Функция glDeleteLists (GLuint list, GLsizei range)
удаляет последовательные (по индексам) списки отображения, начи-
ная с индекса list. Количество удаляемых списков задается парамет-
ром range. После вызова функции glDeleteLists() индексы удаленных
списков становятся доступны для дальнейшего использования.
48
В модуле «glaux.h» реализовано множество трехмерных геомет-
рических фигур. На рис. 34 приведены некоторые из них.
51
Таблица 1
Функции рисования геометрических фигур «glaux.h»
Функция Описание
auxSolidBox(width, height, depth) параллелепипед со сторонами width, height,
auxWireBox(width, height, depth) depth
auxSolidTorus(r,R) тор, образованный с помощью вращения
auxWireTorus(r,R) окружностей; задаются малый и большой
радиусы r, R
auxSolidCylinder(r,height) цилиндр с радиусом основания r и высотой
auxWireCylinder(r,height) height
auxSolidCone(r,height) конус с радиусом основания r и высотой
auxWireCone(r,height) height
auxSolidIcosahedron(width) правильные многогранники; задается диа-
auxWireIcosahedron(width) метр описанной окружности width
auxSolidOctahedron(width)
auxSolidOctahedron(width)
auxSolidTetrahedron(width)
auxSolidTetrahedron(width)
auxSolidDodecahedron(width)
auxSolidDodecahedron(width)
auxSolidTeapot(width) чайник; задается размер объекта
auxWireTeapot(width)
53
}
// создание структуры текстурной координаты
tvertex2 tvertex(float x, float y)
{
tvertex2 tv = { x, y };
return tv;
}
// создание структуры линии
line2 line(int p1, int p2)
{
line2 l;
l.p1 = p1; l.p2 = p2;
return l;
}
// создание структуры треугольника
triangle3 triangle(int p1, int p2, int p3)
{
triangle3 t;
t.p1 = p1; t.p2 = p2; t.p3 = p3;
return t;
}
// создание структуры четырехугольника
quad4 quad(int p1, int p2, int p3, int p4)
{
quad4 q;
q.p1 = p1; q.p2 = p2; q.p3 = p3; q.p4 = p4;
return q;
}
55
Пример 31. Описание и реализация класса Point, наслед-
ника базового класса Item
class Point : public Item
{
public:
Point(vertex3 pos, color3 color, float size);
virtual void Draw();
};
Point::Point(vertex3 pos, color3 color, float size) :Item()
{
SetPos(pos); SetColor(color); SetSize(size);
}
void Point::Draw()
{
glPointSize(size);
glColor3d(color.r, color.g, color.b);
glPushMatrix();
glTranslated(pos.x, pos.y, pos.z);
glBegin(GL_POINTS);
glVertex3d(0, 0, 0);
glEnd();
glPopMatrix();
}
56
:Point(pos1, color, size)
{
this–>pos2 = pos2;
color2 = color;
}
Line::Line(vertex3 pos1, vertex3 pos2, color3 color, color3
color2, float size) : Point(pos1, color, size)
{
this–>pos2 = pos2;
this–>color2 = color2;
}
void Line::Draw()
{
glPushMatrix();
Rotate();
glLineWidth(size);
glBegin(GL_LINES);
glColor3d(color.r, color.g, color.b);
glVertex3d(pos.x, pos.y, pos.z);
glColor3d(color2.r, color2.g, color2.b);
glVertex3d(pos2.x, pos2.y, pos2.z);
glEnd();
glPopMatrix();
glPopMatrix();
}
57
Triangle(vertex3 pos1, vertex3 pos2, vertex3 pos3, color3
color, color3 color2, color3 color_3);
virtual void Draw();
};
Triangle::Triangle(vertex3 pos1, vertex3 pos2, vertex3 pos3,
color3 color) :Line(pos1, pos2, color, size)
{
this–>pos3 = pos3;
color_3 = color;
}
Triangle::Triangle(vertex3 pos1, vertex3 pos2, vertex3 pos3,
color3 color, color3 color2, color3 color_3) : Line(pos1, pos2,
color, color2, size)
{
this–>pos3 = pos3; this–>color_3 = color_3;
}
void Triangle::Draw()
{
glPushMatrix();
Rotate();
glBegin(GL_TRIANGLES);
glColor3d(color.r, color.g, color.b);
glVertex3d(pos.x, pos.y, pos.z);
glColor3d(color2.r, color2.g, color2.b);
glVertex3d(pos2.x, pos2.y, pos2.z);
glColor3d(color_3.r, color_3.g, color_3.b);
glVertex3d(pos3.x, pos3.y, pos3.z);
glEnd();
glPopMatrix();
glPopMatrix();
}
58
// конструктор с координатами, цветом и размером
Quad(vertex3 pos1, vertex3 pos2, vertex3 pos3, vertex3 pos4,
color3 color);
// конструктор с координатами, четырьмя цветами и размером
Quad(vertex3 pos1, vertex3 pos2, vertex3 pos3, vertex3 pos4,
color3 color, color3 color2, color3 color_3, color3 color4);
virtual void Draw();
};
Quad::Quad(vertex3 pos1, vertex3 pos2, vertex3 pos3, vertex3
pos4, color3 color) :Triangle(pos1, pos2, pos3, color)
{
this–>pos4 = pos4;
color4 = color;
}
Quad::Quad(vertex3 pos1, vertex3 pos2, vertex3 pos3, vertex3
pos4, color3 color, color3 color2, color3 color_3, color3 col-
or4) : Triangle(pos1, pos2, pos3, color, color2, color_3)
{
this–>pos4 = pos4;
this–>color4 = color4;
}
void Quad::Draw()
{
glPushMatrix(); Rotate();
glBegin(GL_QUADS);
glColor3d(color.r, color.g, color.b);
glVertex3d(pos.x, pos.y, pos.z);
glColor3d(color2.r, color2.g, color2.b);
glVertex3d(pos2.x, pos2.y, pos2.z);
glColor3d(color_3.r, color_3.g, color_3.b);
glVertex3d(pos3.x, pos3.y, pos3.z);
glColor3d(color4.r, color4.g, color4.b);
glVertex3d(pos4.x, pos4.y, pos4.z);
glEnd();
glPopMatrix();
glPopMatrix();
}
59
Пример 35. Описание и реализация класса QuadT, наслед-
ника класса Quad
class QuadT : public Quad
{
protected:
tvertex2 tv1, tv2, tv3, tv4;
string name_texture;
public:
QuadT(vertex3 pos1, vertex3 pos2, vertex3 pos3, vertex3 pos4,
color3 color, string name_texture);
QuadT(vertex3 pos1, vertex3 pos2, vertex3 pos3, vertex3 pos4,
color3 color, string name_texture, tvertex2 tv1, tvertex2 tv2,
tvertex2 tv3, tvertex2 tv4);
virtual void Draw();
};
QuadT::QuadT(vertex3 pos1, vertex3 pos2, vertex3 pos3, vertex3
pos4, color3 color, string name_texture) :Quad(pos1, pos2,
pos3, pos4, color)
{
this–>name_texture = name_texture;
this–>tv1 = tvertex(0, 0); this–>tv2 = tvertex(0, 1);
this–>tv3 = tvertex(1, 1); this–>tv4 = tvertex(1, 0);
}
QuadT::QuadT(vertex3 pos1, vertex3 pos2, vertex3 pos3, vertex3
pos4, color3 color, string name_texture, tvertex2 tv1, tvertex2
tv2, tvertex2 tv3, tvertex2 tv4) :Quad(pos1, pos2, pos3, pos4,
color)
{
this–>name_texture = name_texture;
this–>tv1 = tv1; this–>tv2 = tv2;
this–>tv3 = tv3; this–>tv4 = tv4;
}
void QuadT::Draw()
{
glPushMatrix();
Rotate();
int tindex = SCENE::getTextureIndex(name_texture);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tindex);
glBegin(GL_QUADS);
glTexCoord2f(tv1.x, tv1.y);
glColor3d(color.r, color.g, color.b);
glVertex3d(pos.x, pos.y, pos.z);
glTexCoord2f(tv2.x, tv2.y);
60
glColor3d(color2.r, color2.g, color2.b);
glVertex3d(pos2.x, pos2.y, pos2.z);
glTexCoord2f(tv3.x, tv3.y);
glColor3d(color_3.r, color_3.g, color_3.b);
glVertex3d(pos3.x, pos3.y, pos3.z);
glTexCoord2f(tv4.x, tv4.y);
glColor3d(color4.r, color4.g, color4.b);
glVertex3d(pos4.x, pos4.y, pos4.z);
glEnd();
glPopMatrix();
glDisable(GL_TEXTURE_2D);
}
61
lines.clear();
quads.clear();
triangles.clear();
}
void Item3D::Draw()
{
glPushMatrix();
Rotate();
if ((drawtype == 0)) // рисование только точками
for (unsigned i = 0; i<points.size(); i++)
DrawPoint(points[i], 10, color);
62
Рис. 38. Диаграмма классов
63
Kub(vertex3 pos, float size, color3 color, int drawtype, int
tindex);
Kub(vertex3 pos, float size, color3 color, vertex3 angle, int
drawtype, int tindex);
void Init();
};
Kub::Kub(vertex3 pos, float size, int drawtype, int tindex)
:Item3D()
{
SetPos(pos);
SetSize(size);
this–>tindex = tindex;
this–>drawtype = drawtype;
Init();
}
Kub::Kub(vertex3 pos, float size, color3 color, int drawtype,
int tindex) :Item3D()
{
SetPos(pos); SetSize(size); SetColor(color);
this–>tindex = tindex;
this–>drawtype = drawtype;
Init();
}
Kub::Kub(vertex3 pos, float size, color3 color, vertex3 angle,
int drawtype, int tindex) :Item3D()
{
SetPos(pos);
SetSize(size);
SetColor(color);
SetAngle(angle);
this–>tindex = tindex;
this–>drawtype = drawtype;
Init();
}
void Kub::Init() // создание вершин, ребер и граней куба
{
GLdouble x0 = pos.x – size / 2,
y0 = pos.y – size / 2, z0 = pos.z – size / 2;
GLdouble dx = size, dy = size, dz = size;
points.push_back(vertex(x0, y0, z0));
points.push_back(vertex(x0 + dx, y0, z0));
points.push_back(vertex(x0 + dx, y0 + dy, z0));
points.push_back(vertex(x0, y0 + dy, z0));
points.push_back(vertex(x0, y0, z0 + dz));
points.push_back(vertex(x0 + dx, y0, z0 + dz));
64
points.push_back(vertex(x0 + dx, y0 + dy, z0 + dz));
points.push_back(vertex(x0, y0 + dy, z0 + dz));
lines.push_back(line(0, 1)); lines.push_back(line(1, 2));
lines.push_back(line(2, 3)); lines.push_back(line(0, 3));
lines.push_back(line(4, 5)); lines.push_back(line(5, 6));
lines.push_back(line(6, 7)); lines.push_back(line(4, 7));
lines.push_back(line(0, 4)); lines.push_back(line(1, 5));
lines.push_back(line(2, 6)); lines.push_back(line(3, 7));
quads.push_back(quad(0, 3, 2, 1));
quads.push_back(quad(1, 2, 6, 5));
quads.push_back(quad(5, 6, 7, 4));
quads.push_back(quad(4, 7, 3, 0));
quads.push_back(quad(2, 3, 7, 6));
quads.push_back(quad(1, 0, 4, 5));
}
65
this–>drawtype = drawtype;
Init();
}
Shere::Shere(vertex3 pos, float size, color3 color, vertex3 an-
gle, int drawtype, int tindex) :Item3D()
{
Item3D();
SetPos(pos);
SetSize(size);
SetColor(color);
SetAngle(angle);
this–>tindex = tindex;
this–>drawtype = drawtype;
Init();
}
void Shere::Init()// создание вершин, ребер и граней сферы
{
int i = 0, j, l, k = 0, q = 0; float a, b;
float R = size / 2; int N = 30;
float da = 2 * 3.1415f / N; float dx = 1; float x, y, z;
for (l = 0; l < N; l++) // формирование точек
for (j = 0; j < N; j++)
{
a = j*da; b = l*da / 2;
x = R * sin(a)*sin(b);
y = R * cos(b);
z = R * cos(a)*sin(b);
points.push_back(vertex(x + pos.x, y + pos.y, z + pos.z));
}
// формирование горизонтальных линий
for (l = 0; l < N; l++)
{
for (j = 0; j < N – 1; j++)
lines.push_back(line(j + l*N, j + 1 + l*N));
lines.push_back(line(l*N, N – 1 + l*N));
}
// формирование вертикальных линий
for (l = 0; l < N – 1; l++)
for (j = 0; j < N; j++)
lines.push_back(line(j + l*N, j + N + l*N));
// формирование полигонов
for (j = 0; j < N – 1; j++)
{
for (l = 0; l < N – 1; l++)
quads.push_back(quad(l + j*N, l + 1 + j*N,
66
l + N + 1 + j*N, l + N + j*N));
quads.push_back(quad(0 + j*N, 0 + N + j*N,
0 + j*N + N + N – 1, 0 + j*N + N – 1));
}
67
textures_index.push_back(value);
textures_names.push_back(name);
}
// поиск текстуры по имени
GLuint TexturesList::getTextureIndex(string name)
{
if (textures_names.size()>0)
for (unsigned i = 0; i<textures_names.size(); i++)
if (textures_names[i].compare(name) == 0)
return textures_index[i];
return –1;
}
68
}
void SCENE::Init()
{
textures = new TexturesList();
textures–>LoadTexture("wall1.bmp");
textures–>LoadTexture("wall2.bmp");
textures–>LoadTexture("Grass32.bmp");
items.push_back(new Line(vertex(–10, 0, 0), vertex(10, 0, 0),
color(1, 1, 1), 1));
items.push_back(new Line(vertex(0, –10, 0), vertex(0, 10, 0),
color(1, 1, 1), 1));
items.push_back(new Line(vertex(0, 0, –10), vertex(0, 0, 10),
color(1, 1, 1), 1));
// points
items.push_back(new Point(vertex(0, 0, 0), color(1, 1, 1),
10));
items.push_back(new Point(vertex(0, 1, 0), color(1, 0, 0), 5));
items.push_back(new Point(vertex(0, –1, 0), color(1, 0, 0),
5));
items.push_back(new Point(vertex(1, 0, 0), color(0, 1, 0), 5));
items.push_back(new Point(vertex(–1, 0, 0), color(0, 0, 1),
5));
// triangles
items.push_back(new Triangle(vertex(–0.5, 0.2, 0), vertex(0,
0.5, 0), vertex(0.5, 0.2, 0), color(0, 1, 0)));
items.push_back(new Triangle(vertex(–0.5, –0.2, 0), vertex(0, –
0.5, 0), vertex(0.5, –0.2, 0), color(1, 0, 0), color(0, 1, 0),
color(0, 0, 1)));
// quads
Quad * quad = new Quad(vertex(–2, –2, 0), vertex(–2, –1, 0),
vertex(–1, –1, 0), vertex(–1, –2, 0), color(1, 0, 0));
quad–>SetAngle(vertex(0, 0, 45));
items.push_back(quad);
items.push_back(new Quad(vertex(–2, 2, 0), vertex(–2, 1, 0),
vertex(–1, 1, 0), vertex(–1, 2, 0), color(1, 0, 0), color(0, 1,
0), color(0, 0, 1), color(0, 1, 1)));
// quadst
items.push_back(new QuadT(vertex(1, 1, 0), vertex(1, 2, 0),
vertex(2, 2, 0), vertex(2, 1, 0), color(1, 1, 1), "wall1.bmp",
tvertex(0, 0), tvertex(0, 1), tvertex(1, 1), tvertex(1, 0)));
items.push_back(new QuadT(vertex(1, 2, 0), vertex(1, 3, 0),
vertex(2, 3, 0), vertex(2, 2, 0), color(1, 0, 0), "wall1.bmp",
tvertex(0, 0), tvertex(0, 0.5), tvertex(0.5, 0.5), tvertex(0.5,
0)));
69
items.push_back(new Kub(vertex(1, 0, 0), 1, color(1, 1, 1), 1,
0));
items.push_back(new Shere(vertex(3, 0, 0), 2, color(1, 1, 1),
1, 0));
}
GLuint SCENE::getTextureIndex(string name)
{
return textures–>getTextureIndex(name);
}
void SCENE::Draw()
{
for (unsigned i = 0; i<items.size(); i++)
items[i]–>Draw();
}
70
Фракталом называют геометрическую фигуру, которая удовле-
творяет одному или нескольким из следующих свойств:
• обладает сложной структурой при любом увеличении;
• является (приближенно) самоподобной;
• обладает дробной хаусдорфовой (фрактальной) размерностью,
которая больше топологической;
• может быть построена рекурсивными процедурами.
В 1904 году швед Хельге фон Кох придумал непрерывную кри-
вую, которая нигде не имеет касательной, причем ее довольно просто
нарисовать. Оказалось, что она обладает свойствами фрактала. Один
из вариантов этой кривой носит название «снежинка Коха» (см.
рис. 42).
71
DrawKox(n – 1, x4, y4, x5, y5);
DrawKox(n – 1, x5, y5, x2, y2);
}
}
72
Рис. 45. H-фрактал
73
Рис. 48. Ковер Серпинского
74
Рис. 50. Множества Жюлиа
75
{
float re = 0, im = 0, i = 0;
bool flag = false;
while (i<100)
{
float re2 = re*re – im*im + (x) / 140.0;
float im2 = 2 * re*im + (y) / 140.0;
re = re2; im = im2;
if (sqrt(re*re + im*im) >= 2)
{
flag = true;
break;
}
i++;
}
if (!flag)
{
glColor3f(1, 1, 1);
glVertex2f(x / 20.0 – 10, y / 20.0 – 10);
}
}
glEnd();
}
76
обозначим рисование единичного отрезка. Символами «+» и «–» обозна-
чены повороты на 60 градусов против и по часовой стрелке соответст-
венно. Получим следующую иллюстрацию фрактала (рис. 53).
Таблица 2
Поколения L-системы «Водоросль»
Поколение Состояние
0 A
1 B
2 AB
3 BAB
4 ABBAB
5 BABABBAB
6 ABBABBABABBAB
7 BABABBABABBABBABABBAB
8 ABBABBABABBABBABABBABABBABBABABBAB
77
Рис. 54. Пример L-системы «дракон Хартера – Хейтвея»
78
size = size / 3;
}
DrawLSystem(s, size); // вывод L-системы
string UseRule(string s, string s1, string r1, string s2 = "",
string r2 = "", string s3 = "", string r3 = "")
{ int n = s.length() – s1.length() + 1; string s0 = "";
string s00;
for (int i = 0; i<n; i++)
{ s00 = s.substr(i, s1.length());
if (s1.compare(s00) == 0) s0 = s0 + r1;
else if ((s2 != "") && (s2.compare(s00) == 0))
s0 = s0 + r2;
else if ((s3 != "") && (s3.compare(s00) == 0))
s0 = s0 + r3;
else s0 = s0 + s[i];
}
return s0;
}
void DrawLSystem(string s, float w)
{ int n = s.length();
for (int i = 0; i<n; i++) {
switch (s[i]) {
case 'F': DrawLine(0, 0, 0, w, 0, 0, 1, 1, 1);
glTranslated(w, 0, 0); break;
case '+': glRotated(60, 0, 0, 1); break;
case '–': glRotated(60, 0, 0, –1); break;
}
}
}
79
Необходимо реализовать программу с использованием библио-
теки OpenGL, которая выводит на экран изображение, созданное из
нескольких графических примитивов (точки, отрезки, ломаные, четы-
рехугольники, треугольники, полигоны, квадраты, прямоугольники,
круги, эллипсы, окружности, дуги и т. д.). В программе должны быть
использованы операции геометрических преобразований: glTranslate,
glRotate, glScale.
Варианты работ:
1. Используя базовые примитивы, создайте один из трех рисунков:
80
4. Используя базовые и собственные графические примитивы,
создайте графические примитивы «Солнышко с лучами» и «Облако».
81
В работе необходимо анимировать примитивы (задать траекто-
рии движения, реализовать вращение).
Варианты работ:
1. Несколько точек двигаются в прямоугольной области и оттал-
киваются от стенок прямоугольника («броуновское движение»).
2. Несколько полигонов вращаются вокруг своей оси и двигают-
ся справа налево и сверху вниз под разными углами («астероидный
поток»).
3. Несколько объектов вращаются относительно центра коорди-
нат, а относительно них вращаются спутники («солнечная система»).
4. Несколько объектов вращаются относительно своей оси и
двигаются по синусоиде слева направо («синусоида»).
5. Придумайте свои траектории движения, алгоритм изменения
размеров и углов поворота.
82
Необходимо реализовать наложение текстур на примитивы и
сделать освещение сцены.
Варианты работ:
1. Несколько точек двигаются в прямоугольной области и оттал-
киваются от стенок прямоугольника («броуновское движение»).
2. Несколько полигонов вращаются вокруг своей оси и двигают-
ся справа налево и сверху вниз под разными углами («астероидный
поток»).
3. Несколько объектов вращаются относительно центра коорди-
нат, а относительно них вращаются спутники («солнечная система»).
4. Несколько объектов вращаются относительно своей оси и
двигаются по синусоиде слева направо («синусоида»).
5. Придумайте свои траектории движения, алгоритм изменения
размеров и углов поворота.
83
Варианты работ:
1. Нарисовать фрактал «Кривая Пеано».
2. Нарисовать фрактал «Кривая Гильберта».
3. Нарисовать фрактал «Ковер Серпинского».
4. Нарисовать фрактал «Дерево Пифагора».
5. Нарисовать фрактал «Пирамида Коха».
6. Придумайте свой фрактал или скомбинируйте уже известные
фракталы.
84
1. Большаков В. П., Тозик В. Т., Чагина А. В. Инженерная и
компьютерная графика: учеб. пособие. − СПб.: БХВ-Петербург,
2013. − 288 c.
2. Френсис Х. OpenGL. Программирование компьютерной гра-
фики. − СПб.: Питер, 2002.
3. Гинсбург Д., Пурномо Б. OpenGL ES 3.0. Руководство разра-
ботчика. − М.: ДМК Пресс, 2015. − 448 c.
4. Боресков А.В. Расширения OpenGL. − М.: БХВ-Петербург,
2005. − 688 c.
5. Электронный ресурс. – URL: http://www.glprogramming.com/red/
6. Электронный ресурс. – URL: https://e.sfu-kras.ru/course/view.php?
id=9144
85
Научное издание
Учебное пособие
Редактор Л. А. Киселева
Компьютерная верстка И. В. Гревцовой
86
Подписано в печать 24.10.2018. Печать плоская
Формат 60×84/16. Бумага офсетная. Усл. печ. л. 5,5
Тираж 100 экз. Заказ № 5776
Библиотечно-издательский комплекс
Сибирского федерального университета
660041, Красноярск, пр. Свободный, 82а
Тел. (391) 206-26-67; http://bik.sfu-kras.ru
E-mail: publishing_house@sfu-kras.ru
87
88