使用延迟渲染(OpenGL)进行阴影映射

时间:2016-08-15 19:25:40

标签: opengl glsl rendering shader shadow-mapping

所以我一直试图在过去的一周里围绕OpenGL中的阴影贴图进行包围,但它并没有那么好。所以我希望有人可以帮助我。 我一直在学习使用LearnOpenGL的阴影映射教程中的阴影映射,该教程使用正向渲染,从我收集的内容看起来像延迟的阴影映射有点不同。 首先,这是我的影子地图:

Shadow map picture

由于某种原因它是红色的,但显然根据朋友说这没关系。但我仍然觉得我已经做错了什么。但假设不是这样,阴影贴图会正确渲染并且在没有任何问题的情况下到达延迟渲染的光照通道。我还发送了一个缓冲区,其中包含了我使用光空间变换矩阵变换的光空间中的所有片段。

//Create LSMatrix
    GLfloat near_plane = 1.0f;
    GLfloat far_plane = 10.0f;
    glm::mat4 lightProjMat = glm::ortho(-10.0f, 10.0f, -10.0f, 10.0f, near_plane, far_plane);
    glm::mat4 lightPerspective = glm::lookAt(glm::vec3(-2.0f, 6.0f, -1.0f),
                                                glm::vec3(0.0f, 0.0f, 0.0f),
                                                glm::vec3(0.0f, 1.0f, 0.0f));

    shadowBuf.lightSpaceMat = lightProjMat * lightPerspective;

我现在没有方向灯,只有两个点光源。所以使用正交投影,所有这些都会给我一个不正确的阴影。但仍然是一个阴影。现在影子的来源并不重要,我只是想学习。然后我可以担心如何让它与光源相匹配。

这里它被用在几何传递的GLSL顶点着色器中。 (LSMat)

void main()
{
    gl_Position = vec4(position, 1.0f);
    vs_out.uv = uv;
    vs_out.normal = normal;
    vs_out.FragPos = vec3(model * vec4(position, 1.0f));
    vs_out.FragPosLS = LSMat * vec4(vs_out.FragPos, 1.0f); //Fragment position in light space
}

然后在片段着色器中将其保存到纹理并运送到光照通道。

所以现在我拥有在照明通道中进行阴影计算所需的一切。 (希望至少)

以下是我在进行阴影计算的光通道中片段着色器的一部分:

float shadowCalc()
{
    vec4 fragPosLS = texture(gFragPosLS, uvs); //Fetch the lightspace frag pos from the texture

    vec3 projCoords = fragPosLS.xyz / fragPosLS.w; //Manually do perspective divison
    projCoords = projCoords * 0.5 + 0.5; //Get the pos in [0,1] range

    float closestDepth = texture(shadowMap, projCoords.xy).r;
    float currentDepth = projCoords.z;

    float shadow = currentDepth > closestDepth ? 1.0 : 0.0;

    return shadow;
}

最后,我在漫反射和镜面反射值上使用此阴影值:

    float shadowValue = shadowCalc();
    diffuse = diffuse * (1.0 - shadowValue);
    specular = specular * (1.0 - shadowValue);

    return ((diffuse * vec4(gColor, 1.0f)) + specular + ambient);

然后我就像平常一样输出结果颜色,结果如下:

Picture of the result

可怕的纹理只是因为我现在没有在Maya中烦扰UV地图的事情。但除此之外,你可以清楚地看到它是各种各样的搞砸了。我甚至尝试禁用其中一个灯以确保它没有断开,因为我有两个灯执行shadowCalc功能,但事实并非如此。但我对此并不是100%肯定。

如果有人对此为何发生任何想法,那么我全都听见了。一个星期以来我一直困扰着我,我似乎无法弄清楚为什么会这样。我只知道当我使用阴影偏差时,地面上的条纹消失,但金字塔背后的巨大阴影仍在那里。它不仅看起来很糟糕,而且如果将它与渲染阴影贴图的角度进行比较,它也会指向完全错误的方向。所以它必须是坐标的东西。我读到了一些关于延迟渲染如何要求你以不同的方式做某些事情的事情,但我还没有设法得到一个正确的答案。

这已经是相当庞大的帖子,但是如果我忘记展示任何可能会让事情变得清晰的事情,那就告诉我们。

1 个答案:

答案 0 :(得分:0)

只是在黑暗中刺伤:我遇到了阴影贴图与延迟渲染相结合的问题,这看起来非常类似于你在屏幕截图中显示的内容。就我而言,我正在从深度纹理中错误地读取Z值。使用

创建的深度纹理中的值

gl.texImage2D(gl.TEXTURE_2D, 0, gl.DEPTH_COMPONENT16, 2048, 2048, 0, gl.DEPTH_COMPONENT, gl.UNSIGNED_SHORT, null);

被标准化为(-1;+1)所以我不得不将它们修改为

texture(shadowMap, projCoords.xy).r - .5) * 2.

可见性计算看起来像:

float bias = .01;
float visibility = (texture(shadowMap, projCoords.xy).r - .5) * 2. < projCoords.z - bias ? 0.1: 1.0;