AlexeySpace.Ru

Программирование трехмерной графики. Часть 1.

1.1. Основные соглашения

1.2. Точка в пространстве

1.3. Создание буфера рисования

1.4. Программа генерации точек в пространстве


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

1.1. Основные соглашения

Для программирования трехмерной графики мы будем использовать интегрированную среду программирования Borland Delphi 7.0 (все примеры и программы написаны именно на ней). А вывод графики будем осуществлять через стандартный графический класс TCanvas, который присутствует практически у всех визуальных компонентов Delphi. Я не буду здесь описывать принципы работы в среде Borland Delphi и основ программирования на языке Object Pascal. Это отдельная и большая тема. Предполагается, что у вас уже есть опыт работы в Delphi, а также навыки программирования графики с помощью класса TCanvas. Если нет, то придется наверстать. Тем более что в интернете достаточно информации на эту тему.

Сразу скажу, что используя данный класс для вывода графики, нам не удаться добиться высокой скорости отрисовки объектов, и уж тем более сделать на нем свой DOOM 3. Но нам это и не нужно. Для изучения основ трехмерности он вполне пригоден. К тому же этот класс скрывает от нас множество ненужных проблем, которые у нас возникли бы, если бы мы выводили графику через низкоуровневые API – функции. Я уже не говорю про низкоуровневую работу с видеоадаптером. Вот там настоящий АД!

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

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

1.2. Точка в пространстве

Итак, что бы описать точку в пространстве, достаточно создать вот такую структуру:

// Структура, описывающая точку в пространстве TPoint3D = record X: Real; Y: Real; Z: Real; end;

На рисунке (1.2.1) видно, что каждая координата точки задает плоскость параллельную противоположенной координатной плоскости. Например, координата X – задает плоскости, которая параллельна координатной плоскости YZ. Пересечение всех трех плоскостей и дает нам искомое расположение точки в пространстве. На рисунке – это точка A.

Рис 1.2.1. Точка в пространстве

Итак, у нас имеются координаты точки в пространстве (X, Y, Z). Как же теперь нам отобразить эту точку на экране монитора? Очень просто! Для того что бы отобразить ее на мониторе, нам нужно спроецировать ее на плоскость экрана. Поэтому следующее, что нам понадобится – это формулы перевода трехмерных координат, в двухмерные, т.е. формулы проецирования.

Казалось бы, зачем нам какие-то формулы, когда можно просто взять (X, Y) – координаты точки, и по этим значениям нарисовать ее на экране? А координату Z – просто отбросить... В этом случае у нас получится параллельное (ортогональное) проецирование точки. Так конечно тоже можно сделать, и объекты, построенные на экране, таким образом, тоже будут казаться трехмерными. Но все-таки отображаться они буду не очень красиво. Дело в том, что построенное таким образом изображение, не будет учитывать эффекта перспективы . Такой вид проекции используется в основном в техническом черчении.

Поэтому в программировании трехмерной графики лучше использовать центральное (перспективное) проецирование.

Посмотрите на рисунки (1.2.2), (1.2.3), (1.2.3) и (1.2.5), на них видны основные отличия между параллельной и центральной проекциями.

Рис 1.2.2. Параллельная (ортогональная) проекция

Рис 1.2.3. Параллельная (ортогональная) проекция трехмерного куба

Рис 1.2.4. Центральная (перспективная) проекция

Рис 1.2.5. Центральная (перспективная) проекция трехмерного куба
  • Красные линии на рисунках – лучи проецирования.
  • Синие точки – точки проецируемого объекта c координатами: (X, Y, Z).
  • Красные точки – проекции синих точек на плоскость экрана.

По рисункам 1.2.3. и 1.2.5. видно, что в первом случае противоположенные ребра у куба параллельны, а во втором, все ребра куба имеют точку схода где-то на горизонте.

Мы уже выяснили, что найти параллельную проекцию трехмерного объекта, не составляет большого труда, а вот с центральной проекцией будет немного посложнее. Ниже представлена формула нахождения центральной проекции точки (X, Y, Z).

k := D / (Z + OfsZ); x2d := oX + ROUND(X * k); y2d := oY + ROUND(Y * k);

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

// Вычисляем центр экрана oX := ClientWidth div 2; oY := ClientHeight div 2;

ClientWidth, ClientHeight – это стандартные свойства формы, задающие ширину и высоту клиентской части окна, т.е. без учета системного меню, строки заголовка и т.д. Собственно в этой области мы и будем, выводит графику.

Следующее, это параметр OfsZ – задающий расстояние от центра локальной координатной оси проецируемой точки, до центра плоскости экрана. Что бы понять это взгляните на Рис 1.2.6.

Рис 1.2.6. Перспективная проекция

На рисунке, параметр Ofs показывает длину отрезка зеленого цвета, соединяющий центр плоскости экрана и центр локальной координатной оси.

Следующий параметр D – влияющий на коэффициент угла обзора проекции, который вычисляется по формуле: k := D / (Z + Ofs);

Нам важно научится правильно подбирать параметры D и Ofs для того что бы наша проекция отображалась корректно. На Рис 1.2.7. – показана проекция человеческой головы с неправильно подобранными параметрами D и Ofs. На Рис 1.2.8. параметры подобраны, верно.

Рис 1.2.7. Неправильная проекция

Рис 1.2.8. Правильная проекция

Т.е. по этим рисункам видно, к каким искажениям приводит неправильный подбор параметров. Дело в том, что наша проекция работает по принципу объектива видеокамеры. И в соответствии с законами оптики, для получения резкого изображения, проектируемый объект должен располагаться на определенном расстоянии от центра проекции (объектива видеокамеры). В наших формулах это расстояние задает параметр Ofs. С параметром D – немного посложнее. Как уже и было сказано, этот параметр задает коэффициент угла обзора проекции. Т.е. с помощью этого параметра можно производить масштабирование объектов.

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

D := (ClientWidth / ClientHeight) div 2; Ofs := (ClientWidth / ClientHeight) div 2;

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

Конечно, что бы получить максимально точную проекцию объекта, нужно провести более сложные расчеты. Но об этом мы поговорим чуть попозже.

1.3. Создание буфера рисования

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

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

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

Создать данный буфер в Delphi – проще пареной репы! Для этого достаточно использовать стандартный графический класс Delphi – TBitMap.

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

DrawBuffer := TBitMap.Create; DrawBuffer.Width := ClientWidth; DrawBuffer.Height := ClientHeight;

В первой строке собственно и происходит создание буфера рисования. А именно, создается экземпляр класса TBitMap, и под него выделяется память в компьютере. В следующих строчках указываем размеры нашего буфера, т.е. ширину и длину. Здесь мы указали свойства ClientWidth и ClientHeight т.е. наш буфер будет занимать всю область окна.

Удаление:

if DrawBuffer <> nil then begin DrawBuffer.Free; DrawBuffer := nil; end;

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

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

Очистка происходит следующим образом:

procedure TMainForm.ClearBuffer; begin DrawBuffer.Canvas.Pen.Color := BufferColor; DrawBuffer.Canvas.Brush.Color := BufferColor; DrawBuffer.Canvas.Rectangle(0, 0, ClientWidth, ClientHeight); end;

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

DrawBuffer.Canvas.Pen.Color – цвет рамки нашего прямоугольника

DrawBuffer.Canvas.Brush.Color – цвет заливки прямоугольника

В нашем случае, цвет рамки и цвет заливки у нас одинаковы.

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

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

procedure TMainForm.FormResize(Sender: TObject); begin if DrawBuffer <> nil then begin oX := ClientWidth div 2; oY := ClientHeight div 2; DrawBuffer.Width := ClientWidth; DrawBuffer.Height := ClientHeight; end; end;

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

Вот в принципе и все! Но остался еще один нюанс. Проведите небольшой эксперимент. Киньте на форму компонент Timer, свойству Enabled присвоим значение True, а значение Interval сделаем равным единице.

Кликнете два раза на таймере, и добавьте следующий код:

procedure TMainForm.Timer1Timer(Sender: TObject); begin RePaint; end;

Запустите приложение и посмотрите что будет. А будет очень некрасиво, окно будет страшно мерцать. Это происходит потому, что при перерисовки окна, ему сначала посылается сообщение ”WM_ERASEBKGND”, которая стирает фон, а только потом посылается сообщение "WM_PAINT". Поэтому, что бы убрать это неприятное мерцание, нам просто нужно перекрыть функцию, которая вызывается при получении окном сообщения ”WM_ERASEBKGND”. Сделать это, тоже очень легко.

Достаточно добавить в раздел private главной формы следующую функцию:

procedure WMErasebkgnd(var Msg: TWMErasebkgnd); message WM_ERASEBKGND;

А само описание функции оставить пустым:

procedure TMainForm.WMErasebkgnd(var Msg: TWMErasebkgnd); begin end;

1.4. Программа генерации точек в пространстве

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

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

Рис 1.4.1. Окно программы

Процедура генерации точек выглядит следующим образом:

Randomize; for I := 1 to PointsCount do begin Points3D[I].X := Random(ClientWidth) - oX; Points3D[I].Y := Random(ClientHeight) - oY; Points3D[I].Z := Random(ClientWidth) - oX; end;

Из этой процедуры видно, что точки генерируются так, что бы их координаты не выходили из поля обзора нашей проекции. Points3D – массив структур TPoint3D. PointsCount – количество элементов в массиве (т.е. количество генерируемых точек).

const PointsCount = 1000; var Points3D: array[1..PointsCount] of TPoint3D;

Теперь напишем главную процедуру рисования точек. Мы будем вызывать ее тогда, когда наше окно нужно будет перерисовать. Например, когда выполняется событие формы OnPaint, OnResize или событие таймера OnTimer.

procedure TMainForm.DrawPoints; var tX: Real; tY: Real; tZ: Real; Sum: Real; X: Integer; Y: Integer; I: Integer; begin if DrawBuffer <> nil then begin ClearBuffer; for I := 1 to PointsCount do begin case Direct of TRUE: begin tY := Points3D[I].Y * CosA - Points3D[I].Z * SinA; tZ := Points3D[I].Y * SinA + Points3D[I].Z * CosA; Points3D[I].Y := tY; Points3D[I].Z := tZ; end; FALSE: begin tX := Points3D[I].X * CosA - Points3D[I].Z * SinA; tZ := Points3D[I].X * SinA + Points3D[I].Z * CosA; Points3D[I].X := tX; Points3D[I].Z := tZ; end; end; SUM := D / (POINTS3D[I].Z + Ofs); X := oX + ROUND(POINTS3D[I].X * SUM); Y := oY + ROUND(POINTS3D[I].Y * SUM); DrawBuffer.Canvas.Pen.Color := clWhite; DrawBuffer.Canvas.Brush.Color := clWhite; DrawBuffer.Canvas.Ellipse(X - rPoint, Y - rPoint, X + rPoint, Y + rPoint); end; Canvas.Draw(0, 0, DrawBuffer); end; end;

Блок-схема этой процедуры будет выглядеть следующим образом:

Рис 1.4.2. Блок-схема процедуры рисования точек

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

Alpha := 0.01; CosA := Cos(Alpha); SinA := Sin(Alpha); case Direct of TRUE: begin tY := Points3D[I].Y * CosA - Points3D[I].Z * SinA; tZ := Points3D[I].Y * SinA + Points3D[I].Z * CosA; Points3D[I].Y := tY; Points3D[I].Z := tZ; end; FALSE: begin tX := Points3D[I].X * CosA - Points3D[I].Z * SinA; tZ := Points3D[I].X * SinA + Points3D[I].Z * CosA; Points3D[I].X := tX; Points3D[I].Z := tZ; end; end;

Переменная Direct задает направление поворота. Если Direct = True, то точки вертятся сверху вниз, если Direct = False, то слева направо. Подробно эти формулы мы сейчас разбирать не будем, а познакомимся с ними в следующих наших уроках. Но уже сейчас видно, что ничего сложного в них тоже нет…


Комментарии (25):

| Jorgefek
Thank you for helping people find the info they need. Good stuff as usual. Keep up the great work!!!
howtowriteacriticalanalysisessay138.blogspot.com/
howtowriteashortessay622.blogspot.com/
writeacompareandcontrastessay.blogspot.com/
howtowriteanevaluationessay10.blogspot.com/
howtowriteathesisstatementforanessa64.blogspot.com/
| LarryUtere
Нет смысла и упоминать студентов кафедры «ТехБез» МИИТа! Зачеты и экзамены сдаются только через личную кассу кандидата наук кафедры Сорокиной Екатерины Александровны.
К.н. Сорокина Екатерина Александровна ничего не боится, потому что действует под прикрытием заведующего кафедрой - Аксенова В.А.
| Neoodag
Здесь вы можете заказать копию любого сайта под ключ, недорого и качественно, при этом не тратя свое время на различные программы и фриланс-сервисы.

Клонированию подлежат сайты как на конструкторах, так и на движках:
- Tilda (Тильда)
- Wix (Викс)
- Joomla (Джумла)
- Wordpress (Вордпресс)
- Bitrix (Битрикс)
и т.д.
телефон 8-996-725-20-75 звоните пишите viber watsapp
Копируются не только одностраничные сайты на подобии Landing Page, но и многостраничные. Создается полная копия сайта и настраиваются формы для отправки заявок и сообщений. Кроме того, подключается админка (админ панель), позволяющая редактировать код сайта, изменять текст, загружать изображения и документы.

Здесь вы получите весь комплекс услуг по копированию, разработке и продвижению сайта в Яндексе и Google.

Хотите узнать сколько стоит сделать копию сайта?
напишите нам
8-996-725-20-75 звоните пишите viber watsapp
| Neoodag
Здесь вы можете заказать копию любого сайта под ключ, недорого и качественно, при этом не тратя свое время на различные программы и фриланс-сервисы.

Клонированию подлежат сайты как на конструкторах, так и на движках:
- Tilda (Тильда)
- Wix (Викс)
- Joomla (Джумла)
- Wordpress (Вордпресс)
- Bitrix (Битрикс)
и т.д.
телефон 8-996-725-20-75 звоните пишите viber watsapp
Копируются не только одностраничные сайты на подобии Landing Page, но и многостраничные. Создается полная копия сайта и настраиваются формы для отправки заявок и сообщений. Кроме того, подключается админка (админ панель), позволяющая редактировать код сайта, изменять текст, загружать изображения и документы.

Здесь вы получите весь комплекс услуг по копированию, разработке и продвижению сайта в Яндексе и Google.

Хотите узнать сколько стоит сделать копию сайта?
напишите нам
8-996-725-20-75 звоните пишите viber watsapp
| LarryUtere
Нелегка жизнь слушателей кафедры «Техносферная безопасность» МИИТ! Зачеты и экзамены сдаются только через личную кассу кандидата наук кафедры Сорокиной Екатерины Александровны.
К.н. кафедры «ТехБез» МИИТа Сорокина Екатерина Александровна чувствует свою безнаказанность, т.к. действует под прикрытием зав.кафа - Аксенова В.А.
If any one desires to be a successful blogger, afterward he/she must look at this article, for the reason that it consists of al} strategies related to that.
| Neoodag
Здесь вы можете заказать копию любого сайта под ключ, недорого и качественно, при этом не тратя свое время на различные программы и фриланс-сервисы.

Клонированию подлежат сайты как на конструкторах, так и на движках:
- Tilda (Тильда)
- Wix (Викс)
- Joomla (Джумла)
- Wordpress (Вордпресс)
- Bitrix (Битрикс)
и т.д.
телефон 8-996-725-20-75 звоните пишите viber watsapp
Копируются не только одностраничные сайты на подобии Landing Page, но и многостраничные. Создается полная копия сайта и настраиваются формы для отправки заявок и сообщений. Кроме того, подключается админка (админ панель), позволяющая редактировать код сайта, изменять текст, загружать изображения и документы.

Здесь вы получите весь комплекс услуг по копированию, разработке и продвижению сайта в Яндексе и Google.

Хотите узнать сколько стоит сделать копию сайта?
напишите нам
8-996-725-20-75 звоните пишите viber watsapp
| MikeFef
&#1051;&#1091;&#1095;&#1096;&#1080;&#1077; &#1055;&#1088;&#1086;&#1089;&#1090;&#1080;&#1090;&#1091;&#1090;&#1082;&#1080; &#1057;&#1055;&#1073;
| LarryUtere
Нелегка жизнь студентов кафедры «ТехБез» МИИТа! Экзамены и зачеты сдаются только нескромную плату для к.н. кафедры «ТехБез» МИИТа Сорокиной Екатерины Александровны.
Сорокина Екатерина Александровна ведет себя беспечно, т.к. действует под прикрытием заведующего кафедрой - Аксенова Владимира Алексеевича
| Aaronchomo
Many thanks for helping people find the info they need. Good stuff as usual. Keep up the great work!!!
autobiographycollegeessay417.blogspot.com
ibessaywriting724.blogspot.com
custompaperwriting70.blogspot.com
howtowriteanessayonamovie688.blogspot.com
essaywritingbasics431.blogspot.com
| Neoodag
Здесь вы можете заказать копию любого сайта под ключ, недорого и качественно, при этом не тратя свое время на различные программы и фриланс-сервисы.

Клонированию подлежат сайты как на конструкторах, так и на движках:
- Tilda (Тильда)
- Wix (Викс)
- Joomla (Джумла)
- Wordpress (Вордпресс)
- Bitrix (Битрикс)
и т.д.
телефон 8-996-725-20-75 звоните пишите viber watsapp
Копируются не только одностраничные сайты на подобии Landing Page, но и многостраничные. Создается полная копия сайта и настраиваются формы для отправки заявок и сообщений. Кроме того, подключается админка (админ панель), позволяющая редактировать код сайта, изменять текст, загружать изображения и документы.

Здесь вы получите весь комплекс услуг по копированию, разработке и продвижению сайта в Яндексе и Google.

Хотите узнать сколько стоит сделать копию сайта?
напишите нам
8-996-725-20-75 звоните пишите viber watsapp
| DanielAscek
Wow! This might be by far the most useful thing on the subject I have ever come across. Many thanks for your work.
thehelpmovieanalysisessay871.blogspot.com
howtowriteanenglishessay794.blogspot.com
fsucollegeessay353.blogspot.com
writemypapers135.blogspot.com
writingessaysforkids776.blogspot.com
| LarryUtere
Нелегка жизнь студентов кафедры «ТехБез» МИИТа! Зачеты и экзамены сдаются только взятку для к.н. кафедры «ТехБез» МИИТа Сорокиной Екатерины Александровны.
Кандидат наук кафедры Сорокина Екатерина Александровна чувствует свою безнаказанность, т.к. действует под прикрытием зав.кафа - Аксенова Владимира Алексеевича
| DanielAscek
Many thanks for the blog, it is packed with a lot of handy info. Reading this helped me a lot.
howtowriteapaperabstract755.blogspot.com
parentswritingcollegeessays225.blogspot.com
reflectiveessaywriting435.blogspot.com
creativecollegeessay750.blogspot.com
tipstowriteessay174.blogspot.com
| as2714
Отличный материал! Все по полочкам!
Спасибо большое!
С наступающим!
| Никита
Отличная статья, спасибо!
Поможет мне в написании универсального визуализатора музыки
| El
спасибо! хорошо изложено, интересно, кое-что даже стало понятно, как новичку в этом деле.)
| Виталя
Спасибо, мне очень понравился подход - от простого к сложному.
| ujif
обещали про коэффициент D рассказать
и де?
| pragma
lol.
Потестил проц Intel Core i7.
Нормально вытягивает 15000 - 17000 точек в один пиксель(с увеличением размера точки fps падает).

В диспетчере максимальная нагрузка на проц(какой нить один) начинается где то с 6000 - 6500 точек.
| pragma
Здравствуйте, есть несколько вопросов.
1. Как вы импортировали меш башки в свой проект?
2. Рисовали ее с помощью GDI?
3. Я вот думаю повысится ли производительность, если заюзать ассемблерные вставки, в проекте на VC++ 2008 при пересчете и отрисовке меша? Понимаю, что под винду лучше юзать d3d, ogl, чисто спортивный интерес.
| n3ytron
Большое спасибо!!! Очень помогло. Понятно и интересно. Продолжайте писать такие статьи-у вас очень хорошо выходит ^__^
| alex_ey
К сожалению, исходники я посеял. Но в новой свой статье, я сделаю тоже что-нибудь подобное.
| Дмитрий
Отличная статья, Спасибо!
А можете выложить исходники программы Projection?
очень интересно)
| Mauni
Спасибо огромное за статью!
А будет ли продолжение в виде второй части?

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

Имя:

email:

Защита от спама:

Введите число, изображенное на картинке:

Текст комментария:

AlexeySpace.Ru
(c) alex_ey (Alexey Sokolov)
2010 - 2018
alex_ey@mail.ru