OpenGL阴影映射几乎可以工作
Posted
技术标签:
【中文标题】OpenGL阴影映射几乎可以工作【英文标题】:OpenGL shadow mapping almost working 【发布时间】:2013-09-26 21:47:23 【问题描述】:我正在尝试按照教程为我的类似 Minecraft 的克隆添加实时阴影映射:here
首先会发生什么:
据我所知,阴影贴图渲染正确吗?问题似乎出在最后一遍。
我创建深度纹理:
glGenFramebuffers(1, &m_frameBufferId);
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferId);
glGenTextures(1, &m_depthTexture);
glBindTexture(GL_TEXTURE_2D, m_depthTexture);
glTexImage2D(GL_TEXTURE_2D, 0,GL_DEPTH_COMPONENT16, 1024, 1024, 0,GL_DEPTH_COMPONENT, GL_FLOAT, 0);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_FUNC, GL_LEQUAL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_COMPARE_MODE, GL_NONE);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, m_depthTexture, 0);
glDrawBuffer(GL_NONE);
注意:我还尝试在着色器中使用带有 sampler2DShadow 的 GL_COMPARE_R_TO_TEXTURE。同样的结果。
然后运行两遍:
// ==================== Shadow =====================
glBindFramebuffer(GL_FRAMEBUFFER, m_frameBufferId);
glViewport(0, 0, 1024, 1024);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
ShadowShader->Bind();
VCSceneGraph::Instance->RenderGraph();
// ==================== Final =======================
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glViewport(0, 0, 1280, 800);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
VoxelShader->Bind();
VCSceneGraph::Instance->RenderGraph();
阴影着色器代码:
// ==================== Vert =====================
#version 330 core\n
in vec4 vertexPosition_modelspace;
uniform mat4 depthMVP;
void main()
gl_Position = depthMVP * vertexPosition_modelspace;
// ==================== Frag =====================
#version 330 core\n
out float fragmentdepth;
void main()
fragmentdepth = gl_FragCoord.z;
Final-Pass(体素着色器)代码:
// ==================== Vert =====================
#version 330 core\n
in vec3 position;
in int normal;
in vec4 color;
out vec4 colorVarying;
out vec4 ShadowCoord;
uniform mat4 modelViewProjectionMatrix;
uniform mat4 DepthBiasMVP;
void main()
gl_Position = modelViewProjectionMatrix * vec4(position, 1);
ShadowCoord = DepthBiasMVP * vec4(position, 1);
colorVarying = color;
// ==================== Frag =====================
#version 330 core\n
in vec4 colorVarying;
in vec4 ShadowCoord;
out vec4 color;
uniform sampler2D shadowMap;
void main()
float visibility = 1.0;
if ( texture(shadowMap, ShadowCoord.xy).z < ShadowCoord.z)
visibility = 0.5;
color.xyz = colorVarying.xyz * visibility;
color.w = colorVarying.w;
我怀疑我的问题在于更新制服以进行最后一关的代码:
// Re-create the exact same MVP matrix that was used for the shadow pass
glm::mat4 depthProjectionMatrix = glm::ortho<float>( -30, 30, -30, 30, -100, 100);
glm::mat4 depthViewMatrix = glm::lookAt(glm::vec3(0.5f, 2, 2), glm::vec3(0,0,0), glm::vec3(0,1,0));
depthViewMatrix = glm::translate(depthViewMatrix, -15.0f, 30.0f, 0.0f);
glm::mat4 depthMVP = depthProjectionMatrix * depthViewMatrix;// * modelMatrix;
// Multiply it be the bias matrix
glm::mat4 biasMatrix
(
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
);
glm::mat4 depthBiasMVP = biasMatrix * depthMVP;
// Create Camera's MVP
VCCamera* currentCamera = VCSceneGraph::Instance->CurrentRenderingCamera;
glm::mat4 ProjectionMatrix = currentCamera->ProjectionMatrix;
glm::mat4 ViewMatrix = currentCamera->ViewMatrix;
glm::mat4 MVP = ProjectionMatrix * ViewMatrix;// * modelMatrix;
// Update uniforms
glUniformMatrix4fv(m_unifMVP, 1, GL_FALSE, &MVP[0][0]);
glUniformMatrix4fv(m_unifDepthMVP, 1, GL_FALSE, &depthBiasMVP[0][0]);
编辑:
我通过使阴影纹理与窗口具有相同的分辨率解决了这个问题。但是,我无法解释为什么会解决它。如果其他人想破解它,我会接受你的回答。预期的输出是这样的:
我还应该注意到完整的源代码可以在:GitHub.
【问题讨论】:
感谢您的帮助。我添加了 ShadowCoord.xyz = ShadowCoord.xyz / ShadowCoord.w;乘以 DepthBiasMVP 后到我的顶点着色器,但没有效果。 您期待什么结果?另外,您能否在某些 3D 建模软件中提供您的场景、相机和光源位置/方向的屏幕截图之类的东西,这样我就可以想象什么结果应该被认为是“正确的”?从我在阴影贴图上看到的 - 不应该有任何阴影,因为你的对象几乎没有阴影投射 - 也许它甚至是凸的,在这个视图上很难看到。 如果将第二个视口设置为 1024 x 1024 会怎样? 有趣的是,什么也没发生。事实上,我设置的第二个 View 端口的值似乎无关紧要。场景仍然像以前一样渲染。奇怪... 嗯,你能在表面上应用照明或在表面上渲染线框吗?并指示照明位置?使用当前的屏幕截图,很难弄清楚您的几何形状是什么样的。 【参考方案1】:我比较了你和我的影子,我建议你使用sampler2DShadow
而不是sampler2D
。此采样器仅用于阴影,并且有一些阴影投影功能(shadow2DProj 等)。你可以这样使用它。
in vec4 colorVarying;
varying vec4 ShadowCoord;
out vec4 color;
uniform sampler2DShadow shadowMap;
float offset_lookup(sampler2DShadow map, vec4 loc, vec2 offset)
//Texture size (1024 x 1024)
vec2 texmapscale = vec2(1.0/1024.0, 1.0/1024.0);
//Set bias as you need (it corrects shadow acne)
float bias = 0.001;
vec4 result = shadow2DProj(map, vec4(loc.xy + offset * texmapscale * loc.w, loc.z, loc.w));
if (loc.z > result.z + bias)
return 0.5;
else
return 1.0;
void main()
float shadowFactor;
shadowFactor = offset_lookup(shadowMap, ShadowCoord, vec2(0, 0));
color = colorVarying * shadowFactor;
什么是最后一个参数偏移量?你可以做一些阴影模糊。 3x3 阴影模糊:
//3x3 blur
for (y = -1.5; y <= 1.5; y += 1.0)
for (x = -1.5; x <= 1.5; x += 1.0)
sum += offset_lookup(shadowMap, ShadowCoord, vec2(x, y));
//I am no sure why 16 (insted of 9) but I use this and it works :D
float shadeFactor = sum / 16.0;
试试吧,也许结果会如你所愿。
PS:对不起我的英语。
【讨论】:
以上是关于OpenGL阴影映射几乎可以工作的主要内容,如果未能解决你的问题,请参考以下文章
使用立方体贴图(OpenGL/GLSL)的点光源是不是可以实现软阴影?