什么是屏幕空间导数?何时使用它们?


12

我偶尔看到着色器代码中出现了ddxddyglsl函数以及hlsl等效项。我目前正在使用它们来进行不切线或不切线的凹凸贴图,但是我基本上是复制粘贴了代码。我不了解这些功能的实际含义,作用以及何时使用它们。

所以问题:

  1. 屏幕空间派生函数是什么?
  2. 这些功能做什么?输入值和输出值
  3. 它们最常用于什么效果?
  4. 什么样的效果需要您关注这些功能?

过去,我将这些用于纹理变形,其中变形可能会导致为某些片段选择了错误的Miplevel。通常是较低的Miplevel,因此您可以看到纹理在弯曲时非常明显地发生了明显的变化。取未变形的texcoords的导数,然后计算变形,然后对变形的texcoords和导数使用tex2Dgrad / SampleGrad / textureGrad可以防止这种情况的发生。
Maximus Minimus

@ LeComteduMerde-fou什么是纹理变形?一个快速的谷歌建议你的意思换行?
NeomerArcana '16

不,我的意思是扭曲,即通过随时间改变纹理坐标来扭曲纹理。
Maximus Minimus

请参阅此相关问题。我不认为这是完全重复的,因为链接的问题是询问更多有关这些函数如何工作/如何计算的信息,而不是更高层次的“这是什么,它有什么用?”。
DMGregory

您好,我对此非常感兴趣,目前我正在使用它们来进行不切线或不切线的凹凸贴图,但是我基本上是复制粘贴了代码。...我当时正在考虑将其用于... ...但是我不知道如何使用便宜的线性代数将这些屏幕空间导数转换为世界空间法线。也许我需要逆相机投影矩阵。
Prokop Hapala

Answers:


12

首先,它有助于了解GPU总是一次评估2x2像素块上的片段/像素着色器。(即使最终只需要绘制其中一些像素,而其他像素则位于多边形之外或被遮挡-不需要的片段也会被屏蔽掉,而不是最后写入)。

该图说明了栅格化三角形中的导数

v着色器中变量(或表达式)的屏幕空间导数是v从2x2像素四边形的一侧到另一侧(在代码中的该点)的值的差。即。ddxv右侧像素中的值减去v左侧像素中的值,ddy垂直像素也是如此。

这回答了“ v当我们在屏幕上水平(ddx)或垂直(ddy)移动时,增加或减少的速度有多快?” -即 用微积分的术语,它近似于变量的偏导数(近似值,因为它在每个片段上使用离散样本,而不是数学上评估函数的无穷小行为)

对于标量,我们也可以将其视为梯度矢量 ∇v = float2(ddx(v), ddy(v)),该梯度矢量指向屏幕空间方向,该方向以v最快的速度增长。

此类信息通常在内部用于选择适当的mipmap各向异性过滤内核以进行纹理查找。例如,如果我的相机看起来几乎与uv带纹理的地板平面的垂直方向平行,ddy(uv.y)则与ddx(uv.x)(相比)(由于垂直轴在屏幕上被缩短-一个像素跨越垂直方向会覆盖较长的纹理空间),因此它会很大。告诉纹理采样硬件,我需要各向异性过滤来使垂直纹理方向比水平方向更多地模糊,以避免出现假象。

对于大多数简单效果,您不需要使用这些导数,因为基本的2D纹理采样方法可以为您处理。但是正如Le Comte du Merde-fou在上面的评论中提到的那样,当您扭曲纹理查找时,您可能需要手动检索和/或调整要使用的屏幕空间派生工具,以帮助硬件选择适当的过滤(例如,通过tex2Dlod在HLSL中)

屏幕空间贴图就是这样一种情况,其中,如果您让系统天真地计算过滤级别,则单个2x2块可以覆盖所计算的纹理坐标中的较大跳跃不连续性,从而导致边缘模糊或混叠。本文详细介绍了此工件以及减轻该工件的方法

当您在过程纹理生成中使用噪声函数时,这些导数也可以派上用场。例如,如果您要将过程噪声转换为法线贴图,则ddx和ddy提供了一种简单的方法(近似)来计算噪声值在当前片段附近的变化方式以及倾斜的方式,因此您可以构造适当的法线。

渲染抗锯齿线或交叉点高光的技术也可以使用屏幕空间派生,以确保厚度/衰减一致且不依赖于几何形状或视角。

在《旅程》中有关沙子渲染的演讲中,发言者提到他们本可以使用这些派生函数来控制沙子在掠过的边缘上的发光程度……如果当时他们对此有所了解(相反,他们使用了mipmapping技巧,无论如何,它们都是由这类衍生工具提供动力的)

最后要注意的一点是:屏幕空间导数可以“粗” /低精度(表示一对导数由整个四边形共享)或“精细” /高精度(表示每个像素仅与其立即数进行比较)进行计算。相邻的四边形,可以在四边形上给出四个不同的导数对。粗略通常足够,但是如果您发现效果中可见2x2块,则可以将其切换为精细/高精度是一个很好的线索。;)

(在顶部的图中,我使用了精细导数的计算,但请注意,仅ddx / ddy可能会默认使用粗导数)


当您说这是2x2块的一侧到另一侧的像素之间的差异时,是像素值的差异还是texel位置的差异?如果是值的差异,那么是否将两者之间的纹理像素相加?
NeomerArcana '16

这是参数值的差异(v此处),并且由于它是2x2的四边形,因此两者之间没有像素。因此,如果我们阴影四边形的左上角片段,那里的v = 1,而在右上角片段v = 4,则ddx(v)= 3(说“ v随着我们移动而增加3左到右“)
DMGregory

我还是不太明白。如果我以一定角度观看,则2x2块可能不是由纹理中并排的像素组成。因此,值的差异是两个选定纹理像素之间的差异,还是两个已跳过的纹理像素之间的差异?
NeomerArcana '16

忘记纹理像素-它不是对纹理进行采样。它采用您传递给ddx或ddy的参数的字面值,并在评估相邻片段时将其与传递给ddx或ddy的值进行比较。如果该值恰好来自纹理样本,则可以,但是派生函数对纹理没有任何了解。他们只是减去数字。回到电脑后,我将尝试在此答案中添加图表。
DMGregory

哦,我想我现在明白了。取得图表会很棒,但我想我理解。这些似乎非常有用的功能。
NeomerArcana '16
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.