Я пытаюсь создать проход карты теней дисперсии.
Итак, сейчас у меня есть FBO, установленное так:
- RBO GL_DEPTH_ATTACHMENT
- Массив текстур (для каждого каскада)
GL_COLOR_ATTACHMENT0
с форматом RG32
для хранения соответствующей информации для vsm (depth
& depth^2
). - Массив текстур (для каждого каскада )
GL_COLOR_ATTACHMENT0
с форматом RG32
для сохранения результата вертикального гауссовского синего - Массив текстуры (для каждого каскада)
GL_COLOR_ATTACHMENT0
с форматом RG32
для хранения результата горизонтального гауссовского синего
Мой проход рендеринга выглядит следующим образом:
- bind vsm shader
- установка размера окна просмотра для размера карты теней
- привязать FBO
- привязать привязку глубины RBO к FBO
- для каждого каскада привязать соответствующий слой массива текстур (первый массив текстур) к FBO
- очистить глубину и цветовые буферы
- рисовать сцену
- связывать шейдер вертикального размытия
- связывать текстур Массив (первый массив текстур) для выборки
- для каждого каскада связывает соответствующий слой массива текстур (второй массив текстур) с FBO и устанавливает
- , очищает буфер цвета
- отрисовка полноэкранного четырехугольника (используются координаты ND C, поэтому нет необходимости отключать тест глубины)
- привязка горизонтального размытия шейдера
- привязка массива текстур (второй массив текстур; массив текстуры, содержащий вертикальное размытие) для выборки - для каждого каскада свяжите соответствующий слой массива текстуры (массив третьей текстуры) с FBO и установите - очистите буфер цвета - выведите полноэкранный квад (используя координаты ND C, поэтому нет необходимости отключить проверку глубины)
- отменить привязку FBO
- установить область просмотра в исходный размер
Создание FBO:
void DirectionalLightShadow::Setup(const ShadowSettings& settings)
{
m_Settings = settings;
if (settings.m_FilterMode != ShadowSettings::FilterMode::VSM)
{
m_FrameBuffer->AddTexutreArrayAttachment(
new Texture2DArray(
Texture2DArray::Texture2DArraySettings
{
SHADOW_MAP_TEXTURE_UNIT, GL_DEPTH_COMPONENT32F, GL_DEPTH_COMPONENT, GL_FLOAT,
m_Settings.m_MapSize, m_Settings.m_MapSize, 1,
Texture::TextureFilterMode::NEAREST, Texture::TextureFilterMode::NEAREST,
Texture::TextureWrapMode::CLAMP_TO_BODER, Texture::TextureWrapMode::CLAMP_TO_BODER, Texture::TextureWrapMode::CLAMP_TO_BODER,
Color(1.0f, 1.0f, 1.0f, 1.0f), m_Settings.m_NumCascades
}
), GL_DEPTH_ATTACHMENT, 0);
m_FrameBuffer->DisableColorBuffer();
}
else
{
m_FrameBuffer->AddRenderBufferAttachment(new RenderBuffer(1, GL_DEPTH_COMPONENT32F, m_Settings.m_MapSize, m_Settings.m_MapSize), GL_DEPTH_ATTACHMENT);
m_FrameBuffer->AddTexutreArrayAttachment(
new Texture2DArray(
Texture2DArray::Texture2DArraySettings
{
SHADOW_MAP_TEXTURE_UNIT, GL_RG32F, GL_RG, GL_FLOAT,
m_Settings.m_MapSize, m_Settings.m_MapSize, 1,
Texture::TextureFilterMode::NEAREST, Texture::TextureFilterMode::NEAREST,
Texture::TextureWrapMode::CLAMP_TO_BODER, Texture::TextureWrapMode::CLAMP_TO_BODER, Texture::TextureWrapMode::CLAMP_TO_BODER,
Color(1.0f, 1.0f, 1.0f, 1.0f), m_Settings.m_NumCascades
}
), GL_COLOR_ATTACHMENT0, 0);
m_FrameBuffer->AddTexutreArrayAttachment(
new Texture2DArray(
Texture2DArray::Texture2DArraySettings
{
SHADOW_MAP_TEXTURE_UNIT, GL_RG32F, GL_RG, GL_FLOAT,
m_Settings.m_MapSize, m_Settings.m_MapSize, 1,
Texture::TextureFilterMode::NEAREST, Texture::TextureFilterMode::NEAREST,
Texture::TextureWrapMode::CLAMP_TO_BODER, Texture::TextureWrapMode::CLAMP_TO_BODER, Texture::TextureWrapMode::CLAMP_TO_BODER,
Color(1.0f, 1.0f, 1.0f, 1.0f), m_Settings.m_NumCascades
}
), GL_COLOR_ATTACHMENT0, 0);
m_FrameBuffer->AddTexutreArrayAttachment(
new Texture2DArray(
Texture2DArray::Texture2DArraySettings
{
SHADOW_MAP_TEXTURE_UNIT, GL_RG32F, GL_RG, GL_FLOAT,
m_Settings.m_MapSize, m_Settings.m_MapSize, 1,
Texture::TextureFilterMode::NEAREST, Texture::TextureFilterMode::NEAREST,
Texture::TextureWrapMode::CLAMP_TO_BODER, Texture::TextureWrapMode::CLAMP_TO_BODER, Texture::TextureWrapMode::CLAMP_TO_BODER,
Color(1.0f, 1.0f, 1.0f, 1.0f), m_Settings.m_NumCascades
}
), GL_COLOR_ATTACHMENT0, 0);
}
}
Пропуск визуализации:
void ShadowMapRendererSystem::Update(std::vector<std::vector<std::reference_wrapper<Entity>>> entities, ECSManager* ecs)
{
for (auto& lightEntity : entities[0])
{
DirectionalLight& light = ecs->GetComponent<DirectionalLight>(lightEntity);
if (!light.m_CastShadows)
continue;
Camera& camera = ecs->GetComponent<Camera>(entities[1][0]);
auto& shadow = light.m_Shadow;
Shader& shader = shadow->GetSettings().m_FilterMode == ShadowSettings::FilterMode::PCF3x3 ? m_PCFShader : m_VSMShader;
shader.Bind();
RendererCommands::SetViewport(shadow->GetSettings().m_MapSize, shadow->GetSettings().m_MapSize);
UniformMat4f projectionUniform("u_Projection");
UniformMat4f viewUniform("u_View");
UniformMat4f modelUniform("u_Model");
viewUniform.SetValues(light.GetView());
shader.SetUniform(viewUniform);
Uniform1f nearUniform("u_Near");
Uniform1f farUniform("u_Far");
nearUniform.SetValues({ camera.GetNear() });
farUniform.SetValues({ camera.GetFar() });
if (shadow->GetSettings().m_FilterMode == ShadowSettings::FilterMode::VSM)
{
shader.SetUniform(nearUniform);
shader.SetUniform(farUniform);
shadow->GetFrameBuffer()->BindRenderBufferAttachmentWrite(0);
}
for (size_t i = 0; i < light.m_Shadow->GetSettings().m_NumCascades; i++)
{
shadow->GetFrameBuffer()->BindTextureArrayAttachmentWrite(0, i);
if (shadow->GetSettings().m_FilterMode == ShadowSettings::FilterMode::VSM)
{
RendererCommands::Clear(FrameBufferTypes::COLOR | FrameBufferTypes::DEPTH);
}
else
{
RendererCommands::Clear(FrameBufferTypes::DEPTH);
}
projectionUniform.SetValues(light.GetProjection(camera, i));
shader.SetUniform(projectionUniform);
for (auto& meshEntity : entities[2])
{
MeshRendererComponent& meshRenderer = ecs->GetComponent<MeshRendererComponent>(meshEntity);
if (meshRenderer.m_CastShadows)
{
Model* model = ecs->GetComponent<MeshFilterComponent>(meshEntity).m_Model;
Transform& transform = ecs->GetComponent<Transform>(meshEntity);
modelUniform.SetValues(transform.m_ModelMatrix);
shader.SetUniform(modelUniform);
for (auto& mesh : model->GetMeshes())
{
mesh.GetVertexArray()->Bind();
if (mesh.GetVertexArray()->GetIndexBuffer().GetID() != 0)
glDrawElements(GL_TRIANGLES, mesh.GetVertexArray()->GetIndexBuffer().GetCount(), GL_UNSIGNED_INT, nullptr);
else
glDrawArrays(GL_TRIANGLES, 0, mesh.GetVertexArray()->GetVertexBuffer().GetSize() / mesh.GetVertexArray()->GetVertexBuffer().GetLayout().GetStride());
}
}
}
}
if (shadow->GetSettings().m_FilterMode == ShadowSettings::FilterMode::VSM)
{
float quadVertices[] = {
-1.0f, 1.0f, 0.0f, 1.0f,
-1.0f, -1.0f, 0.0f, 0.0f,
1.0f, -1.0f, 1.0f, 0.0f,
-1.0f, 1.0f, 0.0f, 1.0f,
1.0f, -1.0f, 1.0f, 0.0f,
1.0f, 1.0f, 1.0f, 1.0f
};
std::shared_ptr<VertexArray> fbQuadVa = std::make_shared<VertexArray>();
VertexBufferLayout fbQuadVbl;
fbQuadVbl.Push({ GL_FLOAT, 2, sizeof(float) * 2, GL_FALSE });
fbQuadVbl.Push({ GL_FLOAT, 2, sizeof(float) * 2, GL_FALSE });
VertexBuffer fbQuadVb(quadVertices, sizeof(quadVertices), fbQuadVbl);
fbQuadVa->SetVertexBuffer(std::move(fbQuadVb));
std::shared_ptr<Material> fbQuadMat = std::make_shared<Material>();
Mesh fbQuadMesh(fbQuadVa, fbQuadMat);
fbQuadMesh.GetVertexArray()->Bind();
m_GuassianBlurVShader.Bind();
light.m_Shadow->GetFrameBuffer()->BindTextureAttachmentRead(0);
Uniform1i textureUniform("u_Texture");
textureUniform.SetValues({ (int)light.m_Shadow->GetFrameBuffer()->GetTextureAttachments()[0].second->m_Unit });
m_GuassianBlurVShader.SetUniform(textureUniform);
Uniform1f sigmaUniform("u_Sigma");
sigmaUniform.SetValues({ 1.0f });
m_GuassianBlurVShader.SetUniform(sigmaUniform);
Uniform1f muUniform("u_Mu");
muUniform.SetValues({ 0.0f });
m_GuassianBlurVShader.SetUniform(muUniform);
for (size_t i = 0; i < light.m_Shadow->GetSettings().m_NumCascades; i++)
{
shadow->GetFrameBuffer()->BindTextureArrayAttachmentWrite(1, i);
RendererCommands::Clear(FrameBufferTypes::COLOR);
Uniform1i depthUniform("u_Depth");
depthUniform.SetValues({ (int)i });
m_GuassianBlurVShader.SetUniform(depthUniform);
glDrawArrays(GL_TRIANGLES, 0, fbQuadMesh.GetVertexArray()->GetVertexBuffer().GetSize() / fbQuadMesh.GetVertexArray()->GetVertexBuffer().GetLayout().GetStride());
}
m_GuassianBlurHShader.Bind();
light.m_Shadow->GetFrameBuffer()->BindTextureAttachmentRead(1);
textureUniform.SetValues({ (int)light.m_Shadow->GetFrameBuffer()->GetTextureAttachments()[1].second->m_Unit });
m_GuassianBlurHShader.SetUniform(textureUniform);
m_GuassianBlurHShader.SetUniform(sigmaUniform);
m_GuassianBlurHShader.SetUniform(muUniform);
for (size_t i = 0; i < light.m_Shadow->GetSettings().m_NumCascades; i++)
{
shadow->GetFrameBuffer()->BindTextureArrayAttachmentWrite(2, i);
RendererCommands::Clear(FrameBufferTypes::COLOR);
Uniform1i depthUniform("u_Depth");
depthUniform.SetValues({ (int)i });
m_GuassianBlurHShader.SetUniform(depthUniform);
glDrawArrays(GL_TRIANGLES, 0, fbQuadMesh.GetVertexArray()->GetVertexBuffer().GetSize() / fbQuadMesh.GetVertexArray()->GetVertexBuffer().GetLayout().GetStride());
}
}
shadow->GetFrameBuffer()->Unbind();
}
RendererCommands::SetViewport(Screen::GetWidth(), Screen::GetHeight());
}
Гауссовское размытие шейдера:
#version 330 core
out vec4 color;
in VS_OUT
{
vec2 v_TexCoord;
} fs_in;
uniform sampler2DArray u_Texture;
uniform int u_Detph;
uniform float u_Sigma;
uniform float u_Mu;
#define K 1
#define PI 3.1415926535897932384626433832795
float gaussianDistribution(int x, float mu, float sigma)
{
float d = x - mu;
return exp(-d * d / (2 * sigma * sigma)) / (sqrt(2 * PI) * sigma);
};
void main()
{
const int rows = 2 * K + 1;
float kernel[rows];
float sum = 0.0f;
int count = rows / 2 + 1;
for (int i = 0; i < count; i++)
{
float distribution = gaussianDistribution(count - i - 1, u_Mu, u_Sigma);
kernel[i] = distribution;
if (i != count - 1)
{
kernel[rows - (i + 1)] = distribution;
sum += distribution + distribution;
}
else
{
sum += distribution;
}
}
for (int i = 0; i < count; i++)
{
kernel[i] /= sum;
if (i != count - 1)
{
kernel[rows - (i + 1)] = kernel[i];
}
}
float offset = textureSize(u_Texture, 0).y;
vec2 offsets[] = vec2[](
vec2(0.0f, -offset), // top
vec2(0.0f, 0.0f), // center
vec2(0.0f, offset) // bottom
);
vec3 sampleTex[rows];
for (int i = 0; i < rows; i++)
sampleTex[i] = vec3(texture(u_Texture, vec3(fs_in.v_TexCoord.st + offsets[i], u_Detph)));
vec3 col = vec3(0.0);
for (int i = 0; i < rows; i++)
col += sampleTex[i] * kernel[i];
//color = vec4(col, 1.0);
color = vec4(1.0, 1.0, 0.0, 1.0);
}
отображение отладочной текстуры:
#version 330 core
struct Material
{
sampler2DArray diffuse;
};
out vec4 color;
in VS_OUT
{
vec2 v_TexCoord;
} fs_in;
uniform Material u_Material;
void main()
{
color = vec4(vec3(texture(u_Material.diffuse, vec3(fs_in.v_TexCoord, 0)).r), 1.0f);
}
Теперь, если я выведу результат первого подпрохода при рисовании сцены в текстуру отладки, я вижу, что результат правильный, красный канал показывает правильные значения depth
, а зеленый канал показывает правильные значения depth^2
:
Но по какой-то причине, когда я вывожу результат второго / третьего подпроцесса, я вижу неправильный вывод (не размытый и выглядит как неправильный каскадный вид) текстура:
Я даже пытался установить фра Чтобы отладить его, нужно изменить значение затенения до outColor = vec4(1.0, 0.0, 0.0, 1.0)
, но оно по-прежнему отображает неверный результат, и я уверен, что код для выбора массива текстур, для которого будет отображаться текстура отладки, верен, я просто изменяю индекс для этого. Поэтому я не уверен, что здесь не так, но что-то не работает.
Буду признателен за помощь в определении кода виновника ?
ОБНОВЛЕНИЕ: Таким образом, отключение проверки глубины перед подпроцессом размытия по Гауссу и его повторное включение решает проблему неверного результата текстуры размытия. Изображение текстуры размытия - это вид с последнего каскада. Я не уверен, почему я должен это делать, так как текстурный квад находится в ND C с 0.0f
в качестве значения z, но я просто отключил тест глубины перед размытием (мог также очистить буфер глубины после основного l oop Наверное).
После этого я захотел проверить правильность размытия, но кажется, что оно только отбеливает изображение немного после прохождения вертикального размытия и отбеливает его еще больше после горизонтального пройти, так что я не знаю почему, но я думаю, что это как-то связано с шейдером размытия, любая помощь будет оценена. GIF показывает текстуру отладки значений глубины, затем значения глубины размыты по вертикали, а затем размыты по горизонтали (показаны только красные каналы; depth
значения, а не depth^2
значения): https://gfycat.com/keymadblacklab