У меня небольшие проблемы с реализацией 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;