为什么你的偏差基于光和表面之间的角度?这就是造成这些奇异的莫尔条纹的原因。通常,如果您想根据角度对深度进行偏差(将其想象为阴影贴图的各向异性偏差),您将glPolygonOffset (...)
在创建阴影贴图时使用,并且在着色器中您将使用恒定偏差或随距离略有变化的偏差(但不是角度)。
然而,多边形偏移的问题在于,它会在启用时禁用分层 Z 缓冲(因此阴影贴图构造填充率理论上会下降)。偏移发生在基元组装之后。这不是一个完美的解决方案,但绝对比你现在拥有的更好。
您可以通过稍微偏置 W 坐标在阴影贴图的顶点着色器中实现基于斜率的偏置,这将允许使用原始组装阶段的结果进行早期 Z 拒绝......但很难找到一个好的值用于 W。
...所以我决定将 sampler2Dshadow 与 shadow2D 一起使用,因为我读过它作为简单的抗锯齿解决方案。
至于和之间的区别sampler2D
,sampler2DShadow
当在调用texture (...)
(或shadow2D (...)
旧版本的 GLSL)sampler2DShadow
中使用启用了纹理比较的 a 时,将产生二进制结果 -如果通过测试函数,则为1.0 ,如果失败,则为0.0。考虑到您的片段着色器已经执行了比较并期望采样器返回的值是深度,而不是您应该使用的通过/失败结果——在这种情况下忽略 的存在。sampler2D
sampler2DShadow
我不知道您使用的是什么版本的 GLSL,因为您使用的是shadow2D (...)
早已被弃用的 . 但是,如果您查看版本 440 的 GLSL 规范,请参阅第 440页。153(8.9 - 纹理函数)它将向您推荐我上面包含的表格。
对于阴影形式(采样器参数是阴影类型),在绑定到采样器的深度纹理上进行深度比较查找,如 OpenGL 图形系统规范的第 8.22 节“纹理比较模式”中所述。请参阅下表,了解哪个组件指定了 D ref。绑定到采样器的纹理必须是深度纹理,否则结果未定义。如果对代表深度纹理且深度比较打开的采样器进行非阴影纹理调用,则结果未定义。如果在深度比较关闭的情况下对表示深度纹理的采样器进行阴影纹理调用,则结果未定义。如果对不代表深度纹理的采样器进行阴影纹理调用,则结果未定义。
有效地sampler2DShadow
减少锯齿,但仅仅是因为它产生了两个结果:1.0和0.0,这些结果的平均值比平均深度更有意义(我将在下面解释)。所以这句话有一些道理,但我相信你已经断章取义了。
实际上,如果你想减少阴影混叠,你应该做的是取 N 次深度测试的平均值。使用线性过滤通常是减少传统纹理中锯齿的有效方法,但对于深度纹理,存储在纹理中的值实际上应该用于比较目的。如果您使用线性过滤和sampler2D
,GPU 将收集阴影贴图中最近的 4 个深度,对它们进行平均,然后您将对平均深度执行单次通过/失败测试。这实际上对您没有任何用处,因为您的片段仍然通过或失败。
您要做的是收集 4 个最近的深度,分别测试它们,然后平均通过/失败结果。然后,您可能会天真地拥有 0%、25%、50%、75% 或 100% 的障碍,而不是每个片段都通过或失败——实际上,平均值可能由每个样本与样本坐标的距离加权。这称为Percentage Closer Filtering (PCF),如果您在某些驱动程序上启用线性过滤shadow2D (...)
,实际上就是这样做的。sampler2DShadow
他们不是对采样深度进行平均,而是对采样深度进行测试,然后对所有测试的结果进行平均。
这实际上是抗锯齿属性的sampler2DShadow
来源,但您必须正确构建 GLSL 着色器才能利用它。您可以使用 NEAREST 过滤器自己轻松(且更便携)采样 4 个点sampler2D
,然后自己执行测试和平均...
另外,尽量不要读取z
深度纹理的组件。您很幸运,对于 GLSL >= 130 的版本,采样深度纹理会产生结果:vec4 (r, r, r, 1.0)
,但在旧版本的 GLSL 中,行为取决于称为深度纹理模式的东西。也有可能z
是0.0或完全未定义的 pre-GL3。您应该阅读r
or x
,因为深度纹理本质上是单分量的。上表甚至表明了这一点——计算结果存储在 中r
,而不是b
.