карта теней проход пингпонг размытие - PullRequest
0 голосов
/ 20 апреля 2020

Я пытаюсь создать проход карты теней дисперсии.

Итак, сейчас у меня есть 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: enter image description here enter image description here

Но по какой-то причине, когда я вывожу результат второго / третьего подпроцесса, я вижу неправильный вывод (не размытый и выглядит как неправильный каскадный вид) текстура:

enter image description here

Я даже пытался установить фра Чтобы отладить его, нужно изменить значение затенения до 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

...