Проблема расчета теней с рендерингом ShadowMap - PullRequest
0 голосов
/ 02 мая 2020

У меня небольшие проблемы с реализацией Shadow Mapping в движке, который я делаю. Я следую учебнику LearnOpenGL , чтобы сделать это, и более или менее это «работает», но есть что-то, что я делаю неправильно, например, если что-то в карте теней было изменено или что-то еще, проверьте следующие гифки: gif1 , gif2

В этих гифках есть простая сцена с направленным светом (который имеет ортогональное усеченное кольцо для вычисления теней и облегчить мою жизнь), которая должна отбрасывать тени. Затем, справа, есть небольшое окно, показывающее «сцену карты теней», сцена, визуализированная с точки зрения источника света только со значениями глубины.

Теперь, что касается кода, он довольно точно следует указаниям из упомянутый учебник. У меня есть ModuleRenderer, и я сначала создаю фреймбуферы с текстурами, которые у них должны быть:

    glGenTextures(1, &depthMapTexture);
    glBindTexture(GL_TEXTURE_2D, depthMapTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, App->window->GetWindowWidth(), App->window->GetWindowHeight(), 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);

    glGenFramebuffers(1, &depthbufferFBO);
    glBindFramebuffer(GL_FRAMEBUFFER, depthbufferFBO);
    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMapTexture, 0);
    glDrawBuffer(GL_NONE);
    glReadBuffer(GL_NONE);

    glBindFramebuffer(GL_FRAMEBUFFER, 0);
    glBindTexture(GL_TEXTURE_2D, 0);

Затем, в обновлении после рендера модуля, я делаю 2 прохода рендера и рисую FBO:

    // --- Shadows Buffer (Render 1st Pass) ---
    glBindFramebuffer(GL_FRAMEBUFFER, depthbufferFBO);
    SendShaderUniforms(shadowsShader->ID, true);
    DrawRenderMeshes(true);
    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    // --- Standard Buffer (Render 2nd Pass) ---
    glBindFramebuffer(GL_FRAMEBUFFER, fbo);
    SendShaderUniforms(defaultShader->ID, false);
    DrawRenderMeshes(false);

    // --- Draw Lights ---
    std::vector<ComponentLight*>::iterator LightIterator = m_LightsVec.begin();
    for (; LightIterator != m_LightsVec.end(); ++LightIterator)
        (*LightIterator)->Draw();

    glBindFramebuffer(GL_FRAMEBUFFER, 0);

    // -- Draw framebuffer textures ---
    DrawFramebuffer(depth_quadVAO, depthMapTexture, true);
    DrawFramebuffer(quadVAO, rendertexture, false);

Функция DrawRenderMeshes (), в основном, получает список мешей для рисования, шейдер, который он должен выбрать, и отправляет все необходимые формы. Здесь огромная функция, но для обычного me sh он получает шейдер Standard и отправляет все, что ему нужно. Для карты теней, она отправляет текстуру, прикрепленную к глубине FBO:

    glUniform1i(glGetUniformLocation(shader, "u_ShadowMap"), 4);
    glActiveTexture(GL_TEXTURE0 + 4);
    glBindTexture(GL_TEXTURE_2D, depthMapTexture);

В стандартном шейдере для вершины я просто передаю униформу для светового пространства (проекции светового луча x матриц вида) в рассчитать положение фрагмента в световом пространстве (следующее делается в главном):

    v_FragPos = vec3(u_Model * vec4(a_Position, 1.0));
    v_FragPos_InLightSpace = u_LightSpace * vec4(v_FragPos, 1.0);
    v_FragPos_InLightSpace.z = (1.0 - v_FragPos_InLightSpace.z);
    gl_Position = u_Proj * u_View * vec4(v_FragPos, 1.0);

И для фрагмента я вычисляю с этим значением затенение фрагмента (диффузное + зеркальное значение света умножаются на результат этой функции теневого копирования):

float ShadowCalculation()
{
    vec3 projCoords = v_FragPos_InLightSpace.xyz / v_FragPos_InLightSpace.w;
    projCoords = projCoords * 0.5 + 0.5;
    float closeDepth = texture(u_ShadowMap, projCoords.xy).z;
    float currDept = projCoords.z;

    float shadow = currDept > closeDepth ? 1.0 : 0.0;
    return (1.0 - shadow);
}

Опять же, я не уверен, что может быть не так, но я могу догадаться, что что-то вроде инвертировано? Не уверен ... Если кто-нибудь может что-то представить и сообщить мне, я был бы очень признателен, спасибо вам:)

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

gl_Position = u_Proj * u_View * u_Model * vec4(a_Position, 1.0);

И фрагмент ничего не делает, это пустой main (), поскольку это то же самое, что делать то, что мы хотим для теней pass

gl_FragDepth = gl_FragCoord.z;
...