Компьютерная графика. Курсовая работа

После лабораторных работ бывает и курсовая работа.

СОДЕРЖАНИЕ

СОДЕРЖАНИЕ.. 2

ЗАДАНИЕ.. 3

ВЫБОР ХАРАКТЕРА ПРОГРАММЫ… 4

ВЫБОР ГРАФИЧЕСКОЙ БИБЛИОТЕКИ.. 4

ВЫПОЛНЕНИЕ.. 4

Создание фигур. 4

Кубическая текстура. 5

Создание реалистичного отражения окружающего мира на объекте. 8

Создание пола с попиксельным освещением.. 10

РЕЗУЛЬТАТ КУРСОВОЙ РАБОТЫ… 16

Внешний вид. 16

ЛИТЕРАТУРА.. 17

ПРИЛОЖЕНИЕ. ТЕКСТ ОСНОВНОЙ ЧАСТИ ПРОГРАММЫ… 18

ЗАДАНИЕ

Суть задания – разработать программу с использованием библиотек OpenGL или DirectX, создающую сложную графическую сцену (сцены).

Возможные варианты достижения цели:

  • Компьютерная игра. Типичный пример — автогонки. При этом необходимо чтобы движение автомобиля было реалистичным и подчинялось законам физики. Другой пример – спортивные игры. Здесь не обойтись без искусственного интеллекта (в данном случае это подразумевает необходимость симулировать действия спортсменов-соперников.) В любом случае основной упор следует сделать на графике, а не на искусственном интеллекте.
  • Сложная сцена, в которой реализуются сложные графические эффекты (например, детализированное лицо человека, реалистичные волосы на голове человека, и т. д.)
  • ……..

В целом, характер программы определяется вашей фантазией. Самое главное – своей работой вы должны показать, что научились создавать качественные приложения трёхмерной графики, провели серьезную работу и научились решать задачи заметно более сложные, чем при выполнении лабораторных работ по компьютерной графике.

Для создания сложных графических моделей можно (и, возможно, необходимо) использовать специальные программы, такие как 3D Studio MAX, Maya или Blender.

Важную роль в оценке вашей работы играет отчет (пояснительная записка). Что написать в нем? Необходимо предоставить всю информацию, которая может понадобиться человеку, который захочет повторить достижение, то есть создать такую же программу как и ваша. В отчёте следует так же показать, насколько большой труд был приложен лично вами для создания тех или иных частей программы.

Например, трёхмерные модели 3D Max можно создать собственноручно «с нуля» или загрузить готовую из Интернета. Если модель создана лично вами, в отчёте необходимо объяснить, как у вас это получилось, чтобы читающий ваш отчёт мог (при наличии некоторого опыта работы в 3D Max, разумеется) понять, как он может сделать это. Если модель была позаимствована, необходимо рассказать, какие изменения и как были внесены вами.

Если вы используете специальные библиотеки поверх OpenGL (например, GLScene), или классы С++, созданные не вами, необходимо объяснить в отчёте откуда это взять и как это работает. Необходимо объяснить назначение и принцип работы используемых классов, чтобы было видно, что вы хорошо понимаете то, чем пользуетесь.

Работа будет оцениваться по трем основным критериям:

  • Общее эстетическое впечатление от отображаемой трёхмерной сцены. Первый, но не обязательно самый важный фактор.
  • Сложность сцены, используемых в ней спецэффектов и т. д. Иными словами, должно быть очевидно, что человек изучил что-то новое, научился реализовывать заметно более сложные вещи, чем в прошлом семестре.
  • Степень приложенного студентом труда. Если человек создал сложную сцену, но при этом сам написал только десять строк программного кода, это не очень хорошо. Если есть хорошие заготовки программ из Интернета и модели 3D MAX, значит нужно поставить планку ещё выше и сделать ещё лучше.

ВЫБОР ХАРАКТЕРА ПРОГРАММЫ

Нарисовать просто какую-нибудь трёхмерную сцену не слишком интересно. Гораздо лучше сделать то, для чего собственно и создавались OpenGL и DirectX. Естественно, они создавались для создания трёхмерных компьютерных игр. Но создать полноценную игру достаточно трудоёмкое занятие, слишком объёмное для курсовой работы. Поэтому будет создана некое подобие игры, то есть нечто вроде заготовки.

В этой курсовой была создана программа, которая рисует пол с использованием «объёмной» текстуры (bump mapping). На этом полу находятся небольшие горки, между которыми летает самолет. На поверхности самолета отражаются все окружающие пейзажи.

 

ВЫБОР ГРАФИЧЕСКОЙ БИБЛИОТЕКИ

Программа будет написана с использованием библиотеки OpenGL. Этот выбор основан на том, что:

  • OpenGL – межплатформенная библиотека
  • По мощности OpenGL сравнима с DirectX, но гораздо легче в использовании
  • Для OpenGL легче найти примеры и легче найти статьи про OpenGL.

В программе также для облегчения работы будет использоваться glTools (написанная Richard S. Wright Jr.), которая облегчает работу с OpenGL, а также собственные библиотеки CGL (облегчает инициализацию, установку освещения и позволяет создавать прозрачные элементы пользовательского интерфейса) и myutils (в которой реализована загрузка изображений из файлов bmp, tga).

 

ВЫПОЛНЕНИЕ

 

Создание фигур

Фигуры горок и корабля, которым управляет пользователь были нарисованы в примитивном редакторе 3D_Editor и загружены с помощью библиотеки Edit, поставляемой вместе с ним. Собственно такие фигурки можно было сделать и в любом другом редакторе. Это не составляет особой сложности.

Небо было сделано с помощью стандартных функций OpenGL. С помощью функций glVertex3f был нарисован куб, таким образом, чтобы его грани были обращены лицевой стороной к наблюдателю, находящемуся в центре куба. Размер куба сделан достаточно большим.

Далее стороны куба были обёрнуты текстурами (каждая сторона – свое текстурой). Текстуры для этих целей можно скачать из internet. Текстуры созданы так, что при натягивании их на куб они стыкуются краями и получается единая цельная картина, такая, что наблюдателю не видно, что на самом деле она состоит из кучи мелких текстур.

Тут следует заметить, что для текстур необходимо включить режим CLAMP_TO_EDGE, чтобы она обязательно дотягивалась до края полигона и на границе полигонов не было видно полосок, не охваченных текстурой (без такого режима этого не получится).

 

 

Кубическая текстура

Поддержку кубических текстур осуществляет расширение GL_ARB_texture_cube_map (также как и расширение GL_EXT_texture_cube_map). Значит, OpenGL поддерживает следующие типы текстур: 1D, 2D, 3D и cube maps.

Для каждого из этих типов есть константа, которая передаётся в такие функции как glBindTexture, glTexParameter и glEnable в параметр texture target. Константа для кубических текстур — GL_TEXTURE_CUBE_MAP_ARB (или равная ей по значению GL_TEXTURE_CUBE_MAP_EXT).

Однако в отличие от традиционных (одно-, двух- и трехмерных) текстур, каждая кубическая текстура состоит из набора шести текстур одинакового размера, которые как бы наложены на грани куба.

При работе с одной из этих шести текстур (например для загрузки в память графического ускорителя) следует использовать константы, однозначно идентифицирующие соответствующую текстуру (грань куба, на которую эта текстура должна быть наклеена).

Вот эти константы:

Каждая из этих констант идентифицирует одну из граней куба, расположенном в положительном или отрицательном направлении соответствующей координатной оси (перпендикулярной данной грани).

ориентация куба относительно осей

Значения всех этих констант идут последовательно одно за другим, поэтому, например

При работе с функциями, использующими именно с конкретные текстуры (например, glTexImage2D), нужно использовать именно эти константы.

Загрузка кубической текстуры:

В этом примере функция принимает в качестве параметра список из шести имён текстур.

При работе с кубическими текстурами используются три текстурные координаты (s, t, r). Фактически эти координаты задают направление прямой, выходящей из начала координат. Отсюда точка на текстуре является точкой, где пересекается эта прямая с единичным кубом, описанным вокруг начала координат (с гранями, параллельными осям координат).

 текстурные координаты (s, t, r)

Можно заметить, что пересекаемая прямой грань определяется той текстурной координатой, у которой наибольшее значение по модулю.

Так, если наибольшее по модулю значение имеет координата r, то в зависимости от знака r будет выбрана либо GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB, либо GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB.

Текстурные координаты (u,v), использующиеся для обращения к текстуре соответствующей грани, вычисляются по следующим формулам:

Явное задание текстурных координат:

Есть возможно автоматически вычислять текстурные координаты. Поддерживается два способа автоматической генерации текстурных координат: отражение и вектор нормали.

Автоматическая генерация текстурных координат, соответствующих отражению:

Текстурные координаты, соответствующие нормали:

Для предотвращения появления артефактов в случаях, когда точка на поверхности куба, соответствующая текстурным координатам, подходит слишком близко к какому-либо из ребер куба, следует использовать режим GL_CLAMP_TO_EDGE.

Задание этого режима осуществляется следующими командами:

Данный режим устанавливается только для s и t, поскольку texture wrapping происходит в пределах одной из граней куба, т.е. в 2D.

OpenGL по умолчанию использует режим GL_REPEAT, при работе с кубическими картами нужно явно указать режим GL_CLAMP_TO_EDGE для всех кубических карт.

Перед использованием кубических текстур их следует сперва разрешить при помощи следующей команды

Кубические текстуры имеет более высокий приоритет по сравнению с обычными, поэтому если одновременно разрешить и кубическую и обычную текстуры, то будет использована кубическая.

 

Создание реалистичного отражения окружающего мира на объекте

С помощью описанной предыдущей главе кубической текстуры можно реализовать отражение на поверхности произвольного объекта окружающего мира. Для этого необходимо обернуть объект кубической текстурой с автоматической генерацией текстурных координат, соответствующей отражению, но при этом генерировать текстуры для каждой грани автоматически.

При генерации текстуры используется следующая функция:

Эта текстура позволяет сохранить изображение, нарисованное в данный момент на экране в текстуру. Чтобы получить реалистичное отражение на объекте нужно обхватить этот объект кубической текстурой, каждая грань которой сформирована с помощью этой функции.

Ниже приведена функция, сохраняющая текущее изображение на экране в обыкновенную плоскую текстуру:

В качестве параметров этой функции передаётся идентификатор текстуры, инициализированный массив типа GLubyte, размер которого достаточен для хранения изображения размером width на height.

Для создания отражения в качестве параметров width и height лучше всего передать 128 и 128 соответственно.

Далее с помощью функции glGetTexImage можно получить байты этой текстуры и после всех необходимых преобразований с ними поставить их как грань кубической текстуры: Под преобразованиями имеется в виду то, что в некоторых случаях возможно текстуру нужно будет зеркально отразить слева направо и сверху вниз так как мы делаем именно отражение.

Основная сложность с созданием отражения таким способом состоит в правильном преобразовании матрицы MODELVIEW. Например, для левой грани её нужно преобразовать таким образом, чтобы камера как будто смотрела влево, при правой – вправо. Это всё делается очень просто, если объект стоит на месте. А если он ещё и двигается в пространстве, то необходимо ещё сначала перенести систему координат в место его расположения, повернуть на угол, на который повёрнут объект и т. д.

Создание пола с попиксельным освещением

Каким образом можно простейшим образом реализовать попиксельное освещение средствами OpenGL?

В качестве модели освещения мы возьмем простейшую модель только диффузного освещения — освещенность каждого видимого пикселя задается следующей формулой:

Где через l и n обозначены единичные вектора направления от точки к источнику света и нормали к поверхности в этой точке. Функция вычисления максимального значения избавляет от «отрицательной» освещенности (когда нормаль направлена от источника света и свет падать на эту точку просто не может).

В OpenGL значения освещенности вычисляются лишь в вершинах граней, а затем полученные значения интерполируются вдоль граней. Поэтому при использовании стандартной модели освещения OpenGL блики внутри граней не появляются.

Для попиксельного освещения стандартная модель освещения OpenGL не подходит.

Нам понадобятся значения векторов l и n для каждого пикселя.

Можно задать единичные значения вектора l в каждой вершине грани (например, как цвет или текстурные кординаты).

векторы попиксельного освещения

Если в каждой из вершин A, B, C и D задать значение вектора l, то можно стандартными средствами OpenGL произвести билинейную интерполяцию этого вектора (вдоль всего многоугольника ABCD), и для каждого пикселя получить проинтерполированное значение.

Самый простой способ для этого — задание вектора l как текстурных координат.

У этого подхода есть серьезный недостаток —  если значения, заданные в вершинах и были единичными векторами, то значения, полученные в результате интерполяции, скорее всего единичными уже не будут (см. рис.).

значения, полученные в результате интерполяции, скорее всего единичными уже не будут

Для нормализации полученных значений (для их использования в скалярном произведении) можно использовать нормализирующие кубические карты (normalization cube map).

Кубическая карта задаёт функцию от направления трехмерного вектора (т.е. функцию, которая зависит только от направления и не зависит от его длины).

Построим следующую карту — каждому вектору (s,t,r)  сопоставим его нормированное значение — (s,t,r)/sqrt(s*s+t*t+r*r) .

Тогда если значения вектора l в вершинах задавать как текстурные координаты для такой кубической карты (она называется нормирующей или нормализирующей), то на выходе операции текстурирования мы будем получать единичный трехмерный вектор.

Так как на выходе операции текстурирования мы получаем цвет (3-х или 4-х компонентный), то для построения такой карты нужен способ кодирования почти единичных (поскольку длина вектора, получающиеся в результате интрерполячции единичных, не сильно отличается от единицы) векторов в RGB цвета.

Сопоставим вектору (x,y,z), каждая компонента которого лежит на отрезке [-1,1], цвет (r,g,b), по следующему правилу:

Полученный вектор (r,g,b) содержится в единичном кубе и является допустимым значением цвета (в рельных приложениях каждый компонент нужно умножить на 255 для перевода в диапазон значения байта).

Процедура построения нормирующей кубической карты:

Если в вершинах грани задать нормированные значения вектора направления на источник света l, то в каждом пикселе грани мы получим нормированное значение вектора l, соответствующее данному пикселю. Правда это значение будет представлено в виде цвета.

Тогда можно нормаль для каждого пикселя задать в виде текстуры, где каждому значению единичного вектора нормали сопоставляется цвет.

Обычно считается, что грань расположена параллельно плоскости Оху, поэтому неискаженному вектору нормали (0,0,1) будет соответствовать цвет (0.5,0.5,1), имеющий голубоватый оттенок.

Обычно карта нормалей содержит значения, не сильно отличающиеся от (0,0,1), то обычные карты нормалей имеют голубовато-розоватый оттенок.

Для вычисления скалярного произведения можно использовать расширение ARB_texture_env_dot3, которое вычисляет следующую величину:

Если считать, что оба аргумента являются векторами, записанными в виде цвета, то с учетом формул преобразования векторов в цвет, это значение соответствует скалярному произведению двух векторов — Arg0 и Arg1.

Это расширение добавляет два режима к расширению ARB_texture_env_combine — GL_DOT3_RGB_ARB и GL_DOT3_RGBA_ARB. В первом случае вычисленное значение записывается в первые три компоненты цвета (RGB), а во втором — во все четыре (RGBA).

Рассмотрим теперь как можно реализовать простейшее попиксельное освещение с использованием нормирующих кубических карт и расширения ARB_texture_env_dot3.

За счет использования мультитекстурирования можно реализовать вычисление выражения max((l,n),0) за один проход.

В нулевом текстурном блоке располагается текстура, задающая карту нормалей. В качестве режима наложения используется GL_REPLACE. В качестве текстурных координат для него задаются нормальные координаты для текстуры с нормалями.

В первом текстурном блоке размещается нормирующая кубическая карта. Режимом наложения для нее является GL_DOT3_RGB_ARB. В качестве текстурных координат выступает нормированный вектор направления на источник света.

В качестве Arg0 используется GL_TEXTURE, а в качестве Arg1 — GL_PREVIOUS_ARB (в данном случае это будут значения с предыдущего текстурного блока, т.н. значение вектора нормали).

С помощью второго прохода можно реализовать более сложную модель освещения:

Здесь С соответствует собственному цвету пиксела, т.е. является еще одной текстурой. Собственный цвет пиксела модулируется освещенностью данного пиксела.

Для этого достаточно повторно вывести грань с использованием текстуры С и режимом смешения (blending) (GL_DST_COLOR, GL_ZERO).

 

РЕЗУЛЬТАТ КУРСОВОЙ РАБОТЫ

Внешний вид

РЕЗУЛЬТАТ КУРСОВОЙ РАБОТЫ по комьютерной графике

ЛИТЕРАТУРА

  • MSDN Library for Visual Studio 6.0
  • Франк Луна: Введение в программирование трехмерных игр с DX9
  • сайт http://www.steps3d.narod.ru
  • Microsoft DirectX SDK (August 2006)

 

 

 

ПРИЛОЖЕНИЕ. ТЕКСТ ОСНОВНОЙ ЧАСТИ ПРОГРАММЫ

Отрывки из главного файла «kurs.cpp»:

Файл «floor.cpp»:

Файл «spacesheep.cpp»:

Скачать ZIP-архив с исходными кодами курсовой работы по дисциплине «Компьютерная графика»

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *