Должна ли эта визуализация буфера глубины выглядеть гладкой?
Я отлаживаю проблему с 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-битном режиме вы теряете больше, чем вы получаете, сохраняя глубину в формате с плавающей запятой. Глубина с фиксированной точкой - действительно лучший способ, когда вы используете меньше битов для хранения глубины.