Логарифмический буфер глубины OpenGL

Мне удалось реализовать логарифмический буфер глубины в OpenGL, в основном благодаря статьям из Outerra (Вы можете прочитать их Вот, Вот, а также Вот). Однако у меня есть некоторые проблемы, и я не уверен, являются ли эти проблемы присущими использованию логарифмического буфера глубины или есть какой-то обходной путь, о котором я не могу думать.

Для начала, вот как я вычисляю логарифмическую глубину в вершинном шейдере:

gl_Position = MVP * vec4(inPosition, 1.0);
gl_Position.z = log2(max(ZNEAR, 1.0 + gl_Position.w)) * FCOEF - 1.0;
flogz = 1.0 + gl_Position.w;

И вот как я фиксирую значения глубины в фрагментном шейдере:

gl_FragDepth = log2(flogz) * HALF_FCOEF;

куда ZNEAR = 0.0001, ZFAR = 1000000.0, FCOEF = 2.0 / log2(ZFAR + 1.0), а также HALF_FCOEF = 0.5 * FCOEF, Cв моем случае это 1.0, чтобы упростить мой код и сократить вычисления.

Для начала, я очень доволен уровнем точности, которую я получаю. При нормальной буферизации глубины (znear = 0.1, zfar = 1000.0) я получаю немного z-боев по направлению к краю расстояния просмотра. Прямо сейчас, с моим НАМНОГО большим количеством znear: zfar, я положил вторую плоскость земли на 0,01 единицы ниже первой, и я не могу найти z-бой, независимо от того, насколько далеко я уменьшаю камеру (я получаю немного z- борьба, когда он всего в 0,0001 (0,1 мм), но ме).

У меня есть некоторые проблемы / проблемы, как бы то ни было.

1) Я получаю больше отсечения в плоскости, чем с моим обычным буфером глубины, и это выглядит ужасно. Это происходит в тех случаях, когда, по логике, это действительно не должно. Вот несколько скриншотов того, что я имею в виду:

Стричь землю. Отсечение сетки.

Оба эти случая — вещи, которые я не испытывал с моим обычным буфером глубины, и я бы предпочел не видеть (особенно первый). РЕДАКТИРОВАТЬ: Проблема 1 официально решается с помощью glEnable(GL_DEPTH_CLAMP),

2) Чтобы заставить это работать, мне нужно написать gl_FragDepth. Я пытался не делать этого, но результаты были неприемлемы. Запись в gl_FragDepth означает, что моя видеокарта не может выполнять ранние z-оптимизации. Это неизбежно приведет меня к стене, и поэтому я хочу исправить это, как только смогу.

3) Мне нужно иметь возможность извлечь значение, хранящееся в буфере глубины (для этого у меня уже есть кадровый буфер и текстура), а затем преобразовать его в линейную координату пространства вида. Я действительно не знаю, с чего начать, как я делал это раньше, задействовал матрицу обратной проекции, но я не могу сделать это здесь. Любой совет?

6

Решение

Отсечение в ближней плоскости происходит независимо от проверки глубины, но путем Cli Space Volume. В современном OpenGL можно использовать зажим по глубине чтобы все снова выглядело красиво. Увидеть http://opengl.datenwolf.net/gltut/html/Positioning/Tut05%20Depth%20Clamping.html#d0e5707

2

Другие решения

1) В уравнении вы использовали:
gl_Position.z = log2 (max (ZNEAR, 1.0 + gl_Position.w)) * FCOEF — 1.0;
Не должно быть ZNEAR, потому что это не имеет к этому отношения. Константа существует только для того, чтобы аргумент log2 был нулевым, например, вы можете использовать 1e-6 там.

Но в противном случае глубина зажима решит проблему.

2) Вы можете избежать использования gl_FragDepth только с адаптивным тесселяцией, который удерживает ошибку интерполяции в границах. Например, в Outerra местность адаптивно тесселяется, и, таким образом, никогда не бывает видимой ошибки на местности. Но запись глубины фрагмента необходима для объектов при увеличении масштаба, так как длинные треугольники пространства экрана будут иметь несоответствие между линейно интерполированным значением и правильным логарифмическим значением довольно высоким.

Обратите внимание, что последние драйверы AMD теперь поддерживают NV_depth_buffer_float расширение, так что теперь можно использовать Обратный буфер глубины с плавающей точкой настроить вместо. Насколько я знаю, он еще не поддерживается на графических процессорах Intel.

3) Преобразование в глубину пространства просмотра описано здесь: https://stackoverflow.com/a/18187212/2435594

1

Возможно, немного поздно для ответа.
В любом случае для восстановления Z используйте версию log2:

realDepth = pow(2,(LogDepthValue + 1.0)/Fcoef) - 1.0;
1
По вопросам рекламы [email protected]