我偶尔看到着色器代码中出现了ddx
和ddy
glsl函数以及hlsl等效项。我目前正在使用它们来进行不切线或不切线的凹凸贴图,但是我基本上是复制粘贴了代码。我不了解这些功能的实际含义,作用以及何时使用它们。
所以问题:
- 屏幕空间派生函数是什么?
- 这些功能做什么?输入值和输出值
- 它们最常用于什么效果?
- 什么样的效果需要您关注这些功能?
我偶尔看到着色器代码中出现了ddx
和ddy
glsl函数以及hlsl等效项。我目前正在使用它们来进行不切线或不切线的凹凸贴图,但是我基本上是复制粘贴了代码。我不了解这些功能的实际含义,作用以及何时使用它们。
所以问题:
Answers:
首先,它有助于了解GPU总是一次评估2x2像素块上的片段/像素着色器。(即使最终只需要绘制其中一些像素,而其他像素则位于多边形之外或被遮挡-不需要的片段也会被屏蔽掉,而不是最后写入)。
v
着色器中变量(或表达式)的屏幕空间导数是v
从2x2像素四边形的一侧到另一侧(在代码中的该点)的值的差。即。ddx
是v
右侧像素中的值减去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可能会默认使用粗导数)
v
此处),并且由于它是2x2的四边形,因此两者之间没有像素。因此,如果我们阴影四边形的左上角片段,那里的v = 1,而在右上角片段v = 4,则ddx(v)= 3(说“ v随着我们移动而增加3左到右“)