Должна ли эта визуализация буфера глубины выглядеть гладкой?

Я отлаживаю проблему с SSAO и пытаюсь визуализировать мой буфер глубины. Вот результат:Я храню глубину и нормали в одной 16-битной RGBA-текстуре. Это мой глубинный проход шейдера:

// Vertex shader
#version 150 core
#extension GL_ARB_explicit_attrib_location : enable

uniform mat4 _ViewMatrix;
uniform mat4 _ViewProjectionMatrix;
uniform mat4 modelMatrix;

layout (location = 0) in vec4 aPosition;
layout (location = 2) in vec3 aNormal;

out vec4 vPosition;
out vec3 vNormal;

void main()
{
    gl_Position = _ViewProjectionMatrix * modelMatrix * aPosition;

    mat4 modelViewMatrix = _ViewMatrix * modelMatrix;

    vPosition = modelViewMatrix * aPosition;
    vNormal = mat3( modelViewMatrix ) * aNormal;
}

// Fragment shader.
#version 150 core

// Calculated as 1.0 / (far - near)
uniform float uLinearDepthConstant;

in vec4 vPosition;
in vec3 vNormal;

out vec4 outDepthNormal;

void main()
{
    float linearDepth = -vPosition.z * uLinearDepthConstant;

    outDepthNormal = vec4( linearDepth, normalize( vNormal ) );
}

Затем я визуализирую глубину в шейдере, который отображает текстуру (я жестко закодировал расстояния ближней и дальней плоскости):

void main()
{
    float depth = texture( depthNormalMap, vTexCoord ).r;
    fragColor = vec4((2.0 * 1.0) / (200.0 + 1.0 - depth * (200.0 - 1.0)));
}

Должен ли результат казаться гладким или в чем может быть проблема? Я создаю текстуру так:

glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA16F, width, height, 0, GL_RGBA, GL_HALF_FLOAT, 0 );

1 ответ

Решение

Если учесть тот факт, что ни одно оборудование не предлагает 16-битный буфер глубины с плавающей точкой, это выглядит правильно.

Некоторые консоли (например, Xbox 360) предоставляют 24-битный буфер глубины с плавающей точкой, но, как правило, для того, чтобы сделать что-то переносимым, вы должны использовать 32-битный буфер глубины, чтобы он был представлен в плавающей точке. Это требует уродливого 64-битного упакованного формата Depth + Stencil, если вам нужен буфер трафарета и буфер глубины с плавающей запятой, что является одной из причин аппаратного обеспечения ATI в D3D и на Xbox 360 с 24-битной плавающей запятой + 8-битный формат глубины + трафарет, который недоступен в OpenGL. Если бы у GL было это, это назвали бы GL_DEPTH24F_STENCIL8 ,

Теперь, в то время как 16-битное значение с плавающей запятой недостаточно для хранения вашей глубины, вероятно, оно тратит впустую пространство / пропускную способность памяти для хранения ваших нормалей в этом формате. Вам следует попробовать формат, например, RGBA 10:10:10:2 (с фиксированной запятой) или RGB 11:11:10 (с плавающей запятой), чтобы сохранить ваши нормали (если RGBA8 на самом деле неадекватен), а затем с сохраненным пространством Вы могли бы позволить себе 32-битный буфер глубины с плавающей точкой.

В настоящий момент вы фактически не используете буфер глубины с плавающей точкой. Вы пытаетесь упаковать свою глубину в один канал 16-битного цветового буфера для каждого компонента. Я бы посоветовал вам использовать фактическое вложение глубины и использовать 24-битный формат изображения с фиксированной или 32-битной глубиной, если ваше текущее решение не обрезает его. Вы уже должны что-то выводить в выделенный буфер глубины во время обычного рендеринга.

Сразу же, используя формат с плавающей запятой для хранения глубины, вы теряете 1 бит точности, потому что он должен хранить довольно бессмысленный знаковый бит (буферы глубины с фиксированной запятой этого не делают). Кроме того, поскольку значения глубины в общем случае уже находятся в диапазоне 0-1, расширенный диапазон числа с плавающей запятой действительно не применяется. В 16-битном режиме вы теряете больше, чем вы получаете, сохраняя глубину в формате с плавающей запятой. Глубина с фиксированной точкой - действительно лучший способ, когда вы используете меньше битов для хранения глубины.

Другие вопросы по тегам