Z-БУФЕР: наводимо порядок – РОЗРОБКА ІГОР ДЛЯ ОС ANDROID

&nbsp

Що таке z-буфер Коли OpenGL ES отрісовиваєт трикутник до кадрового буфер, він просто змінює колір пікселів, що складають цей трикутник Z-буфер дуже схожий на кадровий буфер в тому, що він також має сховище для кожного пікселя на екрані Однак замість того, щоб зберігати кольору, він зберігає значення глибини Значення глибини пікселя – це приблизно нормалізоване відстань від відповідної точки в 3D до ближньої площини відсікання області видимості

OpenGL ES запише значення глибини для кожного пікселя трикутника в буфер за замовчуванням (якщо z-буфер був створений разом з кадровим буфером) Нам залишається наказати OpenGL ES використовувати цю інформацію для того, щоб вирішити, чи буде отрісовиваємих піксел ближче до ближньої площини відсікання, ніж той, який вже присутня Для цього слід лише викликати метод gl Enabl е, передавши йому відповідний параметр:

Це все, що необхідно зробити Далі OpenGL ES порівняє значення глибини вхідного пікселя зі значенням глибини пікселя, що вже знаходиться в z-буфері Якщо воно менше, то піксель буде ближче до ближньої площини відсікання, тому його слід малювати перед тим пикселом, який вже перебуває в кадровому і z-буфері

Процес проілюстрований на рис 105 На початку роботи програми значення, поміщені в z-буфер, рівні нескінченності (або дуже великому числу) Коли отрісовивается перший трикутник, ми порівнюємо значення глибини кожного його пікселя зі значеннями глибини кожного відповідного пікселя в z-буфері Якщо значення глибини пікселя менше, ніж значення, що знаходиться в z-буфері, піксел проходить так званий тест глибини, або z-тест Його колір запишеться до кадрового буфер, а значення його глибини перезапішет відповідне поточне значення, що знаходиться в z-буфері Якщо ж піксел не проходить тест, ні його колір, ні значення глибини не будуть записані в буфери Це показано на рис 105 для місця, гдефтрі-совиваются другий трикутник Деякі пікселі мають менші значення глибини, тому отрісовиваємих саме вони інші пікселі не проходять тест

Рис 105 Зображення в кадровому буфері (ліворуч) вміст z-буфера після отрисовки кожного трикутника (праворуч)

Як і у випадку з кадровим буфером, нам доводиться очищати z-буфер кожен кадр, в іншому випадку значення глибини пікселів останнього кадру все ще перебуватимуть там Щоб зробити це, ми можемо викликати метод glС1еаг наступним чином:

Це очистить кадровий буфер (або буфер кольорів), як і z-буфер (або буфер глибини), обидва за один раз

&nbsp

Виправляємо останній приклад

Вирішимо проблеми останнього прикладу з використанням z-буфера Я просто скопіював весь код в новий клас, який називається ZBuf ferTest, і змінив метод present нового класу ZBuf ferScreen так, як показано в лістингу 104

Лістинг 104 Фрагменти класу ZBufferTestJava: використання z-буфера

Перше, що ми змінили, – аргументи, що передаються методу glClearO Тепер ми очищаємо обидва буфера замість одного кадрового буфера Ми також дозволяємо тестування глибини перед тим, як отрісуем два трикутника Після того як отрисовка закінчується, ми забороняємо тестування Чому Уявіть, що ми хочемо отрісовать двомірні елементи призначеного для користувача інтерфейсу у верхній частині нашої ЗО-сцени, наприклад поточний рахунок або кнопки Оскільки для цього необхідно використовувати клас Spri teBatcher, який працює тільки у двох вимірах, нам не потрібно мати ніяких осмислених координат по осі z для вершин 2В-елементів Нам також не потрібно проводити тестування глибини, оскільки ми будемо явно задавати порядок отрисовки вершин на екрані Результат роботи цього прикладу показано на рис 106 Тепер він виглядає так, як ми й очікували

Рис 106 Z-буфер в дії, тепер немає необхідності задавати порядок отрисовки

Нарешті зелений трикутник посередині коректно отрісовивается позаду червоного трикутника Це відбувається завдяки нашому новому кращого друга – 2буферу-Але, як і у випадку з багатьма іншими друзями, настають часи, коли дружба кілька страждає від деяких недоліків Дізнаємося, які підводні камені вас можуть очікувати, якщо ви будете використовувати z-буфер

Змішуємо: за вами нічого немає

Припустимо, що ми хочемо дозволити змішування для червоного трикутника, що має координату z = -3 Встановимо, скажімо, альфа-компонент кольору кожної вершини рівним 0,5 f, що змусить цей трикутник просвічуватися У нашому випадку має бути видно зелений трикутник, що має координату z, рівну -5 Подумаємо, що ж буде робити OpenGL ES, а також про те, що ще може статися

OpenGL ES Отріс перший трикутник в z-буфер і буфер кольору

Далі OpenGL ES Отріс зелений трикутник, оскільки він слідує після червоного трикутника в екземплярі класу Vertices3

Частина зеленого трикутника, що знаходиться позаду червоного, не буде висвітлена на екрані, оскільки її пікселі не пройдуть тест глибини

Ніщо не буде просвічуватися крізь червоний трикутник, оскільки через нього ніщо не просвічувалось в той момент, коли він промальовується

Коли ми використовуємо змішування в комбінації з z-буфером, нам слід переконатися в тому, що всі прозорі обєкти впорядковані за зростанням відстані від камери, і малювати їх від останнього до першого Всі непрозорі обєкти повинні бути отрісовани перед Прозорими Їх не обовязково сортувати

Напишемо простий приклад, що демонструє це Ми збережемо нашу поточну сцену, що складається з двох трикутників, і встановимо альфа-компонент квітів вершин першого трикутника (z = -3) рівним 0,5 £ Відповідно з правилом спочатку нам необхідно отрісовать непрозорі обєкти, в нашому випадку зелений трикутник (z = -5), а потім – все прозорі, від далекого до ближнього У нашій сцені присутній тільки один прозорий обєкт: червоний трикутник

Ми скопіюємо весь код попереднього прикладу в новий клас, який називається ZB1 endi ngTest, і перейменуємо ZBuf f erScreen, що знаходиться в ньому, в ZB1 endi ngScreen Нам потрібно змінити кольори вершин першого трикутника, а також дозволити змішування і отрисовку двох трикутників в заданому порядку в методі present У лістингу 105 показаний змінений код

Лістинг 105 Фрагменти класу ZB1endingTestjava: змішування при доступному z-буфері

У конструкторі класу ZB1 endi ngScreen змінимо лише альфа-компоненти квітів вершин першого трикутника, тепер вони будуть рівні 0,5 Це зробить перший трикутник прозорим У методі present виконуються звичні операції начебто очищення буферів і установки значень матриць Ми також дозволяємо змішування і встановлюємо відповідну для цього функцію Більш цікаво те, як саме ми будемо малювати два трикутника Спочатку отрісуем зелений трикутник, який є другим у примірнику класу Verti ces3 Він є непрозорим Всі непрозорі обєкти повинні бути отрісовани перед прозорими Далі отрісовиваємих прозорий трикутник, який є першим в екземплярі класу Vertices3 Для обох викликів методу отрисовки verti ces Draw просто використовуємо підходяще зміщення і лічильники вершин, передаючи їх як другий і третій параметри На рис 107 показаний результат роботи цієї програми

Рис 107 Змішування при включеному z-буфері

Змінимо порядок, в якому будуть отрісовиваться два трикутника, наступним чином:

Малюємо перший трикутник, починаючи з вершини 0, а потім другий, починаючи з вершини 3 В результаті спочатку буде відмалювали червоний трикутник спереду, а потім зелений трикутник ззаду На рис 108 показаний результат роботи такої програми

Рис 108 Змішування виконано невірно дальній трикутник має бути видно крізь ближній

Всі наші обєкти є трикутниками, що робить приклади дещо примітивними Ми повернемося до розгляду звязки змішування і z-буфера, коли будемо малювати більш складні фігури Тепер підсумуємо все розглянуте у вигляді послідовності дій

1 Отрісовка непрозорих обєктів

2 Сортування всіх прозорих обєктів від самого далекого від камери до самого близького

3 Отрісовка всіх прозорих обєктів в відсортованому порядку від самого далекого до самого близького

Сортування може бути заснована на відстані від центру обєкта до камери (так відбувається в більшості випадків) Ви зіткнетеся з проблемами, якщо один з ваших обєктів великий і може перекривати кілька інших обєктів Без досить складних трюків ми не зможемо розібратися з цією проблемою Існує кілька куленепробивних рішень, які відмінно спрацюють на звичайних персональних компютерах, але не можуть бути реалізовані на пристроях з ОС Android через те, що їх функціональність GPU обмежена На щастя, така проблема досить рідкісна, і в більшості випадків можна обійтися простою сортуванням

Джерело: Mario Zechner / Маріо Цехнер, «Програмування ігор під Android», пров Єгор Сидорович, Євген зазноби, Видавництво «Пітер»

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


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

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

Ваш отзыв

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

*

*