我正在开发自己的游戏引擎并在此过程中学习 OpenGL,并且我在阴影贴图上的时间比我想承认的要长。
我一直在遵循本指南:https://learnopengl.com/Advanced-Lighting/Shadows/Shadow-Mapping 但我无法在我的飞机上绘制任何阴影。
这是代码在我的项目中的样子:
用于创建深度纹理的帧缓冲区:
glCreateFramebuffers(1, &m_framebufferID);
glBindFramebuffer(GL_FRAMEBUFFER, m_framebufferID);glGenTextures(1, &depthMapID);
ui32 depthMapID;
glBindTexture(GL_TEXTURE_2D, depthMapID);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 1024, 1024, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glBindFramebuffer(GL_FRAMEBUFFER, m_framebufferID);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthMapID, 0);
ASSERT(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, "Framebuffer is incomplete!");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
深度纹理着色器(忽略未使用的顶点布局):
#type vertex
#version 330 core
layout (location = 0) in vec3 vertex_position;
layout (location = 1) in vec3 vertex_color;
layout (location = 2) in vec3 vertex_normal;
layout (location = 3) in vec3 vertex_tangent;
layout (location = 4) in vec2 vertex_texcoord;
uniform mat4 u_lightViewProjectionMatrix;
uniform mat4 u_worldTransformMatrix;
void main()
{
gl_Position = u_lightViewProjectionMatrix * (u_worldTransformMatrix * vec4(vertex_position, 1.0));
}
#type fragment
#version 330 core
// Ouput data
//layout(location = 0) out float fragmentdepth;
void main(){
// Not really needed, OpenGL does it anyway
//fragmentdepth = gl_FragCoord.z;
}
这就是我创建阴影贴图的方式
if (s_castingShadowMeshes.Size() == 0)
return;
float shadowDistance = 100.0f;
glm::mat4 lightView = glm::lookAt(LightManager::GetDirectionalLight().direction * -shadowDistance, glm::vec3(0.0f), MathUtils::Vector3UnitY);
glm::mat4 lightProjection = glm::ortho(-shadowDistance, shadowDistance, -shadowDistance, shadowDistance, 0.0f, shadowDistance * 2.0f);
s_lightViewProjection = lightProjection * lightView;
glBindFramebuffer(GL_FRAMEBUFFER, m_framebufferID);
glViewport(0, 0, 1024, 1024); //Shadow height and width is 1024
glDepthMask(GL_TRUE);
glClearDepth(1.0f);
glClearColor(color.r, color.g, color.b, color.a);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT););
for (ui32 i = 0; i < s_castingShadowMeshes.Size(); ++i)
{
s_depthMapShader->Bind();
s_depthMapShader->SetUniform(UNIFORM_LIGHT_SPACE_TRANSFORM, ShaderDataType::Mat4, &(s_lightViewProjection));
s_depthMapShader->SetUniform(UNIFORM_MODEL_SPACE_TRANSFORM, ShaderDataType::Mat4, &(s_castingShadowMeshes[i]->GetWorldTransform()[0][0]));
s_rendererPlatformInterface->DrawVertexArray(s_castingShadowMeshes[i]->GetVertexArray());
s_renderStats.drawCalls++;
s_depthMapShader->Unbind();
}
s_shadowFramebuffer->Unbind();
到目前为止,RenderDoc 向我展示了实际上正在生成深度纹理:
现在,这就是渲染飞机的样子:
shader->Bind();
ui32 useShadowMapTex = 0;
if (receiveShadows)
{
useShadowMapTex = 1;
ui32 shadowMapSlot = (ui32)Material::TextureSlots::ShadowMap;
shader->SetUniform(UNIFORM_SHADOWMAP_TEX, ShaderDataType::Int, &shadowMapSlot);
s_shadowMapTex->Bind(shadowMapSlot);
}
shader->SetUniform(UNIFORM_USE_SHADOWMAP_TEX, ShaderDataType::Int, &useShadowMapTex);
shader->SetUniform(UNIFORM_MODEL_SPACE_TRANSFORM, ShaderDataType::Mat4, &(transform[0][0]));
shader->SetUniform(UNIFORM_VIEW_PROJECTION, ShaderDataType::Mat4, &(s_sceneData.viewProjectionMatrix));
shader->SetUniform(UNIFORM_CAMERA_POS, ShaderDataType::Float3, &(s_sceneData.cameraPosition));
shader->SetUniform(UNIFORM_DIR_LIGHT_DIRECTION, ShaderDataType::Float3, &(LightManager::GetDirectionalLight().direction));
shader->SetUniform(UNIFORM_DIR_LIGHT_AMBIENT,ShaderDataType::Float3, &(LightManager::GetDirectionalLight().ambientColor));
shader->SetUniform(UNIFORM_DIR_LIGHT_DIFUSSE, ShaderDataType::Float3, &(LightManager::GetDirectionalLight().diffuseColor));
shader->SetUniform(UNIFORM_DIR_LIGHT_SPECULAR, ShaderDataType::Float3, &(LightManager::GetDirectionalLight().specularColor));
s_rendererPlatformInterface->DrawVertexArray(vertexArray);
s_renderStats.drawCalls++;
s_renderStats.vertices += vertexArray->GetIndexBuffer()->GetCount();
平面着色器:
#type vertex
#version 330 core
layout (location = 0) in vec3 vertex_position;
layout (location = 1) in vec3 vertex_color;
layout (location = 2) in vec3 vertex_normal;
layout (location = 3) in vec3 vertex_tangent;
layout (location = 4) in vec2 vertex_texcoord;
out VS_OUT {
vec3 FragPos;
vec3 Normal;
vec2 TexCoords;
vec4 FragPosLightSpace;
} vs_out;
uniform mat4 u_viewProjectionMatrix;
uniform mat4 u_worldTransformMatrix;
uniform mat4 u_lightViewProjectionMatrix;
void main()
{
vs_out.FragPos = vec3(u_worldTransformMatrix * vec4(vertex_position, 1.0));
vs_out.Normal = transpose(inverse(mat3(u_worldTransformMatrix))) * vertex_normal;
vs_out.TexCoords = vertex_texcoord;
vs_out.FragPosLightSpace = u_lightViewProjectionMatrix * vec4(vs_out.FragPos, 1.0);
gl_Position = u_viewProjectionMatrix* vec4(vs_out.FragPos, 1.0);
}
#type fragment
#version 330 core
out vec4 FragColor;
in VS_OUT {
vec3 FragPos;
vec3 Normal;
vec2 TexCoords;
vec4 FragPosLightSpace;
} fs_in;
struct DirectionalLight
{
vec3 direction;
vec3 ambientColor;
vec3 diffuseColor;
vec3 specularColor;
};
uniform DirectionalLight u_directionalLight;
uniform sampler2D u_shadowMapTex;
uniform vec3 u_cameraPos;
float ShadowCalculation(vec4 fragPosLightSpace)
{
// perform perspective divide
vec3 projCoords = fragPosLightSpace.xyz / fragPosLightSpace.w;
// transform to [0,1] range
projCoords = projCoords * 0.5 + 0.5;
// get closest depth value from light's perspective (using [0,1] range fragPosLight as coords)
float closestDepth = texture(u_shadowMapTex, projCoords.xy).r;
// get depth of current fragment from light's perspective
float currentDepth = projCoords.z;
// check whether current frag pos is in shadow
float shadow = currentDepth > closestDepth ? 1.0 : 0.0;
return shadow;
}
void main()
{
vec3 normal = normalize(fs_in.Normal);
vec3 lightColor = vec3(1.0);
// ambient
vec3 ambient = u_directionalLight.ambientColor;
// diffuse
vec3 lightDir = normalize(u_directionalLight.direction);
float diff = max(dot(lightDir, normal), 0.0);
vec3 diffuse = diff * lightColor;
// specular
vec3 viewDir = normalize(u_cameraPos - fs_in.FragPos);
float spec = 0.0;
vec3 halfwayDir = normalize(lightDir + viewDir);
spec = pow(max(dot(normal, halfwayDir), 0.0), 64.0);
vec3 specular = spec * lightColor;
// calculate shadow
float shadow = ShadowCalculation(fs_in.FragPosLightSpace);
vec3 lighting = (ambient + (1.0 - shadow) * (diffuse + specular));
FragColor = vec4(lighting, 1.0);
}
这是我得到的:
根据RenderDoc,阴影贴图纹理实际上是在着色器中传递的,但它从未在红色平面中绘制:
我希望有人能帮助我。非常感谢。
p.d:这是我在 StackOverflow 上的第一篇文章,如果我违反了任何规则,请见谅。