Использование полного разрешения буфера глубины для 2D-рендеринга

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, могут сделать это проще, я не могу использовать его по соображениям совместимости.

AshleysBrain
источник
Я не могу себе представить, что использование буфера z обеспечит вам значительный прирост производительности (если таковой имеется) после того, как вы добавили все записи, вычисления и сравнения z-буфера против копирования текстур задом наперед, не говоря уже о альфа-прозрачности / смешивании беды.
Мэтт Эш
@MattEsch: Идея состоит в том, что все эти вычисления выполняются в GPU на невероятно высоких скоростях, поэтому имеет смысл сделать это.
Panda Pajama
@MattEsch: FWIW предназначен для интегрированных графических процессоров Intel, которые используют системную память вместо выделенной памяти графического процессора. Это делает их довольно медленными и склонными к превышению пределов скорости заполнения при превышении количества спрайтов. Intel рекомендовала мне этот подход как способ обойти это. Предположительно их реализация глубинного тестирования хорошо оптимизирована и может сэкономить много наполнения. Это еще предстоит увидеть, хотя, я еще не профилировал это!
AshleysBrain
Копирование блоков @PandaPajama на самом деле очень быстро, поэтому, если бы вы просто копировали текстуры на поверхности, это было бы действительно очень быстро. Первыми большими накладными расходами являются, прежде всего, передача данных на графический процессор, что, как указывает Эшли, может быть более дорогим на интегрированных графических процессорах. Вы обнаруживаете, что даже многие 3d-игры выполняют нетривиальную работу с процессором (например, анимацию костей), потому что выгрузка данных, необходимых в первую очередь для этих матричных вычислений, слишком дорога.
Мэтт Эш
@MattEsch: с блинтом можно сделать так много всего. Вспоминаются повороты, масштабирование и деформации, но также, поскольку у вас есть пиксельные / вершинные шейдеры, предел того, что вы можете сделать с аппаратным обеспечением, намного выше, чем то, что вы можете сделать с помощью блиттинга.
Панда Пижама

Ответы:

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)). Это тот же результат.
Панда Пижама
Ах я вижу. Спасибо за ответ, все работает хорошо!
AshleysBrain
0

Может быть, вам следует изменить свой подход к чему-то более простому. Что я буду делать; Сохраняйте глубину Z, но сохраняйте список того, что вы делаете. Упорядочите этот список на основе значения глубины z и отобразите объекты в порядке списка.

Надеюсь, это поможет. Люди всегда говорят мне, чтобы все было просто.

HgMerk
источник
1
Извините, это не сильно поможет. Я уже делаю это. Вопрос в том, какие Z позиции выбрать.
AshleysBrain
0

Так как у вас уже есть отсортированный список объектов для рендеринга (спереди назад), вам действительно нужно увеличить индекс Z? Разве вы не можете использовать «меньше или равно» для «функции проверки»? Таким образом, он на самом деле проверяет, нарисован ли уже определенный пиксель или нет.

Эльфийская
источник
«меньше или равно» все равно приведет к тому, что абсолютно все будет переопределено, так как все всегда будет иметь одинаковый индекс Z и, следовательно, пройдет проверку глубины.
AshleysBrain