Використання повної роздільної здатності буфера глибини для двовимірної візуалізації


9

Я працюю над рендером назад для двигуна 2D за допомогою ортографічної проекції. Я хочу використовувати буфер глибини, щоб уникнути перевитрати. У мене буфер 16-бітної глибини, камера на Z = 100, яка дивиться на Z = 0, zNear - 1, а zFar - 1000. Кожен виправлений спрайт встановлює свої Z-координати на все більш віддалені значення, що дозволяє тесту глибини пропускати візуалізацію все, що знаходиться під ним.

Однак я знаю, як Z позиції в кінці значень буфера Z нелінійні. Я хочу використовувати повну роздільну здатність 16-бітового буфера глибини, тобто дозволяючи 65536 унікальних значень. Отже, для кожного наданого спрайту я хочу збільшити позицію Z до наступної позиції, щоб співвіднестись до наступного унікального значення буфера глибини.

Іншими словами, я хочу перетворити інкрементний індекс (0, 1, 2, 3 ...) спрайта, що втягується, у відповідне положення Z для кожного спрайту, щоб мати унікальне значення глибини буфера. Я не впевнений у математиці, що стоїть за цим. Який розрахунок для цього робити?

Зауважте, що я працюю в WebGL (в основному OpenGL ES 2), і мені потрібно підтримувати широкий спектр апаратних засобів, тому, хоча розширення типу gl_FragDepth можуть полегшити це, я не можу використовувати його з міркувань сумісності.


Я не можу уявити, що використання буфера z запропонує вам великий приріст продуктивності (якщо такий є) після того, як ви додали всі записи із буфера z, обчислення та порівняння порівняно з копіюванням текстур на передню частину, не кажучи вже про прозорість / змішування альфа біди.
Метт Еш

@MattEsch: Ідея полягає в тому, що всі ці обчислення робляться в GPU з надзвичайно високими швидкостями, тому це має сенс робити.
Піжама Panda

@MattEsch: FWIW - це спрямовано на інтегровані графічні процесори Intel, які використовують системну пам'ять замість виділеної пам’яті GPU. Це робить їх досить повільними і здатними до досягнення меж рівня заповнення, якщо перевищувати багато спрайтів. Intel рекомендував мені цей підхід як спосіб обійти його. Імовірно, їх глибоке тестування добре оптимізоване і може економити велику кількість заповнення. Це все ще залишається побачити, але я ще цього не профілював!
AshleysBrain

@PandaPajama блокування копіювання пам’яті насправді дуже швидко, тому якби ви просто відривали текстури на поверхні, це було б дуже швидко. Перший головний накладні витрати - це отримання даних про GPU, в першу чергу, що, як зазначає Ешлі, може бути дорожчим на інтегрованих GPU. Ви виявляєте, що навіть багато 3D-ігор роблять нетривіальну кількість роботи на процесорі (як кісткова анімація), оскільки завантаження даних, необхідних для цих матричних обчислень, в першу чергу занадто дороге.
Метт Еш

@MattEsch: Існує лише стільки, що ти можеш зробити з просто миготінням. Приходять до уваги обертання, масштабування та деформації, але, оскільки у вас є піксельні / вершинні шейдери, межа того, що ви можете зробити з апаратним забезпеченням, набагато вище, ніж те, що ви можете зробити з просто миготінням.
Піжама Panda

Відповіді:


5

Дійсно, значення, збережені в буфері z, не є лінійними фактичним координатам z ваших об'єктів, а їх взаємними, щоб дати більшу роздільну здатність тому, що знаходиться поблизу ока, ніж тому, що ближче до задньої площини.

Що ви робите, що ви карту вашим , zNearщоб 0і ваші zFarдо 1. Бо zNear=1і zFar=2це повинно виглядати так

Zbuffer

Спосіб розрахунку цього визначається:

z_buffer_value = k * (a + (b / z))

Де

 k = (1 << N), maximum value the Z buffer can store
 N = number of bits of Z precision
 a = zFar / ( zFar - zNear )
 b = zFar * zNear / ( zNear - zFar )
 z = distance from the eye to the object

... а z_buffer_value - ціле число.

Вище рівняння пропонується вам за допомогою цієї дивовижної сторінки , яка справді добре пояснює z-буфери.

Отже, щоб знайти необхідне zдля даної задачі z_buffer_value, ми просто очистимо z:

z = (k * b) / (z_buffer_value - (k * a))

Дякую за відповідь! Я трохи розгублений, як ви отримали остаточну формулу. Якщо я беру z_buffer_value = k * (a + (b / z))і просто переставляю рішення для вирішення z, тоді я отримую: z = b / ((z_buffer_value / k) - a)- як ти дійшов до іншої останньої формули?
AshleysBrain

@AshleysBrain: ви берете знаменник (v / k) - a => (v - k * a) / kі згортаєте до (k * b) / (v - (k * a)). Це той самий результат.
Піжама Panda

А, бачу. Дякую за відповідь, це працює чудово!
AshleysBrain

0

Можливо, ви повинні змінити свій підхід до чогось більш простого. Що б я зробив; Зберігайте свою глибину Z, але зберігайте список того, що ви робите. Упорядкуйте цей список на основі значення z Depth та відредагуйте об'єкти у порядку списку.

Сподіваюсь, це може допомогти. Люди завжди кажуть мені, щоб все було просто.


1
Вибачте, це не дуже допоможе. Я це вже роблю. Питання в тому, які Z позиції вибрати.
AshleysBrain

0

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


"менше або рівне" все одно призведе до перевищення абсолютно всього, оскільки все завжди матиме рівний показник Z, і тому проходити тест на глибину.
AshleysBrain
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.