Програмування тривимірної графіки

Програмування тривимірної графіки. Частина 3.

Програмування тривимірної графіки

Вершини (точки в просторі) - це основа (каркас) всіх тривимірних об'єктів. З вершин збираються полігони, а з полігонів - складні тривимірні об'єкти.

Що ж таке полігон? Погляньте на малюнок (3.1.1.).

Програмування тривимірної графіки

Рис 3.1.1. Види полігонів.

Тобто по малюнку видно, що полігон - це геометрична фігура, що складається з відрізків, послідовно з'єднаних своїми кінцями в замкнуту фігуру. Трикутник, квадрат, прямокутник є окремими випадками полігону.

Полігон (polygon), в перекладі з англійської - це багатокутник. Просто у нас термін "багатокутник" - використовуються в основному в геометрії. А термін "полігон" прикріпився саме до понять тривимірної графіки. А по суті - це одне і теж.

Що б визначити наш трикутник створимо таку структуру:

Структура TVertex описує точку в просторі, а масив TTriangle - описує наш полігон. Для побудови трикутника, досить трьох точок. Тому наш масив складається з трьох елементів, які визначають координати вершин трикутника.

Тепер давайте визначимо наш, трикутник. Для цього створимо змінну типу TTriangle, і поставимо їй наступні координати:

Координати у нас задаються наступним чином: тому що точка (0,0,0) - це центр екрану, то перша вершина у нас лежить на осі oY і має значення Y = 100; друга вершина лежить в лівій нижній частині графіка і має координати: X = -100; Y = - 100; третя точка відповідно лежить навпроти другої і має координати: X = 100; Y = - 100.

Як видно, координату Z ми не враховуємо (присвоюємо їй нуль), тобто наш трикутник буде паралельний координатної площині XY. Див. Малюнок (3.1.2.).

Програмування тривимірної графіки

Рис 3.1.2. Трикутник.

Запустіть програму, і ви побачите, що вийшло не дуже красиво. Справа в тому, що наші полігони малюються в неправильній послідовності. Наприклад, задній полігон раптом виходить на передній план, хоча насправді він повинен малюватися найпершим. Тобто найвіддаленіші від екрану полігони повинні малюватися найпершими, а ближчі до екрану, останніми. При малюванні ближчі полігони повинні накладатися на вже намальовані більш віддалені полігони, тоді тривимірна сцена буде відображатися правильно. Для цього і існує метод сортування полігонів, від більш віддаленого від екрану, до найближчої. Або по іншому його ще називають - видалення невидимих ​​граней.

На щастя, куб - дуже проста фігура. Тому впорядкувати його полігони нам буде дуже просто.

Для початку трохи модифікуємо наші типи даних:

Ми додали новий тип - TVector. Це-те ж саме, що і TVertex. Цей тип ми додали просто для зручності програмування. Так само ми змінили тип TQuad. Тепер це не просто масив, а структура. Сюди увійшли три нових поля. Color - колір полігону. Point2D -двухмерная проекція нашої вершини. Тепер ми будемо після перекладу вершини в 2D, відразу заносити їх в це поле. Normal - нормаль полігону.

На останньому зупинимося детальніше. Що таке нормаль, і навіщо вона потрібна? По-перше, нормаль - це перпендикуляр. Тобто в нашому випадку перпендикуляр до нашого полігону. По-друге - це вектор. І по-третє, довжина цього вектора завжди дорівнює одиниці.

У тривимірній графіці нормалі використовуються в основному для прорахунку освітлення об'єктів. Тобто чим більше кут між нормаллю і вектором світла, тим більше буде висвітлений наш полігон. А приводити цю нормаль до одиничної довжині потрібно для спрощення математичних обчислень під час промальовування графіки.

Припустимо, у нас є два вектори A1 (x1, y1, z1) і B1 (x2, y2, z2). Формула знаходження кута між ними виглядає наступним чином:

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

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

При ініціалізації куба, кожна його сторона буде перпендикулярна одній з осі координат, тому можна задати наступні координати нормалей:

За допомогою цих нормалей ми і будемо сортувати наші полігони. А точніше з координування Z - кожної нормалі. Тобто полігони з найменшим значенням будуть малюватися найпершими, а полігони з великими значеннями цієї координати, малюються останніми.

Це найпростіший спосіб сортування полігонів, а й підходить він тільки для простих об'єктів. Куба, сфери та інших опуклих фігур. Для тривимірних моделей з уже більш-менш складною структурою цей спосіб вже працювати не буде. У таких випадках нам доведеться використовувати складні алгоритми видалення невидимих ​​граней, наприклад - алгоритм художника.

Сортувати наші полігони ми будемо за допомогою методу швидкого сортування. Коли у нас полігонів трохи, в нашому випадку їх шість - цей метод не дає відчутної надбавки в продуктивності. Але ось коли число їх зашкалює за тисячу, виграш у швидкодії буде вже відчутний. Тому будемо використовувати тільки цю сортування.

Тепер розглянемо процедуру малювання нашого куба:

Як видно процедура малювання куба у нас вже значно ускладнилася. Тепер ми виконуємо поворот не тільки вершин куба, але і всі його нормалі. Тобто нормаль полігон у нас повинна обертатися в ту ж саму сторону, що і сам полігон.

Потім переводимо всі наші вершини в двомірний вигляд. Тобто заповнюємо масив Points2D - кожного полігону. Потім сортуємо полігони по координаті Z. І нарешті виводимо їх на екран.

Метод SetColor розкладає наш колір на RGB - складову. І присвоюється приватній змінної класу FRGB. Приватна змінна (поле) - це змінна, яка буде доступна тільки всередині нашого класу (в методах нашого класу).

А ось в методі GetColor і відбувається самої цікаве. У цьому методі ми RGB кольору конвертуємо назад в тип TColor. При цьому попередньо множачи кожну складову кольору на його інтенсивність. А інтенсивність кольору у нас буде визначатися змінної Normal.Z, тобто Z - координатою нормалі нашого полігону.

Чому так? Та дуже просто! Домовимося, що джерело світла у нас буде спрямований на екран монітора. Тобто світлові промені будуть спрямовані як би з очей людини, що сидить перед монітором. Тому вектор світлового променя буде паралельний координатної осі Z. Тобто координати вектора променя світла будуть наступні: (0, 0, 1);

Цей вектор теж одиничний. А як ми вже дізналися, знайти кут між двома одиничними векторами можна за формулою angle = X1X2 + Y1Y2 + Z1Z2.

Підставляємо наші вектора в цю формулу і отримуємо: Normal.X * 0 + Normal.Y * 0 + Normal.Z * 1. Звідси видно змінна Normal.Z і буде коефіцієнтом кута між нормаллю полігону і вектором променя світла. Все просто!

Чим більше значення Normal.Z наближатиметься до одиниці, тим менше буде кут між нормаллю і променем світла і тим відповідно більше буде інтенсивність кольору.

Ми розглянули найпростіший вид освітлення, і напевно це спосіб освітлення єдиний, який можна реалізувати за допомогою графічних класів Delphi. Але я сподіваюся, що цього було достатньо, щоб зрозуміти, за яким принципом в 3D графіки розраховуються джерела світла.

Схожі статті