使用OpenGL和GLSL的简单硬阴影映射技术的小工件

时间:2014-10-02 23:26:23

标签: opengl glsl shader fragment-shader shadow-mapping

由于我使用的纹理颜色较暗(这些文物不可见),因此我的阴影从未见过,我有一种奇怪的行为。以下是3个不同阴影贴图分辨率的问题截图:

1)Shadowmap 160 * 120

enter image description here

如你所见,立方体表面有一些牙齿。

这里是光线位置的场景视图:

enter image description here

这是影子地图:

enter image description here

2)Shadowmap 640 * 480

enter image description here

分辨率越高,伪像就越不可见,因为阴影贴图会带来更高的精度。

这里是光线位置的场景视图:

enter image description here

这是影子地图:

enter image description here

我尝试了更高的其他分辨率。当然,工件越来越小,但如果放大表面,它们仍然可见。

这是我在第二次传递期间在片段着色器中使用的代码:

[...]

uniform sampler2DShadow ShadowSampler[MAX_LIGHT_COUNT];

[...]

float GetDynamicShadowBias(vec3 normalDir_cs, vec3 lightDir_cs)
{
    float cosTheta = clamp(dot(normalDir_cs, lightDir_cs), 0.0f, 1.0f);
    float bias = 0.005f * tan(acos(cosTheta));

    return (clamp(bias, 0.0f, 0.01f));
}

float GetBiased_Hard_ShadowFactor(vec3 normalDir, vec3 lightDir, int idx)
{    
    if (ShadowCoords[idx].w > 0.0f)
    {
        float bias = GetDynamicShadowBias(normalDir, lightDir);

        float LightToOccluderClipDist = texture(
            ShadowSampler[idx], ShadowCoords[idx].xyz/ShadowCoords[idx].w);

        float LightToVertexClipDist = (ShadowCoords[idx].z - bias)/ShadowCoords[idx].w;

        if (LightToOccluderClipDist < LightToVertexClipDist)
            return (0.0f);
    }
    return (1.0f);
}

所以我想知道是否有可能在立方体的边缘上移除这些瑕疵。我尝试使用阴影偏差而没有真正的成功(对于我在第一次传递期间使用FRONT_FACE剔除(填充深度纹理)的信息)。

1 个答案:

答案 0 :(得分:1)

这里有两件事。一个是这是标准阴影贴图的限制。因为任何给定对象的阴影将占据地图中可能较少数量的像素,当您将该地图投射到场景上时,这些部分可以重新放大并且您将获得锯齿。

似乎正在发生的第二件事是你的阴影基本上是1位,它出现了。它们是黑色或白色。如果你以某种方式在制作它时对地图进行抗锯齿处理(比如超级采样或其他一些技术),那就不太明显了(虽然根据我的经验它不会完全消失)。

有一些基于经典阴影贴图的技术。一个是来自SIGGRAPH 2013的Subpixel Shadow Mapping。(有some other shadow papers that year, too。)我最近还看到了通过GLSL实时实现的光线投影阴影。 (对不起,找不到链接!如果我能把它挖出来,我会稍后发帖。)