简单来说,textureGrad()是什么?

18

我阅读了Khronos维基上的内容,但我不太明白它在说什么。textureGrad到底是做什么的?

我认为它会采样多个mipmap级别,并使用给定的显式导数向量计算一些颜色混合,但我不确定。

1个回答

35
当你采样纹理时,你需要具体的纹理坐标来采样纹理数据。为了简单起见,我假设一个2D纹理,因此纹理坐标是一个二维向量。(其他维度的解释类似)。
如果你想要贴图一个三角形,通常有两种策略来获取纹理坐标:
1. 纹理坐标是模型的一部分。每个顶点都包含2D纹理坐标作为顶点属性。在光栅化期间,这些纹理坐标会在原始数据中插值。
2. 你可以指定数学映射。例如,你可以定义一些将3D对象坐标映射到某些2D纹理坐标的函数。你可以定义一些投影,并将纹理投影到表面上,就像真实的投影仪将图像投影到一些现实世界的物体上一样。
在任一情况下,通常生成的每个片段都有不同的纹理坐标,因此屏幕上绘制的每个像素都会获得纹理的不同部分。
关键点在于:每个片段都有2D像素坐标(x,y)以及2D纹理坐标(s,t),因此我们可以基本上将这种关系解释为数学函数:
(s,t) = T(x,y)

由于这是二维像素位置矢量{{(x,y)}}的向量函数,我们还可以沿着{{x}}方向(向右)和{{y}}方向(向上)构建偏导数,它们告诉我们纹理坐标沿这些方向的变化率。在textureGrad中的dTdxdTdy就是这个含义。
那么GPU需要这个做什么呢?当你想要实际过滤纹理(而不是简单的点采样)时,你需要知道纹理空间中的像素占用区域。每个片元都代表屏幕上一个像素的区域,并且你将使用来自纹理的单个颜色值来表示整个像素(除了多重采样)。像素占用区域现在代表像素在纹理空间中的实际区域。我们可以通过对4个像素角落的纹理坐标进行插值来计算它。结果的纹理坐标会形成纹理空间中的梯形。
当你缩小纹理时,几个纹素被映射到同一个像素上(因此像素占用区域在纹理空间中很大)。当你放大它时,每个像素只代表相应纹素的一部分(因此占用区域相当小)。
纹理占用区域告诉你:
  • 如果纹理被缩小或放大(GL对每种情况都有不同的滤波器设置)
  • 每个像素将映射到多少个纹素,因此哪个mipmap级别更合适
  • 像素占用区域中有多少各向异性。屏幕上的每个像素和纹理空间中的每个纹素基本上都是一个正方形,但是像素占用区域可能会明显偏离这一点,并且可以比宽或高更高(特别是在高透视畸变的情况下)。经典的双线性或三线性纹理过滤器始终使用正方形过滤器占用区域,但各向异性纹理过滤器将使用此信息来实际生成更接近实际像素占用区域的过滤器占用区域(以避免混合不应真正属于像素的纹素数据)。

我们将使用片段中心处的偏导数作为像素占用区域的近似值,而不是计算所有像素角落处的纹理坐标。

以下图表显示了几何关系:

diagram of pixel footprint in texture space

这代表了纹理空间中四个相邻像素(2x2)的足迹,所以均匀网格是texel,而4个梯形代表4个像素足迹。现在计算实际导数意味着我们有一个更多或少明确的公式T(x,y),如上所述。GPU通常使用另一种近似方法:只需查看每个2x2像素块中相邻片段的实际纹理坐标(无论如何都将被计算),并通过有限差分来近似足迹 - 只需从彼此相邻的片段中减去实际纹理坐标。结果显示为图中的虚线平行四边形。
在硬件中,这是这样实现的:总是并行着色相邻的2x2像素矩形,在同一个warp / wavefront / SIMD组中。 GLSL导数函数,如dFdxdFdy只需通过减去相邻片段的实际值即可工作。而标准的texture函数只是在纹理坐标参数上内部使用此机制。 textureGrad函数绕过这一点,并允许您指定自己的值,这意味着您控制GPU在执行实际过滤/ mipmap级别选择时所假定的像素足迹。

如果采样器启用了各向异性过滤(并且配置文件支持它),textureGrad能否在内部执行各向异性过滤? - Tomilov Anatoliy
1
可以的(假设您的实现支持各向异性过滤,并已启用它)。 - derhass

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接