Вход

Программирование в Pascal. Моделирование 3D-объектов

Курсовая работа* по программированию
Дата добавления: 11 июня 2012
Язык курсовой: Русский
Word, rtf, 1.5 Мб
Курсовую можно скачать бесплатно
Скачать
Данная работа не подходит - план Б:
Создаете заказ
Выбираете исполнителя
Готовый результат
Исполнители предлагают свои условия
Автор работает
Заказать
Не подходит данная работа?
Вы можете заказать написание любой учебной работы на любую тему.
Заказать новую работу
* Данная работа не является научным трудом, не является выпускной квалификационной работой и представляет собой результат обработки, структурирования и форматирования собранной информации, предназначенной для использования в качестве источника материала при самостоятельной подготовки учебных работ.
Очень похожие работы

Федеоальное агенство по образованию РФ

государственное образовательное учреждение

высшего профессионального образования

Смоленский государственный университет










Программирование в Pascal. Моделирование 3D-объектов.

Курсовая Работа


Студента 3 курса

заочного отделения

физико-математического факультета

специальность: «Информатика»

Мялкина Ивана Андреевича

Научный руководитель:

Сенчилов Владислав Владимирович



Смоленск

2011г.





Оглавление

Введение. 3

Этапы развития компьютерной графики 5

Понятие трехмерной графики 8

Организация процесса построения проекции. 11

Проволочная модель 11

Отсечение нелицевых граней 12

Вращение 15

Программная реализация построения изображения. 17

Построение сложных моделей. 23

Заключение 27

Литература 28

Приложение 29





Введение.

Программная реализация построения изображения трехмерных объектов встречается все реже. Это вызвано большими затратами ресурсов вычислительной машины. В последнее время активно ведётся разработка систем построения объемных изображений, использующих графический процессор современных видеоадаптеров взамен центрального процессора. Сегодня эффективность видеоадаптеров для таких вычислений намного выше и позволяет строить более сложные и реалистичные сцены, но в то же время имеет ряд недостатков. Основным аспектом аппаратной визуализации в первую очередь является ориентация на скорость исполнения задачи, получение качественного результата задача второстепенная. Кроме того накладываются ограничения набором инструкций адаптера, предусмотренным производителем. Программную обработку можно встретить в основном в системах моделирования компании Autodesk. Иногда программное построение изображений имеет некоторые преимущества по сравнению с аппаратной реализацией – одним из главных особенностей является как разбиение процесса на множество потоков (распараллеливать, вследствие большого объема однотипных вычислений), и как следствие использовать в многопроцессорных системах. Как противопоставление, используя программные методы моделирования и построения изображения, программист ограничивается только собственной фантазией – примером такого продукта является система визуализации изображения V-Ray. Система V-ray позволяет моделировать крайне реалистичное освещение в трехмерных сценах, отражения и рассеивания света, и, вследствие, требует большего количества расчетов. Аппаратное построение по сравнению с программным наследует большинство основных принципов реализации – от расчета и построения нормалей до формирования z-buffer – отличие в выполнении расчетов на видеоадаптере, высвобождая центральный процессор для других задач.

Трехмерное моделирование или 3D графика позволяет решать множество задач и применяется различных сферах деятельности. Это как строительство – результатом может быть модель будущего дома, как частного, так и многоквартирного, офисного здания, или же любого промышленного объекта. Кроме того, визуализация активно применяется в дизайн-проектах интерьеров. Объемное изображение спроектированного сооружения отличается фотографической точностью и позволяет лучше представить себе, как будет выглядеть проект, воплощенный в жизни, внести определенные коррективы. 3D модель обычно производит гораздо большее впечатление, чем все остальные способы презентации будущего проекта. Передовые технологии позволяют добиваться потрясающих результатов. 3D модели популярны так же набирают популярность среди веб-дизайнеров. Многие конструкторы уже давно перешли от использования линейки и карандаша к современным трехмерным компьютерным программам. На основе трехмерного моделирования основаны и множество систем автоматизированного проектирования (САПР) для визуализации результатов, реализуемых математическим обеспечением для демонстрации тех или иных физических процессов. Постепенно новые технологии осваивают и другие компании, прежде всего, производственные и торговые, но не так активно.

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



Этапы развития компьютерной графики

Представление данных на мониторе компьютера в графическом виде впервые было реализовано в середине 50-х годов для больших ЭВМ, применявшихся в научных и военных исследованиях. Первые вычислительные машины не имели отдельных средств. Для работы с графикой, однако, уже использовались для получения и обработки изображений. Программируя память первых электронных машин, построенную на основе матрицы ламп, можно было получать узоры. В середине 1960-х гг. появились разработки в промышленных приложениях компьютерной графики. Графикой на тот момент занимались только при выводе на принтер, в этот период были заложены основные математические основы. Так, была разработана цифровая электронная чертёжная машина, немногим позже были представлены и первые системы автоматизированного проектирования. В 70-х годах начали появляться персональные компьютеры, т.е. появился доступ пользователя к дисплеям. Роль графики резко возросла, но наблюдалось очень низкое быстродействие компьютера, ввиду чего подавляющее большинство программ писалось на ассемблере. Но уже спустя совсем немного времени, в 80-х годах появились персональные компьютеры, позволяющие выводить графические объекты на экраны мониторов, что позволило использовать машинную графику в качестве инструмента специалистам различных областей, не связанных с программированием. Увеличение памяти и скорости обработки информации в персональных ЭВМ, создание видеокомплексов с широким набором программ машинной графики, возможность управления ими в диалоговом режиме способствовали дальнейшему расширению применения машинной графики. Важную, практически определяющую роль в этом процессе сыграл выпуск компанией Apple компьютеров Macintosh. Они были для своего времени настоящей революцией. Во-первых, Macintosh серийно поставлялся с цветным монитором. Во-вторых, его операционная система обладала наглядным, визуальным интерфейсом (своего рода аналог более поздней ОС Windows). И в-третьих, их мощности было достаточно для обработки графических изображений. Именно поэтому Macintosh сразу заслужил внимание множества профессиональных художников и дизайнеров, которые сменили карандаш и кисть на мышь и клавиатуру. С тех пор графический способ отображения данных стал неотъемлемой принадлежностью подавляющего числа компьютерных систем, в особенности персональных. Графический интерфейс пользователя сегодня является стандартом “де-факто” для программного обеспечения разных классов, начиная с операционных систем. Результат многолетнего развития технологий данного рода индустрии можно ежедневно наблюдать в повседневной жизни в неожиданных местах – от старой доброй растровой графики до векторной графики и 3D.

Для упрощения работы с графикой в настоящий момент существует ряд программных и аппаратных решений, позволяющих сконцентрироваться на основной задаче. На рынке широко представлены всевозможные графические акселераторы и массивы быстрой памяти. Ведущие производители электронных компонентов, такие как Intel и AMD, поддерживают обработку изображения на уровне процессорной техники (MMX, 3D Now), следовательно, становится возможным реализация «медленных», но дающих лучшее качество изображения алгоритмов. Среди средств, упрощающих написание программной части корпорация Microsoft предлагает два решения. Первое это DirectX, без которого не в состоянии работать подавляющее большинство приложений игровой индустрии. DirectX — это набор готовых классов, процедур, функций, структур и констант. DirectX представляет собой интерфейс программирования приложений ориентированный на упрощенное использование аппаратных мультимедиа-решений компьютера, а так же подразумевает прямой доступ к ним. DOS позволяла разработчику получить прямой доступ к видеокарте, клавиатуре/мыши/джойстику и прочим частям системы, в то время как новая ОС, Windows, с её защищённой моделью памяти, предоставляла более стандартизованный, но в то же время весьма ограниченный и накладный доступ к устройствам. Вторым решением для разработчиков является Microsoft XNA - набор инструментов с управляемой средой времени выполнения .NET для DirectX, облегчающий разработку и управление компьютерными играми и графическими приложениями. Использование этого продукта позволяет избежать многих технических трудностей и отстраниться от написания подсистемы вывода графики – остается подгрузить уже заранее подготовленные структуры объектов (модели) и описать их взаимодействие в процессе работы приложения.

Существует ряд конкурирующих решений, таких как OpenGL - открытая графическая библиотека. Это довольно мощный независимый от языка программирования, кросс-платформенный программный интерфейс для написания приложений, использующих как двумерную, так и трёхмерную компьютерную графику. Он включает в себя более 250 функций для рисования сложных трёхмерных сцен из простых примитивов, довольно часто используется при создании компьютерных игр, САПР, систем виртуальной реальности, а так же визуализации в научных исследованиях. Существенным преимуществом платформы являются эффективные реализации OpenGL для Windows, Unix-платформ, PlayStation 3 и Mac OS, в отличие от DirectX, применимого только в среде Windows. Еще одной важной особенностью среды является возможность исключительно программной реализации спецификации OpenGL одной из которых является библиотека Mesa в случае отсутствия аппаратных средств либо скудной производительности последних. Для программиста OpenGL хорош не только своей сравнительной простотой реализации и наглядной простотой кода, но и большим выбором дополнительных библиотек, позволяющим расширить возможности среды. Яркими представителями являются GLU и GLUT.


Понятие трехмерной графики

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

Рисунок 1

Задача трёхмерного моделирования — описать эти объекты и разместить их в сцене с помощью геометрических преобразований в соответствии с требованиями к будущему изображению. Математическая либо векторная пространственная модель превращается в плоскую (растровую) картинку. Если требуется создать фильм, то обрабатывается целая последовательность таких картинок — кадров. Как структура данных, изображение на экране представлено матрицей точек. Таким образом, процесс получения изображения преобразует трёхмерную векторную структуру данных в плоскую матрицу пикселов. Этот шаг часто требует очень сложных вычислений, особенно если требуется создать иллюзию реальности.

При работе с трехмерной графикой используется несколько видов систем координат. Для отображения двумерных объектов использовалась соответствующая система координат с двумя осями – горизонтальной осью X и вертикальной осью Y. Экранная система координат для двумерной графики имеет начало (точку 0,0) в левом верхнем углу монитора, положительная часть оси X располагается справа от начала координат, положительная часть оси Y – снизу.

Для работы с трехмерными объектами необходима еще одна ось – ось Z (рис.2). Существует несколько вариантов трехмерных систем координат, в частности, распространены так называемые правосторонняя и левосторонняя системы.

Рисунок 2

Особенность этой системы координат заключается в том, что начало координат можно сопоставить с левым нижним углом монитора, положительная часть оси X находится справа от начала координат, положительная часть оси Y – сверху, а положительная часть оси Z – спереди. А это значит, что видимая часть оси Z – это её отрицательная часть. Эта часть оси находится как бы «в глубине монитора», в то время как положительная часть находится «спереди монитора». В двумерной системе координат существует понятие точки – ее координаты задаются двумя значениями – X и Y. Точки существуют и в трехмерной системе координат – они задаются уже тремя значениями – X, Y, Z.

Точки используют для того, чтобы задавать координаты вершин многоугольников (полигонов), в частности – треугольников. Так, треугольник, задан тремя точками – A, B, C. Как правило, более сложные трехмерные объекты строятся именно из треугольников.

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

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

Несколько граней, из которых состоит трехмерный объект, называются сеткой. "Сетка" представляет собой набор треугольников.

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

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

В трёхмерной компьютерной графике все объекты обычно представляются как набор поверхностей или частиц. Минимальную поверхность (некоторую плоскость, ограниченную набором точек и ребер) иногда называют полигоном. Любой полигон можно представить в виде набора из координат его вершин. Так, у треугольника будет 3 вершины. Координаты каждой вершины представляют собой вектор (x, y, z). Умножив вектор на соответствующую матрицу, мы получим новый вектор. Сделав такое преобразование со всеми вершинами полигона, получим новый полигон, а преобразовав все полигоны, получим новый объект, повёрнутый/сдвинутый/масштабированный относительно исходного.

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

Организация процесса построения проекции.

Проволочная модель

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

Yt = Y * COS(Xan) - Z * SIN(Xan)

Zt = Y * SIN(Xan) + Z * COS(Xan)

Y = Yt

Z = Zt

Xt = X * COS(Yan) - Z * SIN(Yan)

Zt = X * SIN(Yan) + Z * COS(Yan)

X = Xt

Z = Zt

Xt = X * COS(Zan) - Y * SIN(Zan)

Yt = X * SIN(Zan) + Y * COS(Zan)

X = Xt <-- выводим

Y = Yt <-- выводим

Фактически для каждой точки мы должны вычислить X и Y, и вывести на экран. В случае построения полигональных моделей третья координата необходима только для отсечения нелицевых граней.

Отсечение нелицевых граней

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

Нормаль — это прямая, ортогональная (перпендикулярная) касательной прямой к некоторой кривой или касательной плоскости к некоторой поверхности (рис.3). Большое значение при построении объектов имеет не сама нормаль, а ее вектор.

Рисунок 3

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

Предположим, существует объект, внутри которого камера (позиция наблюдателя) заведомо не окажется. Обычно такого рода объекты составляют большую часть или всю сцену. Тогда для каждой грани наблюдатель способен увидеть только одну ее сторону - лицевую. Грань - плоскость, она делит все 3D пространство на два полупространства. Таким образом, лицевую сторону видно только из одного полупространства, из того, в которое "смотрит" нормаль к этой грани, направленная из объекта. Проверив, в какое полупространство попадает камера, можно сразу определить, является ли грань лицевой (то есть, может ли камера увидеть лицевую сторону этой грани) и надо ли ее рисовать.

Пусть грань имеет вершины v1, v2, v3 и нормаль (nx,ny,nz). Тогда уравнение плоскости, в которой она лежит, будет иметь вид

nx*x+ny*y+nz*z+d = 0.

d находим из того факта, что v1 в плоскости лежит:

nx*v1.x+ny*v1.y+nz*v1.z+d = 0,

d = -(nx*v1.x+ny*v1.y+nz*v1.z).

Функция nx*x+ny*y+nz*z+d принимает положительные значения по одну сторону от плоскости, отрицательные по другую и равна нулю на самой плоскости. Точка (v1.x+nx,v1.y+ny,v1.z+nz) лежит, очевидно, в том полупространстве, откуда грань видно. Значение функции (назовем ее функцией видимости) в этой точке равно

nx*(v1.x+nx)+ny*(v1.y+ny)+nz*(v1.z+nz)+d = nx*(v1.x+nx)+ny*(v1.y+ny)+nz*(v1.z+nz)-(nx*v1.x+ny*v1.y+nz*v1.z) = nx*nx+ny*ny+nz*nz > 0.

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

-nz*dist-(nx*v1.x+ny*v1.y+nz*v1.z) < 0,

или, что равносильно,

nz*dist+nx*v1.x+ny*v1.y+nz*v1.z > 0,

заведомо не видны и время на их обработку и отображение тратить не стоит.

Отдельного рассмотрения требует вопрос расчета нормали к граням. Точнее, как выбрать одну из двух нормалей, смотрящую из объекта. Обычно эта проблема решается еще на этапе построения 3D моделей - некоторые пакеты для 3D-моделирования заранее записывают вершины граней в порядке A-B-C так, чтобы векторное произведение BA*CA и было нормалью. Еще один способ - выбрать внутреннюю точку для объекта (либо вручную, либо взять его центр тяжести, либо любым другим способом - методов может быть придумано сколь угодно) и использовать ее: если для этой точки функция видимости положительна, то есть грань якобы видна, то необходимо поменять знак nx, ny и nz.

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

Вращение

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

Рассмотрим для примера поворот точки (x,y,z) относительно оси z. В этом случае z не изменяется вовсе, а (x,y) изменяются так же, как и при повороте на плоскости относительно начала координат. Рассмотрим, какие координаты получит точки A' в результате поворота A(x,y) на некоторый угол ?.

Рисунок 4

Пусть

Пусть угол AOx равен ?, тогда из рисунка 4 видно, что

cos(? i) = x/r, sin(?) = y/r.

Угол A'OA равен по условию ?.

Отсюда

x' = r*cos(?+ ?) = r*(cos(?)*cos(?)-sin(?)*sin(?)) =

= (r*cos(?))*cos(?)-(r*sin(?))*sin(?) =

= x*cos(?)-y*sin (?))

y' = r*sin(? + ?) = r*(cos(?)*sin(?)+sin(?)*cos(?)) =

= (r*cos(?))*sin(?)+(r*sin(?))*cos(?) =

= x*sin(?)+y*cos(?)

Рассматривая случай с трехмерным пространством, таким образом

x' = x*cos(?)-y*sin(?)

y' = x*sin(?)+y*cos(?)

z' = z

Аналогично выводятся формулы и для других осей поворота (Ox, Oy). Поворот относительно произвольной оси, проходящей через начало координат, можно сделать с помощью этих поворотов - сделать поворот относительно Ox так, чтобы ось поворота стала перпендикулярна Oy, затем поворот относительно Oy так, чтобы ось поворота совпала с Oz, сделать собственно поворот, а затем обратные повороты относительно Oy и Ox. В результате чего соответственно получаем:

Y:=Y*cos(xv)-Z*sin(xv)

Z:=Y*sin(xv)+Z*cos(xv)

Здесь Y, Z это координаты вершины, а xv – угол поворота в градусах. Аналогично решаются задачи для поворота по оси X:

X:=X*cos(yv)-Z*sin(yv)

Z:=X*sin(yv)+Z*cos(yv)

И, соответственно, по оси Z:

X:=X*cos(zv)-Y*sin(zv)

Y:=X*sin(zv)+Y*cos(zv)

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

Программная реализация построения изображения.

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

Error 15: File not found (GRAPH.TPU)

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

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

Основной задачей при создании и выводе объемной графики на экран является преобразование трех координат в две, так как на экран можно вывести лишь 2 координаты. Учитывая, что "структуры данных+ алгоритмы= программы", определим изначально структуры данных.

Чем же является 3D-объект. Наиболее просто его можно представить в виде совокупности точек, комбинируя которые в пары или по тройкам можно в дальнейшем получать соответственно требуемые модели. Таким образом для работы с 3D объектами будет достаточно обычного массив точек:

array[1..n] of record x,y,z:double end;

или

array[1..n1*3]of double;

В первом случае задан массив точек (record~point) а во втором массив координат, который необходимо интерплитировать как:

( (x1,y1,z1),(x2,y2,z2), ... ,(xi,yi,zi), ... ,(xn,yn,zn) )

Таким образом каждые 3 элемента массива - точка.

Организовывая первым способом массивы для хранения координат для фигур создадим пользовательский тип записи (для более удобной работы с координатами):

type

d3d=record

x,y,z : real;

end;

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

const tet: array[1..4] of d3d =

((x:50;y:80;z:50),

(x:50;y:0;z:80),

(x:100;y:0;z:0),

(x:0;y:0;z:0));

Аналогично можно поступить, задавая координаты куба. Суть остается прежней, изменится только количество вершин:

const cub : array[1..8] of d3d =

((x:-50;y:-50;z:50),

(x:-50;y:50;z:50),

(x:50;y:50;z:50),

(x:50;y:-50;z:50),

(x:-50;y:-50;z:-50),

(x:-50;y:50;z:-50),

(x:50;y:50;z:-50),

(x:50;y:-50;z:-50));

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

grDriver := Detect;

InitGraph(grDriver, grMode,'');

ErrCode := GraphResult;

На этом этапе предоставим графической системе возможность самостоятельно определить графический режим. Так как современные графические адаптеры, а так же непосредственно видеодисплеи, имеют гораздо большие возможности, всвязи с этим можно предположить, что графическим драйвером будет EGAVGA. Главное при этом иметь необходимый внешний модуль для среды разработки.

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

  1. установка цвета по умолчанию и отчистка экрана;

  2. поворот фигуры на заданный угол, в случае если он задан;

  3. отрисовка текущей проекции фигуры;

  4. проверка действий пользователя.

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

if ErrCode = grOk then

begin { если инициализация графического режима успешна, то }

setcolor(0); {установка цвета}

repeat

clrscr;

DrawVector; {процедура отрисовки фигуры}

delay(4000);

rotateAll; {поворот фигур}

if keypressed then {обработка нажатия клавиши пользователем}

begin

CodeKey:=readkey;

end;

case codekey of {были нажаты клавиши отвечающие за вращение}

'w':a1:=4.0; {укажем соответствующие углы поворота}

'a':a2:=4.0;

's':a3:=4.0;

'd':a2:=-4.0;

'1':figura:=1;

'2':figura:=2;

end;

until CodeKey=#27; {выход из цикла по нажатию Esc}

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

Для проверки видимости введем небольшую функцию проверки грани:

function TestGran(a, b, c : d3d) : boolean;

var v1, w2, v2, w1, n : real;

begin

v1:=a.x-c.x;

v2:=a.y-c.y;

w1:=b.x-c.x;

w2:=b.y-c.y;

n:=v1*w2-v2*w1;

if n>0 then

TestGran:=true {грань видна }

else

TestGran:=false; {грань не видна }

end;

Здесь выполняется построение нормали относительно грани, заданной тремя точками. Грань можно представить в виде треугольника для упрощения расчетов, как известно прямоугольник можно разбить на два треугольника. Единственным ограничением будет являться только то, что прямоугольник должен являться выпуклым, в противном случае могут возникнуть «артефакты» при отрисовке граней. Впоследствие выполняется проверка ориентации нормали в соответствие с приложенным способом. Основной нюанс состоит в том, что все точки в вершинах граней задаются в одном направлении - по часовой либо против часовой стрелки. Направление обхода крайне важно соблюдать, иначе существует некоторая вероятность, как отмечалось ранее, получить неверное направление нормали относительно плоскости. Нормаль к треугольнику - это векторное произведение сторон- векторов, образованных вершинами. Нормаль будет располагаться снаружи у всех граней, и по знаку нормали можно судить, видим ли мы лицевую сторону или изнанку. Если скалярное произведение вектора зрения на нормаль плоскости (треугольника в плоскости) меньше или равно 0, значит плоскость (треугольник) повернут к наблюдателю либо изнаночной стороной, либо ребром, и отображать его нет необходимости.

Далее если грань видна, остается вывести ее на экран. Для этих целей применима встроенная в модуль языка Паскаль процедура FillPoly, которой можно передать заранее подготовленные координаты на экране и формат заливки. Процедура FillPoly вычисляет все горизонтальные пересечения, а затем закрашивает многоугольник, используя текущий стиль и цвет закраски, определенные с помощью сопутствующих процедур SetFillStyle и SetFillPattern. Контур многоугольника выделяется текущим цветом и типом линии, установленными при обращении к процедурам SetLineStyle и SetColor. Так как изначально координаты заданы относительно начала координат, необходимо задать некоторое приращение для расположения объекта в видимой части экрана. В данном случае объект будет отображен строго по центру экрана, учитывая что установленная разрешающая способность составляет 640х480 пикселей:

setfillstyle(1, col); {определяем тип заполнения }

zar[1].x:=round(p1.x+320);

zar[1].y:=round(p1.y+240);

zar[2].x:=round(p2.x+320);

zar[2].y:=round(p2.y+240);

zar[3].x:=round(p3.x+320);

zar[3].y:=round(p3.y+240);

zar[4].x:=round(p4.x+320);

zar[4].y:=round(p4.y+240);

Так как плоскость отображения двухмерная, для воссоздания проекции на экране достаточно воспользоваться только двумя координатами – х и у, z нам нужна только для определения положения грани – выходит она на передний план или нет. Рассчитывать и отрисовывать программно ее имело смысл только при построении «проволочной модели». Впоследствии остается проверить является ли полученная грань треугольником или четырехугольником и отобразить ее:

if (zar[1].x=zar[4].x) and (zar[1].y=zar[4].y)

then fillpoly(3, zar)

else fillpoly(4, zar);

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

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

DrawGran(tet[1],tet[2], tet[3],tet[1], 1);

DrawGran(tet[1],tet[3], tet[4],tet[1], 2);

DrawGran(tet[1],tet[4], tet[2],tet[1], 3);

DrawGran(tet[4],tet[3], tet[2],tet[4], 4);

И для куба:

DrawGran(cub[4],cub[3], cub[2],cub[1], 11);

DrawGran(cub[5],cub[6], cub[7],cub[8], 12);

DrawGran(cub[1],cub[2], cub[6],cub[5], 13);

DrawGran(cub[3],cub[4], cub[8],cub[7], 14);

DrawGran(cub[2],cub[3], cub[7],cub[6], 15);

DrawGran(cub[5],cub[8], cub[4],cub[1], 16);



Построение сложных моделей.

Используя данную методику можно построить более сложные полигональные модели, состоящие из большего числа граней. Рядом трудностей, с которыми можно столкнуться на данном этапе в условиях выбранной среды программирования может являться отсутствие большей палитры цветов и градиентов для выделения каждой грани выбранным методом, а так же отсутствие нормальных средств работы с динамической памятью среды. К тому же среда MS-DOS накладывает ограничение на размер выделяемого участка памяти. Грань ограничена определенным числом точек, относительно которых строится. Используя большее число граней (а соответственно и точек) возможна организация более сложных объектов, таких как цилиндр. Особенностью цилиндра является его структура. Цилиндр это геометрическое тело, ограниченное цилиндрической поверхностью и двумя параллельными плоскостями, пересекающими её. Построить цилиндр в чистом виде невозможно, так как необходимо неким образом задать координаты боковой поверхности, не имеющей в своем составе граней и являющейся идеально гладкой. Для разрешения данной проблемы цилиндр (его боковую поверхность) при построении разбивают на множество граней.

Рисунок 5

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

for j:=1 to 10 do

begin

cyl[j].y:=50*sin(rad*(40*j));

cyl[j].x:=50*cos(rad*(40*j));

cyl[j].z:=50;

cyl[j+10].y:=50*sin(rad*(40*j));

cyl[j+10].x:=50*cos(rad*(40*j));

cyl[j+10].z:=-50;

end;

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

for i:=1 to 9 do

begin

DrawGran(cyl[0],cyl[i], cyl[i+1],cyl[0], i+7);

DrawGran(cyl[21],cyl[10+i+1], cyl[10+i],cyl[21], i+7);

DrawGran(cyl[10+i],cyl[10+i+1], cyl[i+1],cyl[i], i+7);

end;

При использовании сложных конструкций в первую очередь потребует пересмотра алгоритм проверки граней на видимость со стороны наблюдателя. Существует ряд простых решений для отброса граней кроме построения нормалей. Можно воспользоваться «алгоритмом художника». Заключается он в следующем. Пусть имеется некий набор граней (т.е. сцена), который требуется нарисовать. Производится сортировка граней по удаленности от камеры. Далее выполняется отрисовка всех граней, начиная с самых удаленных. Довольно распространенная характеристика удаленности для грани ABC - это среднее значение z, mid_z = (A.z+B.z+C.z)/3. По существу это весь алгоритм. Просто, и обычно достаточно быстро. Но существует несколько проблем. При некотором расположении граней этот алгоритм вообще не может дать правильного результата вне зависимости от порядка. При некотором расположении граней и использовании среднего значения z как характеристики удаленности алгоритм дает неправильный результат (рис.6).

Рисунок 6

В этом случае горизонтальную грань нужно отрисовать второй, но по среднему значению z она лежит дальше и таким образом получается, что ее нужно вывести на экран первой. В итоге, при использовании этого алгоритма отрисовываются вообще все грани сцены. И при большом количестве загораживающих друг друга граней будет расходоваться значительно большая часть времени на вывод невидимых в конечном итоге частей. То есть совершенно впустую. В случае с построением нормали такого рода проблемы не возникает. Однако, метод нормалей будет неприемлем для следующей стандартной ситуации:

Рисунок 7

В качестве решения может быть использован метод с использованием Z-буфера. Z-буферизация - в компьютерной трёхмерной графике это способ учёта удалённости элемента изображения. Представляет собой один из вариантов решения «проблемы видимости». Он очень эффективен и практически не имеет недостатков, если реализуется аппаратно т.к. достаточно ресурсоемок в программном исполнении. Программно существуют некоторые альтернативы, способные конкурировать с ним: например, двоичное разбиение пространства (BSP), но они также имеют свои достоинства и недостатки. Основной недостаток Z-буферизации состоит в потреблении большого объёма памяти: в работе используется так называемый буфер глубины (Z-буфер). Z-буфер представляет собой двумерный массив, каждый элемент которого соответствует пикселу на экране. Когда видеокарта рисует пиксел, его удалённость просчитывается и записывается в ячейку Z-буфера. Если пикселы двух рисуемых объектов перекрываются, то их значения глубины сравниваются, и рисуется тот, который ближе, а его значение удалённости сохраняется в буфер. Получаемое при этом графическое изображение носит название z-depth карта, представляющая собой полутоновое графическое изображение, каждый пиксел которого может принимать до 256 значений серого. По ним определяется удалённость от зрителя того или иного объекта трехмерной сцены.



Заключение

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

  1. анализ применения 3D графики в настоящее время;

  2. выяснения механизма построения графических объектов;

  3. выбор оптимального алгоритма для предложенной среды программирования и операционной системы;

  4. реализация программы построения трехмерных объектов с анимацией.

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



Литература

  1. Зуев Е.А. Программирование на языке TURBO PASCAL 6.0/7.0 М. Веста, Радио и связь, 1993.

  2. Александр Фролов, Григорий Фролов Операционная система MS-DOS М.: Диалог-МИФИ, 1991.

  3. Эдвард Энджел Интерактивная компьютерная графика. Вводный курс. 2-е изд. Вильямс, 2001

  4. Горнаков С. Г. Программирование компьютерных игр под Windows в XNA Game Studio Express. – М.: ДМК Пресс, 2008.

  5. Керниган Б.В., Пайк Р. UNIX – универсальная среда программирования. М.: Финансы и статистика, 1992



Приложение

Код приложения

uses crt, graph; {подключение графических модулей}

const rad : real=0.01745329; {коэффициент преобразования градусов в радианы}



type {пользовательский тип "трехмерная "}

d3d=record

x,y,z : real;

end;



var

j : integer; {переменная цикла }

figura:integer;

CodeKey:char;

a1,a2,a3:real;

ErrCode, grMode, grDriver : Integer; {переменные графического драйвера}



const tet: array[1..4] of d3d =

((x:50;y:80;z:50),

(x:50;y:0;z:80),

(x:100;y:0;z:0),

(x:0;y:0;z:0));

const cub : array[1..8] of d3d =

((x:-50;y:-50;z:50),

(x:-50;y:50;z:50),

(x:50;y:50;z:50),

(x:50;y:-50;z:50),

(x:-50;y:-50;z:-50),

(x:-50;y:50;z:-50),

(x:50;y:50;z:-50),

(x:50;y:-50;z:-50)

);

var cyl:array[0..21]of d3d;



{проверка грани на видимость} {a, b, c -координаты грани}

function TestGran(a, b, c : d3d) : boolean;

var v1, w2, v2, w1, n : real; {внутренние переменные для построения нормали к грани}

begin

{построение нормали }

v1:=a.x-c.x;

v2:=a.y-c.y;

w1:=b.x-c.x;

w2:=b.y-c.y;

n:=v1*w2-v2*w1; {проверка видимости}



if n>0 then

TestGran:=true {грань видна }

else

TestGran:=false; {грань не видна }

end;



{процедура рисования граней} {p1, p2, p3 - координаты грани}

{col - цвет грани}

procedure DrawGran(p1, p2, p3,p4:d3d; col : byte);

var

zar : array [1..4] of pointtype; {внутренний тип для заливки грани заданным цветом}

begin

if TestGran(p1, p2, p3)=false then exit;

setfillstyle(1, col); {определение типа заполнения }

{обработка внутренних переменные для заполнения }

zar[1].x:=round(p1.x+320);

zar[1].y:=round(p1.y+240);

zar[2].x:=round(p2.x+320);

zar[2].y:=round(p2.y+240);

zar[3].x:=round(p3.x+320);

zar[3].y:=round(p3.y+240);

zar[4].x:=round(p4.x+320);

zar[4].y:=round(p4.y+240);

if (zar[1].x=zar[4].x) and (zar[1].y=zar[4].y)

then fillpoly(3, zar)

else fillpoly(4, zar); {заполнить грань заданным цветом}

setfillstyle(6, 1); {определение типа заполнения }

end;

{процедура рисования вектора }

procedure DrawVector;

var i:integer;

begin

if figura =1 then

begin

DrawGran(tet[1],tet[2], tet[3],tet[1], 1);

DrawGran(tet[1],tet[3], tet[4],tet[1], 2);

DrawGran(tet[1],tet[4], tet[2],tet[1], 3);

DrawGran(tet[4],tet[3], tet[2],tet[4], 4);

end;



if figura =2 then

begin

DrawGran(cub[4],cub[3], cub[2],cub[1], 11);

DrawGran(cub[5],cub[6], cub[7],cub[8], 12);

DrawGran(cub[1],cub[2], cub[6],cub[5], 13);

DrawGran(cub[3],cub[4], cub[8],cub[7], 14);

DrawGran(cub[2],cub[3], cub[7],cub[6], 15);

DrawGran(cub[5],cub[8], cub[4],cub[1], 16);

end;



if figura =3 then

begin

for i:=1 to 9 do

begin

DrawGran(cyl[0],cyl[i], cyl[i+1],cyl[0], i+7);

DrawGran(cyl[21],cyl[10+i+1], cyl[10+i],cyl[21], i+7);

DrawGran(cyl[10+i],cyl[10+i+1], cyl[i+1],cyl[i], i+7);

end;

end;

end;



{процедура поворота точки в трехмерном пространстве}

{xv, yv, zv - углы поворота точки в градусах}

{x, y, z - точка, которую нужно повернуть}

procedure rotate(xv,yv,zv:real; var x,y,z:real);

var Yt,Xt,Zt:real; {временные переменные}

begin

{повернуть по оси y}

Yt:=Y*cos((xv*rad))-Z*sin((xv*rad));

Zt:=Y*sin((xv*rad))+Z*cos((xv*rad));

Y:=Yt; Z:=Zt;

{повернуть по оси x}

Xt:=X*cos((yv*rad))-Z*sin((yv*rad));

Zt:=X*sin((yv*rad))+Z*cos((yv*rad));

X:=Xt; Z:=Zt;

{повернуть по оси z}

Xt:=X*cos((zv*rad))-Y*sin((zv*rad));

Yt:=X*sin((zv*rad))+Y*cos((zv*rad));

X:=Xt; Y:=Yt;

end;



procedure RotateAll;

begin

for j := 1 to 4 do rotate(a1,a2,a3,tet[j].x,tet[j].y,tet[j].z);

for j := 1 to 8 do rotate(a1,a2,a3,cub[j].x, cub[j].y,cub[j].z);

for j := 0 to 21 do rotate(a1,a2,a3,cyl[j].x,cyl[j].y,cyl[j].z);

end;



begin

grDriver := Detect; {инициализация графического режима}

InitGraph(grDriver, grMode,'');

ErrCode := GraphResult;

figura:=1;



a1:=3;

a2:=4;

a3:=1;

cyl[0].z:=50;

cyl[21].z:=-50;



for j:=1 to 10 do

begin

cyl[j].y:=50*sin(rad*(40*j));

cyl[j].x:=50*cos(rad*(40*j));

cyl[j].z:=50;

cyl[j+10].y:=50*sin(rad*(40*j));

cyl[j+10].x:=50*cos(rad*(40*j));

cyl[j+10].z:=-50;

end;



if ErrCode = grOk then

begin { если инициализация успешна, то }

setcolor(0); {установка цвета}

repeat

delay(1000);

clrscr;

DrawVector;

delay(4000);

rotateAll;

if keypressed then

begin

a1:=0; {остановка вращения}

a2:=0;

a3:=0;

CodeKey:=readkey;

end;

case codekey of

'w':a1:=4.0;

'a':a2:=4.0;

's':a3:=4.0;

'd':a2:=-4.0;

'1':figura:=1;

'2':figura:=2;

'3':figura:=3;

end;

until CodeKey=#27; {выход по нажатию клавиши Esc}

end;

end.









© Рефератбанк, 2002 - 2024