我目前正在开发一个OpenGL项目,我正在尝试使阴影贴图正常工作。我可以到达阴影贴图渲染到纹理中的点,但在渲染时似乎不会应用于场景。这是我的代码中最重要的部分:
阴影贴图顶点着色器,基本上是一个简单的通过着色器(也做一些像法线一样的额外的东西,但这不应该分散你的注意力);它基本上只是转换顶点,所以它们是从光的角度看到的(它是一个定向光,但由于我们需要假设一个位置,它基本上是一个远点):
#version 430 core
layout(location = 0) in vec3 v_position;
layout(location = 1) in vec3 v_normal;
layout(location = 2) in vec3 v_texture;
layout(location = 3) in vec4 v_color;
out vec3 f_texture;
out vec3 f_normal;
out vec4 f_color;
uniform mat4 modelMatrix;
uniform mat4 depthViewMatrix;
uniform mat4 depthProjectionMatrix;
// Shadow map vertex shader.
void main() {
mat4 mvp = depthProjectionMatrix * depthViewMatrix * modelMatrix;
gl_Position = mvp * vec4(v_position, 1.0);
// Passing attributes on to the fragment shader
f_texture = v_texture;
f_normal = (transpose(inverse(modelMatrix)) * vec4(v_normal, 1.0)).xyz;
f_color = v_color;
}
将深度值写入纹理的阴影贴图片段着色器:
#version 430 core
layout(location = 0) out float fragmentDepth;
in vec3 f_texture;
in vec3 f_normal;
in vec4 f_color;
uniform vec3 lightDirection;
uniform sampler2DArray texSampler;
// Shadow map fragment shader.
void main() {
fragmentDepth = gl_FragCoord.z;
}
实际渲染场景的顶点着色器,还可以从灯光视角(shadowCoord)计算当前顶点的位置,以与深度纹理进行比较;它也应用偏差矩阵,因为坐标不在正确的[0,1]间隔内进行采样:
#version 430 core
layout(location = 0) in vec3 v_position;
layout(location = 1) in vec3 v_normal;
layout(location = 2) in vec3 v_texture;
layout(location = 3) in vec4 v_color;
out vec3 f_texture;
out vec3 f_normal;
out vec4 f_color;
out vec3 f_shadowCoord;
uniform mat4 modelMatrix;
uniform mat4 viewMatrix;
uniform mat4 projectionMatrix;
uniform mat4 depthViewMatrix;
uniform mat4 depthProjectionMatrix;
// Simple vertex shader.
void main() {
mat4 mvp = projectionMatrix * viewMatrix * modelMatrix;
gl_Position = mvp * vec4(v_position, 1.0);
// This bias matrix adjusts the projection of a given vertex on a texture to be within 0 and 1 for proper sampling
mat4 depthBias = mat4(0.5, 0.0, 0.0, 0.5,
0.0, 0.5, 0.0, 0.5,
0.0, 0.0, 0.5, 0.5,
0.0, 0.0, 0.0, 1.0);
mat4 depthMVP = depthProjectionMatrix * depthViewMatrix * modelMatrix;
mat4 biasedDMVP = depthBias * depthMVP;
// Passing attributes on to the fragment shader
f_shadowCoord = (biasedDMVP * vec4(v_position, 1.0)).xyz;
f_texture = v_texture;
f_normal = (transpose(inverse(modelMatrix)) * vec4(v_normal, 1.0)).xyz;
f_color = v_color;
}
片段着色器,它应用纹理数组中的纹理并接收深度纹理(uniform sampler2D shadowMap)并检查片段是否落后于某些东西:
#version 430 core
in vec3 f_texture;
in vec3 f_normal;
in vec4 f_color;
in vec3 f_shadowCoord;
out vec4 color;
uniform vec3 lightDirection;
uniform sampler2D shadowMap;
uniform sampler2DArray tileTextureArray;
// Very basic fragment shader.
void main() {
float visibility = 1.0;
if (texture(shadowMap, f_shadowCoord.xy).z < f_shadowCoord.z) {
visibility = 0.5;
}
color = texture(tileTextureArray, f_texture) * visibility;
}
最后:渲染多个块以生成阴影贴图然后使用阴影贴图渲染场景的函数:
// Generating the shadow map
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
m_shadowShader->bind();
glViewport(0, 0, 1024, 1024);
glDisable(GL_CULL_FACE);
glm::vec3 lightDir = glm::vec3(1.0f, -0.5f, 1.0f);
glm::vec3 sunPosition = FPSCamera::getPosition() - lightDir * 64.0f;
glm::mat4 depthViewMatrix = glm::lookAt(sunPosition, FPSCamera::getPosition(), glm::vec3(0, 1, 0));
glm::mat4 depthProjectionMatrix = glm::ortho<float>(-100.0f, 100.0f, -100.0f, 100.0f, 0.1f, 800.0f);
m_shadowShader->setUniformMatrix("depthViewMatrix", depthViewMatrix);
m_shadowShader->setUniformMatrix("depthProjectionMatrix", depthProjectionMatrix);
for (Chunk *chunk : m_chunks) {
m_shadowShader->setUniformMatrix("modelMatrix", chunk->getModelMatrix());
chunk->drawElements();
}
m_shadowShader->unbind();
glBindFramebuffer(GL_FRAMEBUFFER, 0);
// Normal draw call
m_chunkShader->bind();
glEnable(GL_CULL_FACE);
glViewport(0, 0, Window::getWidth(), Window::getHeight());
glm::mat4 viewMatrix = FPSCamera::getViewMatrix();
glm::mat4 projectionMatrix = FPSCamera::getProjectionMatrix();
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
glActiveTexture(GL_TEXTURE1);
m_textures->bind();
m_chunkShader->setUniformMatrix("depthViewMatrix", depthViewMatrix);
m_chunkShader->setUniformMatrix("depthProjectionMatrix", depthProjectionMatrix);
m_chunkShader->setUniformMatrix("viewMatrix", viewMatrix);
m_chunkShader->setUniformMatrix("projectionMatrix", projectionMatrix);
m_chunkShader->setUniformVec3("lightDirection", lightDir);
m_chunkShader->setUniformInteger("shadowMap", 0);
m_chunkShader->setUniformInteger("tileTextureArray", 1);
for (Chunk *chunk : m_chunks) {
m_chunkShader->setUniformMatrix("modelMatrix", chunk->getModelMatrix());
chunk->drawElements();
}
大多数代码应该是不言自明的,我绑定了一个附加了纹理的FBO,我们对framebuffer进行了正常的渲染调用,它被渲染成一个纹理,然后我试图将它传递给用于正常渲染的着色器。我已经测试了纹理是否正确生成并且确实如此:在此处查看生成的阴影贴图
但是,在渲染场景时,我看到的只有这一点。
没有应用阴影,可见性到处都是1.0。我还使用了一个正常工作的调试上下文,并在有任何错误时记录错误,但它似乎完全正常,没有警告或错误,所以我在这里做了一件非常错误的事情。顺便说一下,我正在使用OpenGL 4.3。
希望你们其中一个可以帮我解决这个问题,我以前从来没有使用阴影贴图,这是我最接近过的,哈哈。提前谢谢。
答案 0 :(得分:0)
通常mat4
OpenGL转换矩阵如下所示:
( X-axis.x, X-axis.y, X-axis.z, 0 )
( Y-axis.x, Y-axis.y, Y-axis.z, 0 )
( Z-axis.x, Z-axis.y, Z-axis.z, 0 )
( trans.x, trans.y, trans.z, 1 )
因此,用于将标准化设备坐标(在ranage [-1,1]中)转换为纹理坐标(在范围[0,1]中)的depthBias
矩阵应如下所示:< / p>
mat4 depthBias = mat4(0.5, 0.0, 0.0, 0.0,
0.0, 0.5, 0.0, 0.0,
0.0, 0.0, 0.5, 0.0,
0.5, 0.5, 0.5, 1.0);
或者这个:
mat4 depthBias = mat4(
vec4( 0.5, 0.0, 0.0, 0.0 ),
vec4( 0.0, 0.5, 0.0, 0.0 ),
vec4( 0.0, 0.0, 0.5, 0.0 ),
vec4( 0.5, 0.5, 0.5, 1.0 ) );
通过模型矩阵,视图矩阵和投影矩阵变换顶点位置后,顶点位置位于剪辑空间(homogeneous coordinates)中。您必须从剪辑空间转换为规范化设备坐标(范围[-1,1]中的cartesian coordinates)。这可以通过将homogeneous coordinate:
w
组件除以来完成
mat4 depthMVP = depthProjectionMatrix * depthViewMatrix * modelMatrix;
vec4 clipPos = depthMVP * vec4(v_position, 1.0);
vec4 ndcPos = vec4(clipPos.xyz / clipPos.w, 1.0);
f_shadowCoord = (depthBias * ndcPos).xyz;
深度纹理仅具有一个通道。如果从深度纹理中读取数据,则数据包含在向量的x(或r)分量中。
调整片段着色器代码,如下所示:
if ( texture(shadowMap, f_shadowCoord.xy).x < f_shadowCoord.z)
visibility = 0.5;
Khronos集团的Image Format规范说:
图像格式不必存储每个组件。当着色器 对这样的纹理进行采样,它仍将解析为4值RGBA 向量。未填写图像格式的组件 自动。如果缺少R,G或B,则使用零,而a 失踪Alpha总是解析为1。
进一步了解:
这是解决方案的一个重要部分,但还需要另一个步骤来正确渲染阴影贴图。第二个错误是使用纹理的错误组件来比较f_shadowCoord.z:它应该是
texture(shadowMap, f_shadowCoord.xy).r
而不是
texture(shadowMap, f_shadowCoord.xy).z