Разработка приложения с использованием OpenGL для построения динамического изображения трехмерной модели объекта "Гоночный автомобиль"

Тип работы:
Курсовая
Предмет:
Программирование


Узнать стоимость

Детальная информация о работе

Выдержка из работы

МИНИСТЕРСТВО ОБРАЗОВАНИЯ И НАУКИ РОССИЙСКОЙ ФЕДЕРАЦИИ

ГОСУДАРСТВЕННОЕ ОБРАЗОВАТЕЛЬНОЕ УЧРЕЖДЕНИЕ

ВЫСШЕГО ПРОФЕССИОНАЛЬНОГО ОБРАЗОВАНИЯ

«СЕВЕРО-КАВКАЗСКИЙ ГОСУДАРСТВЕННЫЙ ТЕХНИЧЕСКИЙ УНИВЕРСИТЕТ»

Кафедра информационных систем и технологий

Пояснительная записка

к курсовой работе

по дисциплине

Гоночный автомобильная геометрия и графика

Разработка приложения с использованием OpenGL для построения динамического изображения трехмерной модели объекта «Гоночный автомобиль»

Ставрополь, 2011

АННОТАЦИЯ

программное трехмерная модель

Приложение написано на языке С++ с использованием библиотеки OpenGL и MFC. Программа создана в среде Visual Studio 6.0. В рамках работы были выполнены все представляемые задачи. Имеется возможность производить различные настройки, такие как: настройка и выбор перспективы, выбор режима тумана, выбор нескольких источников света, вкл/откл текстуры, выбор режима полигона, изменение цвета объектов. Модель анимирована, ею можно управлять клавишами с клавиатуры. Также используя колесо мыши можно приближаться и отдаляться. Программа имеет интуитивно понятный интерфейс, который схож с другими Windows — приложениям, что указывает на массовость программного продукта.

Содержание

  • АННОТАЦИЯ
    • ВВЕДЕНИЕ
  • 1. ПРОГРАММИРОВАНИЕ С ИСПОЛЬЗОВАНИЕМ БИБЛИОТЕКИ OPENGL
    • 1.1 Назначение OpenGL
    • 1.2 Архитектура OpenGL
    • 1.3 Преимущества OpenGL
    • 1.4 Функциональные возможности OpenGL
    • 1.5 Видовое преобразование
    • 1.6 Использование таймера
  • 2. РАЗРАБОТКА ПРИЛОЖЕНИЯ ДЛЯ ПОСТОРОЕНИЯ ДИНАМИЧЕСКОГО ИЗОБРАЖЕНИЯ ТРЕХМЕРНОЙ МОДЕЛИ ОБЪЕКТА «ГОНОЧНЫЙ АВТОМОБИЛЬ».
    • 2.1 Разработка процедуры визуализации трехмерной сцены
    • 2.2 Разработка интерфейса пользователя
    • 2.3 Разработка подсистемы управления событиями
  • 3. ИНФОРМАЦИОННОЕ И ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ
    • 3.1 Общие сведения о программе
    • 3.2 Функциональное назначение
    • 3.3 Логическая структура и функциональная декомпозиция проекта
    • 3.4 Требования к техническому и программному обеспечению
    • 3.5 Руководство пользователя
  • 4. ЗАКЛЮЧЕНИЕ И ВЫВОДЫ
  • СПИСОК ЛИТЕРАТУРЫ
  • ПРИЛОЖЕНИЕ А.
  • Алгоритм построения трёхмерной сцены
    • ПРИЛОЖЕНИЕ Б. Исходный код
    • ПРИЛОЖЕНИЕ В. Диаграмма классов
    • ПРИЛОЖЕНИЕ Г. Трёхмерная модель объекта «ГОНОЧНЫЙ АВТОМОБИЛЬ»
    • ПРИЛОЖЕНИЕ Д. Перечень графического материала

ВВЕДЕНИЕ

OpenGL (Open Graphics Librar -- открытая графическая библиотека) -- спецификация, определяющая независимый от языка программирования кросс-платформенный программный интерфейс для написания приложений, использующих двумерную и трёхмерную Гоночный автомобильную графику.

Включает более 250-ти функций для рисования сложных трёхмерных сцен из простых примитивов. Используется при создании видеоигр, САПР, виртуальной реальности, визуализации в научных исследованиях. На платформе Windows конкурирует с DirectX.

Библиотеку OpenGL может производить кто угодно. Главное, чтобы библиотека удовлетворяла спецификации OpenGL и ряду тестов. Библиотеку выпускают такие корпорации, как Microsoft, Silicon Graphics, а также просто группы программистов. Одним из таких примеров служит реализация Mesa. Эту библиотеку написали целый ряд программистов, главным автором является Brian Paul. Библиотека Mesa распространяется в исходных текстах на языке Си и собирается почти для любой операционной системы.

Стандарт OpenGL развивается с 1992 года. Он разрабатывается фирмой Silicon Graphics. С тех пор библиотека завоевала огромную популярность и была интегрирована с множеством языков и систем разработки приложений. Можно писать программу с использованием OpenGL на Си, С++, Pascal, Java и многих других языках.

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

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

OpenGL непосредственно не поддерживает работу с устройствами ввода, такими как мышь или клавиатура, т.к. эта библиотека является платформенно-независимой. Но возможно задействовать функции конкретной операционной системы, под которую пишется программа или воспользоваться надстройками над OpenGL, такими как библиотеки GLUT или GLAUX.

1. ПРОГРАММИРОВАНИЕ С ИСПОЛЬЗОВАНИЕМ БИБЛИОТЕКИ OPENGL

1.1 Назначение OpenGL

Основная идея OpenGL: графическая библиотека должна быть аппаратно независимой, но в то же время использовать аппаратные ускорители, если они доступны. Кроме того, этот язык с самого начала предусматривал механизм расширения и гибкости — по мере того как расширения становились «общепринятыми», они становились частью следующего релиза.

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

Создатели OpenGL планировали свой язык с явным намерением создать «виртуальный графический акселератор», так чтобы примитивы OpenGL максимально соответствовали примитивам современных графических карт и требовали минимум кода для трансляции из одной системы команд в другую. Фактически большинство современных графических процессоров (обычно называемых видеокартами, хотя к видео они имеют лишь касательное отношение) напрямую воспринимают OpenGL как язык входного уровня без какой-либо (или с минимумом) трансляции.

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

1.2 Архитектура OpenGL

Точно так же, как процессор имеет два типа конвейеров — для целочисленных вычислений и чисел с плавающей точкой, OpenGL имеет два конвейера для пиксельных данных и вертексных операций, то есть для операций с векторными данными. Каждый из потоков обрабатывается отдельно, до тех пор пока это возможно — то есть до стадии мэппинга, когда пиксельные растры как фактуры «натягиваются» на плоскости и более сложные поверхности.

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

Готовые фрагменты окончательно обрабатываются перед тем, как они реально будут внесены в frame buffer. В частности, фрагменты сортируются зависимо от значений «глубины» — и эти значения сравниваются с известными на предмет рекомпозиции. Применение блендинга приводит к тому, что прозрачные фрагменты принимают цвет, состоящий из их собственного и цветов «ниже лежащих» фрагментов. Дополнительно может быть реализовано маскирование и другие эффекты.

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

1.3 Преимущества OpenGL

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

Производительность. С самого начала в OpenGL была заложена «крайне желательная» возможность отрисовки динамических сцен. Для получения нужных результатов в систему введено множество параметров, или, как говорят, режимов рисования. Если некоторый режим или комбинация режимов на данном оборудовании не в состоянии обеспечить интерактивного взаимодействия и необходимой частоты обновления сцены, то пользователь или сама программа должны быть в состоянии отключать так много дополнительных функций, сколько нужно для получения «живой» картинки. Ортогональность. По возможности все функции OpenGL являются ортогональными, то есть независимыми. Вы можете использовать их в произвольной комбинации, например использование мэппинга не ограничивает возможностей применения светотени.

Полнота. Насколько это представляется возможным, OpenGL соответствует набору функций, предоставляемому современными аппаратными средствами графической акселерации. OpenGL старается избегать всего, что должно быть реализовано программно. С другой стороны, по крайней мере, гарантируется получение рабочей картинки, даже если производительность и не позволяет получить ее со всеми подробностями. То есть, если что-то работает на одной платформе, то этот же код будет работать и на другой — хотя, возможно, и с другим результатом.

Интероперабельность. В сетевом окружении важно передавать данные между разными платформами. Поэтому OpenGL заранее ориентирован на работу в режиме клиент-сервер, даже если и клиент и сервер расположены на одном Гоночный автомобилье.

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

1.4 Функциональные возможности OpenGL

Ниже перечислены основные функции OpenGL. По ним вы можете судить об уровне языка и используемых примитивах.

Альфа-канал. Позволяет делать предметы прозрачными, уровень прозрачности от 0 до 100%. Антиалиасинг. Сглаживание цветовых переходов, более реалистическое изображение. Буфер аккумулятора. Дополнительный буфер для 2,5-мерных эффектов, спецэффектов и глобального сглаживания по всей сцене. Градиентная заливка (gouraud shading). Линейно-градиентная заливка полигонов и отрезков. Графические примитивы. В пространстве: точка, отрезок, полигон, битовое изображение или изображение в другом формате. Двойная буферизация. Применяется для сглаживания эффектов анимации, когда новое изображение строится на заднем плане и потом отображается целиком. При этом пользователь не видит самого процесса создания изображения в несогласованном состоянии, например различных «изнанок объектов», «дыр в пространстве», «граней мира» и подобных нежелательных деталей. Заливка и освещенность фактур. К фактурам применяются эффекты освещенности и затенения в зависимости от характеристик «материала». В версии 1.2 реализованы блики поверх текстур.

Маскирование. Можно маскировать некоторые цвета по трафарету.

Массивы вершин. Новая возможность версии 1.5 — для повышения производительности задавать вершины массивами, а не отдельно.

Обратная связь. Данные после растрирования могут быть возвращены в приложение вместо передачи из/в frame buffer или параллельно с ней.

Пересечения. Автоматическое определение того, пересекает ли тот или иной объект заданный пространственный регион.

Пиксельные операции. Масштабирование и другие аффинные преобразования битовых образов.

Поддиапазоны. Возможность работать с частью матрицы вершин; применяется как метод оптимизации.

Полиноминальные операции. Поддержка неравномерных рациональных би-сплайнов для описания кривых поверхностей.

Полноцветное отображение. Представление в режиме RGBA, то есть тремя цветами и значением альфа-канала. Начиная с версии 1. 2, поддерживаются также схемы BGRA и схемы с упакованными цветами для быстрой обработки популярных типов графических файлов.

Пространственные преобразования. Масштабирование, вращение и перемещение объектов в пространстве.

Режим индексированных цветов. Представление цветов не RGB-триплетами, а индексами в таблице цветов. Применяется для сжатия размена изображений «по глубине цвета» и эффектов быстрой замены одного цвета другим.

Режим прямой отрисовки. Рисование по мере поступления команд, без использования списков отображения.

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

Список отображения (displa list). Пакет описания объектов сцены для предварительного разбора и оптимизации кэширования.

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

Z-буффер. Понятие об удалении объектов и их частей от наблюдателя, часть алгоритма удаления скрытых поверхностей.

1.5 Видовое преобразование

Для формирования матрицы преобразований можно воспользоваться готовыми командами:

1. Вращение: void glRotate[f, d](GLt pe angle, GLt pe x, GLt pe, GLt pe z). Эта команда рассчитывает матрицу для выполнения вращения вектора против часовой стрелки на угол, определяемый параметром angle, осуществляемого относительно точки (x,, z). После выполнения этой команды все объекты изображаются повернутыми.

2. Параллельный перенос: void glTranslate[f, d](GLt pe x, GLt pe, GLt pe z). При помощи этой команды осуществляется перенос объекта на расстояние x по оси Х, на расстояние по оси и на расстояние z по оси Z.

3. Масштабирование: void glScale[f, d](GLt pe x, GLt pe, GLt pe z). Осуществляет частичное масштабирование вдоль каждой из координатных осей на значения, определяемые соответствующими параметрами.

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

1.6 Использование таймера

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

Есть и другой способ, также основанный на передаче сообщений. При использовании этого способа сообщения WM_TIMER посылаются не функции окна, а специальной функции, описанной с ключевым словом _export. Эта функция напоминает функцию окна и, так же как и функция окна, вызывается не из приложения, а из Windows. Функции, которые вызываются из Windows, имеют специальный пролог и эпилог и называются функциями обратного вызова (callback function). Функция окна и функция, специально предназначенная для обработки сообщений таймера, являются примерами функций обратного вызова.

Для создания виртуального таймера приложение должно использовать функцию SetTimer:

UINT WINAPI SetTimer (HWND hwnd, UINT idTimer, UINT uTimeout, TIMERPROC tmprc);

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

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

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

Третий параметр (uTimeout) определяет период следования сообщений от таймера в миллисекундах. Физический таймер тикает приблизительно 18,21 раза в секунду (точное значение составляет 1000/54,925). Поэтому, даже если указать, что таймер должен тикать каждую миллисекунду, сообщения будут приходить с интервалом не менее 55 миллисекунд.

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

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

BOOL WINAPI KillTimer (HWND hwnd, UINT idTimer);

Первый параметр функции (hwnd) определяет идентификатор окна, указанный при создании таймера функцией SetTimer.

Второй параметр (idTimer) — идентификатор уничтожаемого таймера. Это должен быть либо тот идентификатор, который был указан при создании таймера (если таймер создавался для окна), либо значение, полученное при создании таймера от функции SetTimer (для таймера, имеющего собственную функцию обработки сообщений).

Функция KillTimer возвращает значение TRUE при успешном уничтожении таймера или FALSE, если она не смогла найти таймер с указанным идентификатором.

Рассмотрим способ работы с таймером — подключение таймера к окну. В этом случае функция окна, к которому подключен таймер, будет получать сообщения от таймера с кодом WM_TIMER.

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

#define FIRST_TIMER 1 int nTimerID; nTimerID = SetTimer (hwnd, FIRST_TIMER, 1000, NULL);

В данном примере создается таймер с идентификатором FIRST_TIMER, который будет посылать сообщения примерно раз в секунду.

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

KillTimer (hwnd, FIRST_TIMER);

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

KillTimer (hwnd, FIRST_TIMER); nTimerID = SetTimer (hwnd, FIRST_TIMER, 100, NULL);

2. РАЗРАБОТКА ПРИЛОЖЕНИЯ ДЛЯ ПОСТОРОЕНИЯ ДИНАМИЧЕСКОГО ИЗОБРАЖЕНИЯ ТРЕХМЕРНОЙ МОДЕЛИ ОБЪЕКТА «ГОНОЧНЫЙ АВТОМОБИЛЬ»

2.1 Разработка процедуры визуализации трехмерной сцены

Прорисовка в рабочей области начинается с метода void CLab1View: :OnDraw (CDC* pDC), в котором вызывается функция usr_RenderScene (). Она отвечает за прорисовку функциональных частей и за некоторые важные расчёты, которые связаны с расположением некоторых отдельных деталей. Модель состоит из геометрических примитивов, таких как цилиндр, параллелепипед, полигон, сфера.

Рисование 3D объекта начинается с установления формата пикселей и области вывода в методах BOOL CLab1View: :usr_setuppixelformat () и void CLab1View: :usr_Resize (int x, int, int width, int heidht) соответственно. Рассмотрим подробнее метод usr_RenderScene (), код которого представлен в приложении Б. В этом методе начинается прорисовка объекта. Модель рисуется с левого переднего колеса состоящего из нескольких примитивов: gluC linder (quadric, 0. 35, 0. 4, 0. 05, 50,40), gluC linder (quadric, 0. 4, 0. 4, 0. 35, 50,40), gluC linder (quadric, 0. 4, 0. 35, 0. 05, 50,40), gluC linder (quadric, 0. 35, 0. 0, 0. 0, 50,40), gluC linder (quadric, 0. 35, 0. 0, 0. 0, 50,40). Затем рисуем переднюю ось — gluC linder (quadric, 0. 06, 0. 06, 1. 5, 50,40), и правое колесо аналогично левому. Затем рисуем передний спойлер: auxSolidBox ((GLfloat)0. 7,0. 1,1. 1), auxSolidBox ((GLfloat)0. 2,0. 1,1. 5), auxSolidBox ((GLfloat)0. 2,0. 06,0. 3), auxSolidBox ((GLfloat)0. 2,0. 06,0. 3). Рисуем дно: auxSolidBox ((GLfloat)1. 7,0. 1,1. 8), auxSolidBox ((GLfloat)0. 7,0. 1,1. 0) и заднюю ось — gluC linder (quadric, 0. 06, 0. 06, 1. 5, 50,40). Затем рисуем задние колёса аналогично передним, но по шире. Теперь рисуем выхлоп — auxSolidBox ((GLfloat)0. 3,0. 3,0. 6). Рисуем задний спойлер: начинаем с его крепления (gluC linder (quadric, 0. 02, 0. 02, 0. 7, 50,40)) и сам спойлер — auxSolidBox ((GLfloat)1. 6,0. 3,0. 03), auxSolidBox ((GLfloat)1. 6,0. 03,0. 15), auxSolidBox ((GLfloat)0. 03,0. 3,0. 15), auxSolidBox ((GLfloat)0. 03,0. 3,0. 15). Затем рисуем кузов состоящего из примитивов: auxSolidBox, glBegin, gluC linder. На этом прорисовка модели закончена.

Весь код метода usr_RenderScene () представлен в приложении Б.

2.2 Разработка интерфейса пользователя

Для данной программы разработан интерфейс, позволяющий:

— включать и выключать эффект тумана;

— выбрать цвет тумана;

— выбирать тип тумана;

— вращать Гоночный автомобиль;

— задавать цвет деталей Гоночного автомобиля;

— вкл/выкл текстуру;

— выбирать тип полигонов;

— выбирать несколько источников света;

— задавать скорость и вид движения Гоночного автомобиля;

— выбирать тип и задавать параметры перспективы;

— вращать и поворачивать сцену цифровой клавиатурой;

— приближать и удалять объект с помощью мышки.

Для добавления данных возможностей было отредактирована панель инструментов приложения, а именно добавлена кнопка «Перспектива».

В главном меню добавлены пункты:

— «Поехали» — F1 едет вперёд.

— «Настройки» — различные настройки всей сцены (Рисунок Г. 2).

Приложение имеет интуитивно понятный интерфейс, с которым удобно работать.

2.3 Разработка подсистемы управления событиями

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

Таким образом, разработка подсистемы управления событиями занимает особое место в общей системе разработки приложения. К основным событиям, обеспечивающим корректную работу программы, относят:

— WM_DESTRO — освобождение занятых ресурсов;

— WM_SIZE — изменения сцены относительно размеров окна;

— WM_ERASEBKGND — предотвращения мерцания;

— WM_TIMER — используется для создания таймера;

— WM_MOUSEWHEEL — обработка вращения колеса мышки;

— WM_KE DOWN — обработка нажатия клавиши;

— COMMAND (ID_PERSP, CKarkasView: :OnPersp ()) — обработка события при вызове окна настройки перспективы;

— COMMAND (ID_OPTIONS, CKarkasView: :OnOptions ()) — обработка события при вызове окна настройки типа вращения и скорости движения объекта;

— COMMAND (ID_VIEW1, CKarkasView: :OnView1()) — обработка события выбора типа тумана;

— COMMAND (ID_VIEW_SBROS, CKarkasView: OnVewSbros ()) — обработка события нажатия кнопки «Убрать туман»;

— COMMAND (ID_VIEW_MOVE, CKarkasView: :OnMove ()) — обработка нажатия кнопки «Поехали».

3. ИНФОРМАЦИОННОЕ И ПРОГРАММНОЕ ОБЕСПЕЧЕНИЕ

3.1 Общие сведения о программе

Программа называется «Гоночный автомобиль». При работе с данной программой у пользователя есть возможность работать с визуальной моделью данного объекта. Вращать ее относительно осей, включать и выключать эффект тумана, выбирать цвет тумана, выбирать тип полигонов, выбирать несколько источников света, выбирать цвет монитора стола и колонок, также задавать тип тумана, приближать и удалять сцену с помощью колеса мышки, включать и выключать вращение модели и устанавливать скорость вращения, а также имеется возможность разобрать на мельчайшие детали. Программное обеспечение, на котором разработана приложение — Microsoft Visual С++ 6.0 с использованием библиотеки OpenGL.

3.2 Функциональное назначение

Данное приложение обеспечивает следующие возможности:

— включать и выключать эффект тумана;

— выбрать цвет тумана;

— выбирать тип тумана;

— вращать Гоночный автомобиль;

— задавать цвет деталей Гоночного автомобиля;

— вкл/выкл текстуру;

— выбирать тип полигонов;

— выбирать несколько источников света;

— задавать скорость и вид движения Гоночного автомобиля;

— выбирать тип и задавать параметры перспективы;

— вращать и поворачивать сцену цифровой клавиатурой;

— приближать и удалять объект с помощью мышки.

3.3 Логическая структура и функциональная декомпозиция проекта

Инициализация OpenGL происходит в несколько этапов.

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

2. Создаем контекст вывода для библиотеки OpenGL. Данный контекст создается с помощью функции wglCreateContext (), далее функция wglMakeCurrent () устанавливает текущий контекст. Функция wglGetCurrentDC () необходима для корректного завершения приложения, а wglGetCurrentDC () — для удаления контекста воспроизведения.

Одним из важных методов является usr_ReSize (), который устанавливает перспективу и область вывода.

За отображение сцены отвечает метод usr_RenderScene (), который вызывает в свою очередь функции рисования Гоночный автомобильа.

Функции, вызываемые методом usr_RenderScene () были подробно рассмотрены в разделе «2.1 Разработка процедуры визуализации трехмерной сцены», а важные для логического понимания структуры события программы рассмотрены в разделе «2.3 Разработка подсистемы управления событиями».

Для наглядности приведем таблицу наиболее важных методов — таблица 3.1.

Таблица 3.1 — Основные методы и функции

Метод

Назначение

Назначение параметров

1

PreCreateWindow (CREATESTRUCT& cs)

Инициализация окна

cs — объект структуры CREATESTRUCT.

Производится изменение значений, присвоенных переменным-членам структуры CREATESTRUCT для изменения режима открытия окна и его параметров.

2

usr_bSetupPixelFormat ()

Установка формата пикселей

3

usr_bInitOpenGL ()

Инициализация OpenGL

4

user_Destor OpenGL ()

Освобождение ресурсов (из-под OpenGL)

5

usr_ReSize (int x, int, int width, int height)

Корректирует вывод сцены на экран при изменении размера окна

x и определяют координаты левого нижнего угла вывода, width и height — ширину и высоту области вывода

6

usr_RenderScene ()

Рисует Гоночный автомобиль целиком

В таблице 3.2 приведены спецификации разработанных классов.

Таблица 3.2 — Спецификации классов

Название

Назначение

СMainframe

Класс главного окна приложения. Используется для управления главным окном

CKarkasApp

Главный класс приложения. Управляет работой всего приложения. Методы этого класса выполняют инициализацию приложения, обработку цикла сообщений и вызываются при завершении приложения.

CKarkasDoc

Класс документа приложения.

CKarkasView

Класс окна просмотра документа. Служит для отображения в клиентской области класса документа приложения в нашем случае нашей 3D модели.

CAboutDlg

Класс справочной информации о программе

DlgPers

Класс диалогового окна. Служит для настройки и смены перспективы

DlgOptions

Класс диалогового окна. Служит для включения различных настроек сцены.

3.4 Требования к техническому и программному обеспечению

Для успешной эксплуатации программного продукта необходим персональный Гоночный автомобиль со следующими характеристиками: процессор Intel Pentium с тактовой частотой 800 МГц и выше, оперативная память — не менее 64 Мбайт, свободное дисковое пространство — не менее 500 Мбайт, устройство для чтения компакт-дисков, монитор типа Super VGA (число цветов — 256). Программное обеспечение: операционная система WINDOWS 2000/XP и выше.

3.5 Руководство пользователя

Для установки приложения требуется скопировать с установочного диска, прилагаемого к работе файл «Karkas. exe» в любую директорию на жестком диске. Для запуска программы нужно два раза нажать на левую клавишу мыши.

Разработанное приложение имеет интуитивно понятный интерфейс, который схож с другими Windows — приложениями. После запуска программы пользователь, может вращать сцену и поворачивать её с помощью цифровой клавиатуры (8 — вверх, 2 — вниз, 4 — влево, 6 — вправо, 7 и 9 — вращение по оси, 1 и 3 — вращение по другой оси). Также имеется возможность приближать и удалять модель, это можно сделать, задействовав колесо мыши.

Существует поддержка различных графических эффектов. Для их выбора нажмите на кнопку Настройки, после нажатия откроется окно где можно выбрать различные опции, для подтверждения нужно нажать кнопку Ок (Рисунок Г. 2).

4. ЗАКЛЮЧЕНИЕ И ВЫВОДЫ

В ходе разработки данного приложения были получены практические навыки по разработке программ для операционных систем семейства Windows с применением технологий трехмерной графики с использованием библиотеки OpenGL.

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

— изучение принципов работы OpenGL в оконной среде Windows;

— получение практических навыков использования средств OpenGL;

— получение навыков программирования динамических трехмерных анимационных сцен;

— получение навыков программирования интерактивных трехмерных приложений.

Также была проведена работа с такими возможностями библиотеки как:

— использование эффекта тумана;

— использование графических примитивов;

— применение освещения;

— загрузка текстур;

— применение проекции.

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

СПИСОК ЛИТЕРАТУРЫ

1. Порев В. Н. Гоночный автомобильная графика. СПб., BHV, 2002.

2. Херн Бейкер, Гоночный автомобильная графика и стандарт OpenGL, 3-е издание.: Пер. с англ. — М.: Издательство дом «Вильямс», 2005. — 1168 с.

3. Шикин А. В., Боресков А. В. Гоночный автомобильная графика. Полигональные модели. Москва, ДИАЛОГ-МИФИ, 2001.

4. Тихомиров Ю. Программирование трехмерной графики. СПб, BHV, 1998.

5. OpenGL performance optimization, Siggraph'97 course.

6. Visual Introduction in OpenGL, SIGGRAPH'98.

7. The OpenGL graphics s stem: a specification (version 1. 1).

8. Программирование GLUT: окна и анимация. Miguel Angel Sepulveda, LinuxFocus.

9. The OpenGL Utilit Toolkit (GLUT) Programming Interface, API version 3, specification.

10. Хилл, Ф. OpenGL. Программирование Гоночный автомобильной графики. Для профессионалов/ Ф. Хилл, — СПб.: «Питер», 2004. — 1088с.

Материалы сайтов:

http: //nehe. gamedev. net/

ПРИЛОЖЕНИЕ А.

Алгоритм построения трёхмерной сцены

Рисунок А.1 — Алгоритм построения объекта «Гоночный автомобиль»

ПРИЛОЖЕНИЕ Б

Исходный код

#include «stdafx. h»

#include «Karkas. h»

#include «KarkasDoc. h»

#include «KarkasView. h»

#include «DlgPers. h»

#include «dlgOptions. h»

#include «math. h»

#ifdef _DEBUG

#define new DEBUG_NEW

#undef THIS_FILE

static char THIS_FILE[] = __FILE__;

#endif

/////////////////////////////////////////////////////////////////////////////

// CKarkasView

IMPLEMENT_D NCREATE (CKarkasView, CView)

BEGIN_MESSAGE_MAP (CKarkasView, CView)

//{{AFX_MSG_MAP (CKarkasView)

ON_WM_CREATE ()

ON_WM_DESTRO ()

ON_WM_SIZE ()

ON_WM_ERASEBKGND ()

ON_COMMAND (ID_PERSP, OnPersp)

ON_WM_CHAR ()

ON_WM_MOUSEWHEEL ()

ON_COMMAND (ID_OPTIONS, OnOptions)

ON_WM_TIMER ()

ON_COMMAND (ID_BUM, OnBum)

//}}AFX_MSG_MAP

// Standard printing commands

ON_COMMAND (ID_FILE_PRINT, CView: :OnFilePrint)

ON_COMMAND (ID_FILE_PRINT_DIRECT, CView: :OnFilePrint)

ON_COMMAND (ID_FILE_PRINT_PREVIEW, CView: :OnFilePrintPreview)

END_MESSAGE_MAP ()

/////////////////////////////////////////////////////////////////////////////

// CKarkasView construction/destruction

CKarkasView: :CKarkasView ()

{

StartPos[0]=0;

StartPos[1]=0;

CurDepth=70;

TransX=0;

Trans =0;

x7 = 0;

1 = 0;

x9 = 0;

3 = 0;

FirstTimer=0;

SecondTimer=0;

XSceneRot=0;

SceneRot=0;

scene_rotate_speed=0;

X=0;

BumTime=0;

Cloud_Enable=0;

C1[0]=C2[0]=C3[0]=0. 8;

C1[1]=C2[1]=C3[1]=0. 7;

C1[2]=C2[2]=C3[2]=0. 5;

Pol gonMode=GL_FILL;

}

CKarkasView: :~CKarkasView ()

{

}

BOOL CKarkasView: :PreCreateWindow (CREATESTRUCT& cs)

=(WS_CLIPCHILDREN

void CKarkasView: :OnDraw (CDC* pDC)

{

CKarkasDoc* pDoc = GetDocument ();

ASSERT_VALID (pDoc);

usr_RenderScene ();

}

BOOL CKarkasView: :OnPreparePrinting (CPrintInfo* pInfo)

{

return DoPreparePrinting (pInfo);

}

void CKarkasView: :OnBeginPrinting (CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

}

void CKarkasView: :OnEndPrinting (CDC* /*pDC*/, CPrintInfo* /*pInfo*/)

{

}

/////////////////////////////////////////////////////////////////////////////

// CKarkasView diagnostics

#ifdef _DEBUG

void CKarkasView: :AssertValid () const

{

CView: :AssertValid ();

}

void CKarkasView: :Dump (CDumpContext& dc) const

{

CView: :Dump (dc);

}

CKarkasDoc* CKarkasView: :GetDocument ()

{

ASSERT (m_pDocument-> IsKindOf (RUNTIME_CLASS (CKarkasDoc)));

return (CKarkasDoc*)m_pDocument;

}

#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////

// CKarkasView message handlers

BOOL CKarkasView: :usr_bSetupPixelFormat ()

{

int iPixelT pe=PFD_T PE_RGBA;

DWORD dwFlags=PFD_DOUBLEBUFFER|

PFD_SUPPORT_OPENGL|

PFD_DRAW_TO_WINDOW;

PIXELFORMATDESCRIPTOR pfd ={0};

pfd. nSize=sizeof (PIXELFORMATDESCRIPTOR);

pfd. nVersion=1;

pfd. dwFlags=dwFlags;

pfd. iPixelT pe=iPixelT pe;

pfd. cColorBits=64;

pfd. cAlphaBits =64;

pfd. cAccumBits=64;

pfd. cDepthBits=64;

pfd. cStencilBits=64;

pfd. cAuxBuffers=64;

pfd. iLa erT pe= PFD_MAIN_PLANE;

CClientDC* lDC = new CClientDC (this);

int pixelformat;

if ((pixelformat=ChoosePixelFormat (lDC-> GetSafeHdc (),&pfd))==0)

{

MessageBox («usr_bSetupPixelFormat: ChoosePixelFormat failed BUM BUM BUM»);

lDC-> DeleteDC ();

return FALSE;

}

if (SetPixelFormat (lDC-> GetSafeHdc (), pixelformat, & pfd)==FALSE)

{

MessageBox («usr_bSetupPixelFormat: SetPixelFormat failed BUM BUM BUM»);

lDC-> DeleteDC ();

return FALSE;

}

lDC-> DeleteDC ();

return TRUE;

}

BOOL CKarkasView: :usr_bInitOpenGL ()

{

HGLRC hrc;

tmpDC = new CClientDC (this);

if (!usr_bSetupPixelFormat ()) return FALSE;

hrc = wglCreateContext (tmpDC-> GetSafeHdc ());

if (!wglMakeCurrent (tmpDC-> GetSafeHdc (), hrc)) return FALSE;

usr_PreInit ();

return TRUE;

}

void CKarkasView: :usr_Destro OpenGL ()

{

HGLRC hrc;

hrc=: :wglGetCurrentContext ();

: :wglMakeCurrent (NULL, NULL);

if (hrc)

: :wglDeleteContext (hrc);

if (tmpDC)

tmpDC-> DeleteDC ();

}

int CKarkasView: :OnCreate (LPCREATESTRUCT lpCreateStruct)

{

if (CView: :OnCreate (lpCreateStruct) == -1)

return -1;

if (!this-> usr_bInitOpenGL ())

{

AfxMessageBox («Error with creating project! PIU!»);

return -1;

}

return 0;

}

void CKarkasView: :OnDestro ()

{

CView: :OnDestro ();

this-> usr_Destro OpenGL ();

}

void CKarkasView: :OnSize (UINT nT pe, int cx, int c)

{

CView: :OnSize (nT pe, cx, c);

int x = cx, = c;

usr_ReSize (0,0,x,);

}

void CKarkasView: :usr_ReSize (int x, int, int width, int height)

{

glViewport (0,0,(GLint)width,(GLint)height);

glMatrixMode (GL_PROJECTION);

glLoadIdentit ();

if (height == 0) asp = 1;

else

asp = (GLfloat)width/height;

gluPerspective (CurDepth, asp, 1,20);

glMatrixMode (GL_MODELVIEW);

}

void CKarkasView: :usr_RenderScene ()

{

glClearColor (0. 2f, 0. 6f, 0. 5f, 1);

glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

glLoadIdentit ();

glTranslatef (0,0,-4);

glTranslatef (TransX, Trans, 0);

glRotatef (XSceneRot, 0,1,0);

glRotatef (SceneRot, 1,0,0);

glRotatef (x7, 1, 0, 0);

glRotatef (1, 0, 1, 0);

glRotatef (3, 0, -1, 0);

glRotatef (x9, -1, 0, 0);

glRotatef (90,1,0,0);

GLUquadricObj * quadric = gluNewQuadric ();

gluQuadricDrawSt le (quadric, GLU_FILL);

if (Cloud_Enable==1)

{

glEnable (GL_TEXTURE_2D);

glEnable (GL_TEXTURE_GEN_S);

glEnable (GL_TEXTURE_GEN_T);

glPushMatrix ();

glColor3f (1,1,1);

glTranslatef (0,0,0. 45);

glTexGeni (GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);

glTexGeni (GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);

auxSolidSphere (10);

glPopMatrix ();

glDisable (GL_TEXTURE_GEN_S);

glDisable (GL_TEXTURE_GEN_T);

glDisable (GL_TEXTURE_2D);

}

glPol gonMode (GL_FRONT_AND_BACK, Pol gonMode);

glTranslatef (-1. 0,0. 0,0. 0);

glTranslatef (0. 0,0. 0+X, 0. 0);

glPushMatrix ();

glColor3dv (C1);

glTranslatef (0. 0,0. 0,0. 0);

glRotatef (90,0,1,0);

gluC linder (quadric, 0. 35, 0. 4, 0. 05, 50,40);

glTranslatef (0. 0,0. 0,0. 05);

gluC linder (quadric, 0. 4, 0. 4, 0. 35, 50,40);

glTranslatef (0. 0,0. 0,0. 35);

gluC linder (quadric, 0. 4, 0. 35, 0. 05, 50,40);

glTranslatef (0. 0,0. 0,0. 05);

gluC linder (quadric, 0. 35, 0. 0, 0. 0, 50,40);

glTranslatef (0. 0,0. 0,-0. 45);

gluC linder (quadric, 0. 35, 0. 0, 0. 0, 50,40);

glTranslatef (0. 0,0. 0,0. 4);

gluC linder (quadric, 0. 06, 0. 06, 1. 5, 50,40);

glPopMatrix ();

glPushMatrix ();

glColor3dv (C1);

glTranslatef (1. 8,0. 0,0. 0);

glRotatef (90,0,1,0);

gluC linder (quadric, 0. 35, 0. 4, 0. 05, 50,40);

glTranslatef (0. 0,0. 0,0. 05);

gluC linder (quadric, 0. 4, 0. 4, 0. 35, 50,40);

glTranslatef (0. 0,0. 0,0. 35);

gluC linder (quadric, 0. 4, 0. 35, 0. 05, 50,40);

glTranslatef (0. 0,0. 0,0. 05);

gluC linder (quadric, 0. 35, 0. 0, 0. 0, 50,40);

glTranslatef (0. 0,0. 0,-0. 45);

gluC linder (quadric, 0. 35, 0. 0, 0. 0, 50,40);

glPopMatrix ();

glPushMatrix ();

glColor3dv (C2);

glTranslatef (1. 15,0. 0,0. 0);

glRotatef (90,1,0,0);

auxSolidBox ((GLfloat)0. 7,0. 1,1. 1);

glTranslatef (0. 0,0. 0,-0. 55);

glRotatef (90,0,1,0);

auxSolidBox ((GLfloat)0. 2,0. 1,1. 5);

glTranslatef (0. 0,0. 0,-0. 75);

glRotatef (90,1,0,0);

auxSolidBox ((GLfloat)0. 2,0. 06,0. 3);

glTranslatef (0. 0,1. 5,0. 0);

auxSolidBox ((GLfloat)0. 2,0. 06,0. 3);

glPopMatrix ();

glPushMatrix ();

glColor3dv (C2);

glTranslatef (1. 15,-1. 4,0. 0);

glRotatef (90,1,0,0);

auxSolidBox ((GLfloat)1. 7,0. 1,1. 8);

glTranslatef (0. 0,0. 0,0. 9);

auxSolidBox ((GLfloat)0. 7,0. 1,1. 0);

glTranslatef (-0. 75,0. 0,0. 5);

glRotatef (90,0,1,0);

gluC linder (quadric, 0. 06, 0. 06, 1. 5, 50,40);

glPopMatrix ();

glPushMatrix ();

glColor3dv (C1);

glTranslatef (0. 0,-2. 75,0. 0);

glRotatef (90,0,1,0);

glTranslatef (0. 0,0. 0,0. 35);

gluC linder (quadric, 0. 4, 0. 35, 0. 05, 50,40);

glTranslatef (0. 0,0. 0,0. 05);

gluC linder (quadric, 0. 35, 0. 0, 0. 0, 50,40);

glTranslatef (0. 0,0. 0,-0. 6);

gluC linder (quadric, 0. 4, 0. 4, 0. 55, 50,40);

glTranslatef (0. 0,0. 0,-0. 05);

gluC linder (quadric, 0. 35, 0. 4, 0. 05, 50,40);

glTranslatef (0. 0,0. 0,-0. 0);

gluC linder (quadric, 0. 35, 0. 0, 0. 0, 50,40);

glPopMatrix ();

glPushMatrix ();

glColor3dv (C1);

glTranslatef (2. 1,-2. 75,0. 0);

glRotatef (90,0,1,0);

glTranslatef (0. 0,0. 0,0. 35);

gluC linder (quadric, 0. 4, 0. 35, 0. 05, 50,40);

glTranslatef (0. 0,0. 0,0. 05);

gluC linder (quadric, 0. 35, 0. 0, 0. 0, 50,40);

glTranslatef (0. 0,0. 0,-0. 6);

gluC linder (quadric, 0. 4, 0. 4, 0. 55, 50,40);

glTranslatef (0. 0,0. 0,-0. 05);

gluC linder (quadric, 0. 35, 0. 4, 0. 05, 50,40);

glTranslatef (0. 0,0. 0,-0. 0);

gluC linder (quadric, 0. 35, 0. 0, 0. 0, 50,40);

glPopMatrix ();

glPushMatrix ();

glColor3dv (C2);

glTranslatef (1. 15,-2. 75,-0. 1);

glRotatef (90,1,0,0);

auxSolidBox ((GLfloat)0. 3,0. 3,0. 6);

glPopMatrix ();

glPushMatrix ();

glColor3dv (C3);

glTranslatef (1. 0,-2. 8,-0. 7);

gluC linder (quadric, 0. 02, 0. 02, 0. 7, 50,40);

glTranslatef (0. 3,0. 0,0. 0);

gluC linder (quadric, 0. 02, 0. 02, 0. 7, 50,40);

glTranslatef (-0. 15,0. 0,0. 0);

auxSolidBox ((GLfloat)1. 6,0. 3,0. 03);

glTranslatef (0. 0,0. 0,-0. 1);

glRotatef (-40,1,0,0);

auxSolidBox ((GLfloat)1. 6,0. 03,0. 15);

glTranslatef (0. 79,0. 0,0. 02);

glRotatef (40,1,0,0);

auxSolidBox ((GLfloat)0. 03,0. 3,0. 15);

glTranslatef (-1. 58,0. 0,0. 02);

auxSolidBox ((GLfloat)0. 03,0. 3,0. 15);

glPopMatrix ();

glPushMatrix ();

glColor3dv (C2);

glTranslatef (1. 15,-0. 2,-0. 2);

glRotatef (15. 0,1,0,0);

auxSolidBox ((GLfloat)0. 6,1. 5,0. 03);

glPopMatrix ();

glPushMatrix ();

glColor3dv (C2);

glTranslatef (1. 9,-1. 5,-0. 2);

glRotatef (90. 0,0,1,0);

auxSolidBox ((GLfloat)0. 42,0. 6,0. 03);

glTranslatef (0. 0,0. 0,-1. 5);

auxSolidBox ((GLfloat)0. 42,0. 6,0. 03);

glTranslatef (0. 0,0. 48,0. 28);

glRotatef (60. 0,1,0,0);

auxSolidBox ((GLfloat)0. 4,0. 65,0. 03);

glTranslatef (0. 0,0. 8,0. 50);

glRotatef (-120. 0,1,0,0);

auxSolidBox ((GLfloat)0. 4,0. 65,0. 03);

glPopMatrix ();

glPushMatrix ();

glColor3dv (C2);

glTranslatef (1. 15,-2. 0,-0. 21);

glRotatef (-33. 0,1,0,0);

auxSolidBox ((GLfloat)1. 5,0. 55,0. 03);

glPopMatrix ();

glPushMatrix ();

glColor3dv (C2);

glTranslatef (1. 15,-1. 5,-0. 4);

auxSolidBox ((GLfloat)1. 54,0. 65,0. 1);

glPopMatrix ();

glPushMatrix ();

glColor3dv (C2);

glBegin (GL_POL GON);

glVertex3f (0. 849,0. 4,-0. 05);

glVertex3f (0. 849,-0. 9,-0. 4);

glVertex3f (0. 849,-0. 9,-0. 05);

glEnd ();

glTranslatef (0. 601,-0. 0,-0. 0);

glBegin (GL_POL GON);

glVertex3f (0. 85,0. 4,-0. 05);

glVertex3f (0. 85,-0. 9,-0. 4);

glVertex3f (0. 85,-0. 9,-0. 05);

glEnd ();

glBegin (GL_POL GON);

glVertex3f (1. 3,-1. 2,-0. 4);

glVertex3f (0. 8,-0. 9,-0. 4);

glVertex3f (0. 25,-0. 9,-0. 4);

glVertex3f (-0. 22,-1. 2,-0. 4);

glVertex3f (1. 3,-1. 2,-0. 4);

glEnd ();

glBegin (GL_POL GON);

glVertex3f (1. 3,-1. 8,-0. 33);

glVertex3f (1. 3,-1. 8,0. 0);

glVertex3f (1. 3,-2. 33,0. 0);

glEnd ();

glTranslatef (-1. 5,-0. 0,-0. 0);

glBegin (GL_POL GON);

glVertex3f (1. 3,-1. 8,-0. 33);

glVertex3f (1. 3,-1. 8,0. 0);

glVertex3f (1. 3,-2. 33,0. 0);

glEnd ();

glPopMatrix ();

glPushMatrix ();

glColor3dv (C2);

glTranslatef (1. 15,-1. 99,-0. 4);

glRotatef (90. 0,0,1,0);

auxSolidBox ((GLfloat)0. 8,0. 6,0. 4);

glTranslatef (0. 5,0. 26,0. 0);

glRotatef (90. 0,1,0,0);

glRotatef (-10. 0,0,1,0);

gluC linder (quadric, 0. 2, 0. 12, 0. 55, 16,40);

glPopMatrix ();

glPopMatrix ();

glFinish ();

gluDeleteQuadric (quadric);

glFinish ();

SwapBuffers (: :wglGetCurrentDC ());

}

BOOL CKarkasView: :OnEraseBkgnd (CDC* pDC)

{

return TRUE;

}

void CKarkasView: :usr_PreInit ()

{

glEnable (GL_DEPTH_TEST);

glEnable (GL_COLOR_MATERIAL);

glShadeModel (GL_SMOOTH);

glEnable (GL_LIGHTING);

glEnable (GL_NORMALIZE);

glEnable (GL_AUTO_NORMAL);

photo_image = auxDIBImageLoad («sea1. bmp»);

glPixelStorei (GL_UNPACK_ALIGNMENT, 1);

gluBuild2DMipmaps (GL_TEXTURE_2D, 3,

photo_image-> sizeX,

photo_image-> size ,

GL_RGB, GL_UNSIGNED_B TE,

photo_image-> data);

glLightModeli (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);

GLfloat light_position[] = { 1. 0, 0. 0, 0. 0, 1.0 };

glLightfv (GL_LIGHT0, GL_POSITION, light_position);

glEnable (GL_LIGHT0);

GLfloat light1_ambient[] = { 0. 2, 0. 2, 0. 2, 1.0 };

GLfloat light1_diffuse[] = { 1. 0, 1. 0, 1. 0, 1.0 };

GLfloat light1_specular[] = { 1. 0, 1. 0, 1. 0, 1.0 };

GLfloat light1_position[] = { -2. 0, 2. 0, 1. 0, 1.0 };

GLfloat spot_direction[] = { 1. 0, 1. 0, 1.0 };

glLightfv (GL_LIGHT1, GL_AMBIENT, light1_ambient);

glLightfv (GL_LIGHT1, GL_DIFFUSE, light1_diffuse);

glLightfv (GL_LIGHT1, GL_SPECULAR, light1_specular);

glLightfv (GL_LIGHT1, GL_POSITION, light1_position);

glLightf (GL_LIGHT1, GL_CONSTANT_ATTENUATION, 1. 5);

glLightf (GL_LIGHT1, GL_LINEAR_ATTENUATION, 0. 5);

glLightf (GL_LIGHT1, GL_QUADRATIC_ATTENUATION, 0. 2);

glLightf (GL_LIGHT1, GL_SPOT_CUTOFF, 45. 0);

glLightfv (GL_LIGHT1, GL_SPOT_DIRECTION, spot_direction);

glLightf (GL_LIGHT1, GL_SPOT_EXPONENT, 2. 0);

glEnable (GL_LIGHT1);

GLfloat light5_diffuse[] = {1. 0, 0. 0, 0. 0};

GLfloat light5_position[] = {1,0,1, 1. 0};

glEnable (GL_LIGHT5);

glLightfv (GL_LIGHT5, GL_DIFFUSE, light5_diffuse);

glLightfv (GL_LIGHT5, GL_POSITION, light5_position);

glLightf (GL_LIGHT5, GL_CONSTANT_ATTENUATION, 0. 0);

glLightf (GL_LIGHT5, GL_LINEAR_ATTENUATION, 0. 4);

glLightf (GL_LIGHT5, GL_QUADRATIC_ATTENUATION, 0. 8);

GLfloat light6_diffuse[] = {0. 0, 1. 0, 0. 0};

GLfloat light6_position[] = {1, 1, 1. 0};

glEnable (GL_LIGHT6);

glLightfv (GL_LIGHT6, GL_DIFFUSE, light6_diffuse);

glLightfv (GL_LIGHT6, GL_POSITION, light6_position);

glLightf (GL_LIGHT6, GL_CONSTANT_ATTENUATION, 0. 0);

glLightf (GL_LIGHT6, GL_LINEAR_ATTENUATION, 0. 4);

glLightf (GL_LIGHT6, GL_QUADRATIC_ATTENUATION, 0. 8);

GLfloat light7_diffuse[] = {0. 0, 0. 0, 1. 0};

GLfloat light7_position[] = {1, 1. 0, 1. 0};

glEnable (GL_LIGHT7);

glLightfv (GL_LIGHT7, GL_DIFFUSE, light7_diffuse);

glLightfv (GL_LIGHT7, GL_POSITION, light7_position);

glLightf (GL_LIGHT7, GL_CONSTANT_ATTENUATION, 0. 0);

glLightf (GL_LIGHT7, GL_LINEAR_ATTENUATION, 0. 4);

glLightf (GL_LIGHT7, GL_QUADRATIC_ATTENUATION, 0. 8);

}

void CKarkasView: :OnPersp ()

{

DlgPers object;

int result = object. DoModal ();

int arra [3]={0,0,0};

if (result==IDOK)

{

switch (object. checked_p)

{

case 1: {

glMatrixMode (GL_PROJECTION);

glLoadIdentit ();

glOrtho (object. m1, object. m2, object. m3, object. m4, object. m5, object. m6);

glMatrixMode (GL_MODELVIEW);

CKarkasView: :usr_RenderScene ();

AfxMessageBox («Changed to glOrtho»);

break; }

case 2: {

glMatrixMode (GL_PROJECTION);

glLoadIdentit ();

glFrustum (object. m1, object. m2, object. m3, object. m4, object. m5, object. m6);

glMatrixMode (GL_MODELVIEW);

CKarkasView: :usr_RenderScene ();

AfxMessageBox («Changed to glFrustum»);

break; }

case 3: {

glMatrixMode (GL_PROJECTION);

glLoadIdentit ();

gluPerspective (object. m1, object. m2, object. m3, object. m4);

glMatrixMode (GL_MODELVIEW);

CKarkasView: :usr_RenderScene ();

AfxMessageBox («Changed to gluPerspective»);

break; }

case 4: {

glMatrixMode (GL_PROJECTION);

glLoadIdentit ();

gluLookAt (object. m1, object. m2, object. m3, object. m4, object. m5, object. m6, object. m7, object. m8, object. m9);

glMatrixMode (GL_MODELVIEW);

CKarkasView: :usr_RenderScene ();

AfxMessageBox («Changed to gluLookAt»);

break; }

default:

glMatrixMode (GL_PROJECTION);

glLoadIdentit ();

gluPerspective (CurDepth, asp, 1,20);

glMatrixMode (GL_MODELVIEW);

CKarkasView: :usr_RenderScene ();

AfxMessageBox («Mode not selected — set to default»);

}

}

else AfxMessageBox («Отмена»);

}

void CKarkasView: :OnChar (UINT nChar, UINT nRepCnt, UINT nFlags)

{

switch (nChar) {

case 56: Trans -=0. 05; break;

case 50: Trans +=0. 05; break;

case 52: TransX+=0. 05; break;

case 54: TransX-=0. 05; break;

case 55: x7 += 2; if (x7==360)x7=0; break;

case 49: 1 += 2; if (1==360) 1=0; break;

case 57: x9 += 2; if (x9==360)x9=0; break;

case 51: 3 += 2; if (3==360) 3=0; break;

}

usr_RenderScene ();

CView: :OnChar (nChar, nRepCnt, nFlags);

}

BOOL CKarkasView: :OnMouseWheel (UINT nFlags, short zDelta, CPoint pt)

{

if (zDelta> 0)

CurDepth++;

else CurDepth--;

glMatrixMode (GL_PROJECTION);

glLoadIdentit ();

gluPerspective (CurDepth, asp, 1,20);

glMatrixMode (GL_MODELVIEW);

CKarkasView: :usr_RenderScene ();

return CView: :OnMouseWheel (nFlags, zDelta, pt);

}

void CKarkasView: :OnOptions ()

{

DlgOptions OptObj;

int result = OptObj. DoModal ();

if (result==IDOK)

{

if ((OptObj. m_rotate==true)/*&&(OptObj. m_rotate≠0)*/)

{

if (OptObj. m_speed≠0)

scene_rotate_speed=OptObj. m_speed;

else scene_rotate_speed=1;

if (OptObj. m_XRG==true)

{

if (OptObj. m_XGroup==1) XSceneRot=-1;

else XSceneRot=1;

}

else XSceneRot=0;

if (OptObj. m_ RG==true)

{

if (OptObj. m_ Group==1) SceneRot=-1;

else SceneRot=1;

}

else SceneRot=0;

if (FirstTimer==0)

{

FirstTimer=1;

SetTimer (1,scene_rotate_speed, NULL);

}

else

{

KillTimer (1);

SetTimer (1,scene_rotate_speed, NULL);

}

}

else

{

if (FirstTimer==1)

{

KillTimer (1);

FirstTimer=0;

}

XSceneRot=0;

SceneRot=0;

}

if (OptObj. m_Tex==1) Cloud_Enable=1;

else Cloud_Enable=0;

if (OptObj. Color1[0]≠-1)

{

C1[0]=OptObj. Color1[0];

C1[1]=OptObj. Color1[1];

C1[2]=OptObj. Color1[2];

}

if (OptObj. Color2[0]≠-1)

{

C2[0]=OptObj. Color2[0];

C2[1]=OptObj. Color2[1];

C2[2]=OptObj. Color2[2];

}

if (OptObj. Color3[0]≠-1)

{

C3[0]=OptObj. Color3[0];

C3[1]=OptObj. Color3[1];

C3[2]=OptObj. Color3[2];

}

switch (OptObj. m_Pol gon)

{

case 0: Pol gonMode=GL_FILL; break;

case 1: Pol gonMode=GL_LINE; break;

case 2: Pol gonMode=GL_POINT; break;

}

if (OptObj. m_L1==TRUE) glEnable (GL_LIGHT0); else glDisable (GL_LIGHT0);

if (OptObj. m_L2==TRUE) glEnable (GL_LIGHT1); else glDisable (GL_LIGHT1);

if (OptObj. m_L3==TRUE) glEnable (GL_LIGHT5); else glDisable (GL_LIGHT5);

if (OptObj. m_L4==TRUE) glEnable (GL_LIGHT6); else glDisable (GL_LIGHT6);

if (OptObj. m_L5==TRUE) glEnable (GL_LIGHT7); else glDisable (GL_LIGHT7);

if (OptObj. m_FOG==TRUE)

{

glEnable (GL_FOG);

switch (OptObj. m_FogMode)

{

case 0: glFogf (GL_FOG_MODE, GL_EXP2); break;

case 1: glFogf (GL_FOG_MODE, GL_EXP); break;

case 2: glFogf (GL_FOG_MODE, GL_LINEAR); break;

}

glFogfv (GL_FOG_COLOR, OptObj. FogColor);

glFogf (GL_FOG_DENSIT, 0. 2);

}

else glDisable (GL_FOG);

}

CKarkasView: :usr_RenderScene ();

}

void CKarkasView: :OnTimer (UINT nIDEvent)

{

switch (nIDEvent)

{

case 1:

{

if (XSceneRot> 0) XSceneRot++;

if (XSceneRot< 0) XSceneRot--;

if (SceneRot> 0) SceneRot++;

if (SceneRot< 0) SceneRot--;

}break;

case 2:

{

X+=0. 07;

if (X> =5)

{

KillTimer (2);

}

}break;

case 3:

{

X-=0. 07;

if (X< =0. 01)

{

KillTimer (3);

}

}break;

}

CKarkasView: :usr_RenderScene ();

CView: :OnTimer (nIDEvent);

}

void CKarkasView: :OnBum ()

{

if (X <= 0. 5)

{

SetTimer (2,100,NULL);

usr_RenderScene ();

}else

{

SetTimer (3,100,NULL);

usr_RenderScene ();

}

}

ПРИЛОЖЕНИЕ В.

Диаграмма классов

Рисунок В.1 — Диаграмма классов

ПРИЛОЖЕНИЕ Г.

Трёхмерная модель объекта «ГОНОЧНЫЙ АВТОМОБИЛЬ»

Рисунок Г.1 — Трехмерная модель объекта «Гоночный автомобиль»

Рисунок Г.2 — Окно настроек

ПРИЛОЖЕНИЕ Д

Перечень графического материала

Рисунок Д.1 — Прототип модели

ПоказатьСвернуть
Заполнить форму текущей работой