3D зсередини

Дмитро Ситник, Мій Комп'ютер

Зараз важко знайти людину яка хоч раз в житті не грав би в тривимірні ігри. Більше того, я впевнений, що для багатьох це улюблене заняття. Але чи замислювався хтось, що стоїть за красивою картинкою на екрані? Як виходить тривимірне зображення в грі? У цій статті я хотів би відкрити завісу таємниці і розповісти про те, як влаштовані сучасні 3D-ігри. І зробити це я б хотів на прикладі популярної гри Quake 3 Arena.

Як відомо, вся тривимірна графіка в іграшці складається з полігонів. Полігон в іграшках – це опуклий багатокутник. Я сподіваюся, ви добре собі уявляєте, як виглядає багатокутник на площині екрану? Координата Х, координата Y, центр координат – верхній лівий кут … У тривимірному зображенні все той же, тільки центр координат знаходиться в центрі екрану і додається ще одна – Z-Координата, яка йде вглиб екрану (має позитивний знак). Ось з таких-то полігонів і полягає вся графіка в іграшці.

Будь-який опуклий полігон, у свою чергу, можна розбити на трикутники. Наприклад, ромб можна розбити на 2 або 4 трикутника. Все це відбувається в процесі побудови зображення. Навіщо це потрібно? Відповідь тривіальний – комп'ютера значно простіше зобразити на екрані трикутник, ніж складна опуклий полігон, що складається з n-ного кількості граней. Так що трикутники – це цеглинки тривимірної графіки (точніше, полігонної графіки – адже є й інші різновиди).

Тепер зрозуміло, з чого складаються рівні. Все це – десятки тисяч полігонів, які потім розбиваються на ще менші елементи – трикутники. Чим більше полігонів, тим більше гладким і деталізованим стає зображення, але тим більше гра "гальмує", відповідно, більше вимагає пам'яті – все має свою ціну. Навіть криві, і ті складаються з полігонів. Може бути, крім стилізації зображень, є і якісь інші методи економії полігонів. Стилізація стилізацією, але ж хочеться реалістичності, проте …

Невидимки

Тут постає питання про HSR – Hidden Surface Removal (видалення невидимих поверхонь). В Quake це робиться за допомогою PVS – Potential Visibility Set (список потенційної видимості). Спробуємо пояснити фігурально. Наприклад, якщо ви стоїте будинку в кухні, то ви можете бачити, покладемо, тільки коридор і ванну. Спальню, велику кімнату і балкон ви ніяк бачити не можете. І навпаки, стоячи на балконі, ви ніяк не можете бачити ні кухню, ні ванну. Так навіщо витрачати час на промальовування і розрахунок цих кімнат, якщо вони не потрапляють в межі своєї видимості? Список потенційно видимих кімнат – це і є PVS, список потенційної видимості.

Гра теж складається з так званих кімнат – кластерів. Кластер – це, грубо кажучи, шматок рівня. Він складається з полігонів. Горезвісний PVS і є список видимих кластерів, складений для кожного кластера окремо. Складання цього списку – справа різних утиліт, що використовуються на етапі проектування рівня. Зображення будується так: спочатку визначається кластер, в якому знаходиться гравець. Далі ми беремо полігони з потенційно видимих кластерів і обробляємо їх. Таким чином, ми працюємо тільки з потрібними нам полігонами.

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

Дуже просто. Спочатку ми повинні додати (або відняти – все одно, просто поміняється напрямок руху) до кожної координаті координати гравця. Таким чином, гравець завжди буде знаходитися в центрі координат. Потім здійснюється поворот – за формулами, відомою будь-якому першокурснику. У результаті, ми отримаємо полігони, трансформовані щодо гравця. Дуже добре! Вже півсправи зроблено. Залишається тільки визначити, які полігони потрапляють у наше поле зору.

Наприклад, ставши в кухні обличчям до стіни, ми не побачимо ні коридору, ні ванни. Ось чому одного списку потенційної видимості мало. Гра відсікає всі полігони, які знаходяться за спиною у гравця. Це здійснюється простою перевіркою – якщо всі координати вершин полігону Z менше нуля, значить, ми не побачимо цей полігон. Але і це ще не все. Виявляється, ми також можемо зменшити кількість зображуваних полігонів. Тут варто зауважити, що всі вершини полігонів рівня задані в одному напрямку – або за годинниковою стрілкою, або проти (див. малюнок).

Так ось, обчисливши нормаль трансформованого полігону, ми можемо дізнатися, куди він, грубо кажучи, "дивиться". Адже нормалі – це напрямки. Якщо нормаль позитивна – значить, полігон дивиться на нас, якщо негативна, то полігон звернений "спиною" до нас. Таким чином, залишаються тільки ті полігони, які можуть бути видимі – вони-то і виводяться на екран. Але і тут виникає проблема. Ми знаємо, які полігони ми бачимо. Але як їх вивести на екран, адже далекі полігони можуть перекрити ближні, і вийде зіпсоване зображення?

Перспектива

Комп'ютеру все одно, які полігони знаходяться ближче, а які – далі. Для цього використовується один з алгоритмів промальовування тривимірних поверхонь. Наприклад, можна відсортувати полігони з їх середнім Z-координатах і вивести в цій послідовності на екран. Але цей спосіб не у всіх випадках може дати коректне зображення. Є ще один спосіб, в даний час має широке застосування на апаратній рівні. Знаючи координати кожної вершини в просторі, їх можна просто інтерполювати (про інтерполяції нижче) і дізнатися координати кожної точки полігону в тривимірному просторі. Нас поки цікавить тільки Z-координата, її ми і інтерполіруем.

Додатково до екранного буфера використовується ще один, таких же розмірів, в якому знаходяться дуже великі числа. Дізнавшись для даної інтерпольованому точки полігону Z-Координату, ми дивимося в цей внеекранний буфер. Якщо розташоване в ній число більше, ніж наша Z-Координата, то ми записуємо її туди, а на екран виводимо відповідний піксель текстури полігону. Якщо якийсь полігон і його конкретна точка в даному місці опиниться ближче, то ця точка і в буфері, і на екрані замінюється. Виглядає досить громіздко, а й OpenGL, І Glide, І Direct3D вміють все це робити на апаратному рівні, завдяки чому виходить цілком прийнятна швидкість. Раніше розробникам ігор залишалося тільки намалювати на екрані трикутники, наклавши на них конкретні текстури. Але зараз, після виходу Quake III, Технологія ускладнилася.

Текстура

Тепер на полігон може накладатися або звичайна текстура (для тих, хто не знає, текстура – це двомірне зображення, яке потім відображається на полігоні), або shader. Shader – це скриптова файл, в якому вказана послідовність "косметичних" перетворень даного полігону: змішання кількох текстур, анімація текстури, прозорість і т. п. Все це задається в текстовому форматі. Як же відбувається процес накладення текстур?

Скажімо так: полігон – площина, розташована в тривимірному просторі. Стало бути, кожній точці полігону, крім абсолютного значення у просторовій системі координат, притаманні відносні координати двовимірної системи – до них-то і прив'язується текстура. Тобто, такий-то точці полігону відповідає певний піксель текстури (10,10). Це здійснюється за простими формулами:

1. SREEN_X=X_RES/2+VDIST*(X/Z);

2. SREEN_Y=Y_RES/2+VDIST*(Y/Z);

де SCREEN_X, SCREEN_Y – Координати точки на екрані; X, Y, Z – Координати тривимірної точки; X_RES, Y_RES – Дозвіл екрана (наприклад, 640×480); VDIST – Спеціальна величина, масштабує зображення, або відстань від камери до початку координат по Z. Отримані двовимірні координати текстури і точки інтерполюються між собою, і на екрані виходить тривимірне зображення. Що таке інтерполяція?

Інтерполяція – це зміна числа від a до b за n кроків. Припустимо, нам треба інтерполювати 1 до 5 у 9 кроків. Ми отримуємо наступний ряд: 1, 1.5, 2, 2.5, 3, 3.5, 4, 4.5, 5. Таким же чином, знаючи координати вершин, ми можемо, інтерпретована їх, одержати проміжні координати для кожної точки. Якщо комусь цікаво, то формула інтерполяції наступна:

3. rez = start+step*(end-start)/num_steps;

де rez – Результат інтерполяції; end, start – Перше і останнє число ряду; num_steps – Кількість кроків; step – Поточний крок, що знаходиться в інтервалі від 0 до num_steps.

При зображенні полігону може застосуються билинейная фільтрація-стандартний за теперішніх часів ефект розмиття пікселів при збільшенні полігонів. Раніше при наближенні до стін пікселі збільшувалися, і текстура виходила квадратної – отримувані в результаті інтерполяції нецілі координати полігону "усереднювались" пікселями текстур. При білінійної фільтрації використовується наступний трюк. При отриманні якихось нецілих двовимірних координат точки ми знаходимо найближчі цілі пікселі текстури і інтерполіруем їх колір, використовуючи як поточного кроку інтерполяції неціле значення, отримане в поточній крапці. Відбувається щось на зразок градієнтної розтяжки – для кожної точки ми отримуємо точне проміжне значення, а не округлене ціле.

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*