阴影贴图,距离与深度比较?

时间:2014-04-15 08:44:09

标签: c++ opengl shadow

我一直在看阴影贴图,我看到一些人写了阴影通道中深度纹理的平方距离,而有些则使用实际的深度值。有什么理由比较喜欢一个吗?使用实际深度值似乎更快?

3 个答案:

答案 0 :(得分:1)

在对其中一个答案的评论中,我注意到你提到了我写的另一个答案,我想确保你理解答案的原始背景。

虽然到目前为止答案都集中在实际比较本身的复杂性上,但他们没有考虑改变存储在硬件深度缓冲区中的值对阴影贴图构造性能的影响。您担心早期Z拒绝的影响,这是一个有效的问题,但它只会影响阴影贴图 构造 的性能,我将在下面解释。< / p>

另外,请记住,answer you are referring to与基于立方体贴图的阴影贴图有关。由于它们的构造和采样的独特方式,它们有一系列的挑战需要处理,这就是为什么比较与你在其他环境中看到的略有不同。


现代GPU使用图块层次压缩颜色和深度缓冲区以增加内存吞吐量。

此压缩不会节省存储空间(事实上,它会增加一点额外的存储空间),但它所做的是允许 更多 更快的缓冲区清除取。不是将相同的颜色或深度写入缓冲区中的每个像素,而是将每个图块标记为&#34;清除&#34;并给出明确的颜色/深度。当需要获取像素的颜色/深度时,首先发生的事情是看到像素所属的图块,如果整个图块是清晰的,则返回图块的颜色而不是通过从内存中获取实际像素的麻烦。

很棒......但压缩与早期深度测试有什么关系呢?

实际上很多。这种分层存储器结构很好地一次拒绝大量片段,因为可以在单个专用存储器操作中确定整个片值的像素的最小/最大深度。这意味着写入颜色/深度缓冲区要复杂得多(必须更新标志和每个磁贴),但硬件专门设计为以这种方式工作,而且很多时候你不需要这样做任何特别的东西都可以从中受益。

现在,即使光栅化器有一个简单的固定功能工作要做,只要分层Z缓冲(Hi-Z)适用,它就会做一些非常聪明的事情。鉴于所有图元都是平面的,如果光栅化器可以保证片段着色器不会改变深度,它可以执行粗粒度(例如 1测试每个图块压缩深度缓冲区)深度测试使用最小/最大深度值并在着色/混合之前杀死多个片段。如果这个粗粒度测试通过,或者片段着色器写入自己的深度,则必须对每个片段进行着色,然后逐个 然后 针对深度缓冲区进行测试。现在,在您的情况下,片段着色器非常简单,因此不必要地遮蔽片段的费用将不会像通常那样多,并且混合也不是仅限深度传递的因素。

然而,必须对完全遮挡的基元进行深度测试的每个片段是Hi-Z可以避免的浪费时间。深度渲染的许多可测量的费用实际上是由绘制调用本身(状态验证,命令序列化等)引起的前端CPU开销。假设您的深度通过是有效批处理的,您可以通过提高深度测试效率来挤出更多性能。只是不要期望看到性能的巨大提升,上面描述的原因有很多,为什么Hi-Z更适合更传统的渲染。

顺便说一下,如果您想要了解我刚刚解释的大部分内容的直观摘要,请查看here


回到原来的问题......

最后,在构建阴影贴图期间正确利用分层Z缓冲不会产生巨大的性能提升,但它可以通过减少数量来增加收益。比较深度所需的算术指令。它主要取决于您更新阴影贴图的频率。一方面,如果你只做一次(静态)硬件填充阴影贴图的效率并不重要。另一方面,如果你必须每帧每帧渲染6个独立的阴影贴图,那么如果你可以减少绘制每个阴影贴图所花费的时间,那么性能将会有明显的改善。

这里没有考虑的房间里的大象是从一开始就从阴影地图中获取深度所需的时间(比你的比较时间多得多)。您可以根据需要加快阴影贴图的构建和比较,但是一些最大的好处来自于改善 重建 (采样)性能。

例如,抗锯齿VSM阴影可以使用传统的纹理过滤来完成,而不是您必须为其他技术执行的多个卷积样本和比较。这使得VSM的抗锯齿重建更加高效。因为VSM基于方差,所以它不需要存储透视深度......如果需要,可以使用线性距离,这对于此算法没有任何影响。即使构造(存储d和d 2 )更复杂,如果你需要抗锯齿,它可以更有效。

显然,没有一个尺寸适合所有人,你在阴影贴图中存储的内容在很大程度上取决于你的算法。

答案 1 :(得分:0)

实际上使用平方值会减少计算量。要确定矢量的长度,请执行sqrt(r·r)。如果比较两个向量的长度,这将是sqrt(r_0·r_0) > sqrt(r_1·r_1),但sqrt是严格单调的函数,因此r_0·r_0 > r_1·r_1即比较平方值同样有效,但它保存了正方形的计算根。

答案 2 :(得分:0)

关于距离平方与实际深度,它只取决于您的经验要求:如果我使用的是涉及平方根的任何东西,我更喜欢使用值的平方,因为平方根的计算量很大,而方块很便宜。另一方面,如果我没有涉及平方根的数学,那么我使用直线深度值。我会尝试解释一下:

在渲染场景之前:在预处理步骤中渲染它,相机位于灯光的位置,以从灯光的POV生成场景。从该位置可见的所有像素都不能处于阴影中,因此通过消除,所有其他像素必须处于阴影中。

如果我们可以以某种方式标记光所到达的所有像素,那将很容易,但这可能是繁琐且占用大量内存。

方法1 :(深度检查)

因此,我们将每个照明像素的距离存储在深度缓冲区中的光线中。渲染场景时,我们计算任何渲染像素到光源位置的距离。如果该距离等于该像素位置处的存储深度,则我们知道从光中可以看到相同的像素,因此被照亮。如果距离较高,我们知道这个像素在光的POV中是不可见的,并且处于阴影中。

方法2 :(阴影贴图)

现在,根据实现细节,您可以使用浮点存储阴影贴图的像素数据,或者将颜色贴图(reference 1)打包成整数,并使用类似链接的GPUGems中的算法但是,对于正常的深度测试阴影贴图,人们可以通过简单的距离(reference 2)离开。

这一切归结为你想要阴影映射的详细程度,以及你愿意接受多少计算:对于实时渲染(游戏,简单的cad渲染等),花在细节上的时间就越少和更多的东西更好,因此我们使用像平方值而不是平方根的技巧(维基百科上有一个很好的复杂基本文本顺序(我知道,通常不会将其用作源)here )。

我试图尽量保持这个简短,所以可能错过了一些东西,让我知道你是否有更多信息,或者我的poist没有意义,我会更新更详细/澄清:)