GL_LINEAR具体使用什么算法?
What algorithm does GL_LINEAR use exactly?
refpages 说 "Returns the weighted average of the four texture elements that are closest to the specified texture coordinates." 它们的权重究竟是多少?那么 3D 纹理呢,它是否仍然只使用 4 个纹素进行插值或更多?
在2D纹理中使用了4个样本,这意味着双线性插值所以3x 线性插值.权重是目标纹素与其 4 个邻居的归一化距离。
所以例如你想要
处的纹素
(s,t)=(0.21,0.32)
但是纹素附近的纹理有坐标:
(s0,t0)=(0.20,0.30)
(s0,t1)=(0.20,0.35)
(s1,t0)=(0.25,0.30)
(s1,t1)=(0.25,0.35)
权重是:
ws = (s-s0)/(s1-s0) = 0.2
wt = (t-t0)/(t1-t0) = 0.4
所以在 s
方向
线性插值文本元素
c0 = texture(s0,t0) + (texture(s1,t0)-texture(s0,t0))*ws
c1 = texture(s0,t1) + (texture(s1,t1)-texture(s0,t1))*ws
最后 t
方向:
c = c0 + (c1-c0)*wt
其中 texture(s,t)
returns 纹理颜色在 s,t
而坐标对应于精确的纹理并且 c
是最终的插值纹理颜色。
实际上,s,t
坐标乘以纹理分辨率 (xs,ys
),将它们转换为纹素单位。在那之后 s-s0
和 t-t0
已经归一化,所以不需要除以 s1-s0
和 t1-t0
因为它们等于一。所以:
s=s*xs; s0=floor(s); s1=s0+1; ws=s-s0;
t=t*ys; t0=floor(t); t1=t0+1; wt=t-t0;
c0 = texture(s0,t0) + (texture(s1,t0)-texture(s0,t0))*ws;
c1 = texture(s0,t1) + (texture(s1,t1)-texture(s0,t1))*ws;
c = c0 + (c1-c0)*wt;
我以前从未使用过3D 纹理,但在这种情况下它使用了 8 个文本元素,它被称为 三线性插值,即 2x 双线性插值 只需取 2 个最近的纹理并使用 双线性插值 计算每个纹理,然后根据基于u
以完全相同的方式坐标...所以
u=u*zs; u0=floor(u); u1=u0+1; wu=u-u0;
c = cu0 + (cu1-cu0)*wu;
其中 zs
是纹理的数量,cu0
是 双线性插值 在 u0
和 [=32] 处的纹理的结果=] 在 u1
。同样的原则也适用于 mipmaps...
所有坐标可能都偏移了 0.5 纹素,并且根据您的钳位设置,分辨率倍增可以用 xs-1
而不是 xs
来完成...
除了 Spektre 的回答中概述的双线性插值外,您还应该了解 GL_LINEAR 插值的 精度。许多 GPU(例如 Nvidia、AMD)使用定点算法进行插值,纹理中的 R、G、B、A 值之间只有约 255 个不同的值。
例如,这里是显示 GPU 如何进行插值的伪代码:
float interpolate_red(float red0, float red1, float f) {
int g = (int)(f*256)
return (red0*(256-g) + red1*g)/256;
}
如果您的纹理用于着色并包含 GL_UNSIGNED_BYTE 值,那么它可能适合您。但是,如果您的纹理是用于某些其他计算的查找 table 并且它包含 GL_UNSIGNED_SHORT 或 GL_FLOAT 值,那么这种精度损失对您来说可能是个问题。在这种情况下,您应该使用(浮点)或(双)精度计算的中间值使查找 table 更大。
refpages 说 "Returns the weighted average of the four texture elements that are closest to the specified texture coordinates." 它们的权重究竟是多少?那么 3D 纹理呢,它是否仍然只使用 4 个纹素进行插值或更多?
在2D纹理中使用了4个样本,这意味着双线性插值所以3x 线性插值.权重是目标纹素与其 4 个邻居的归一化距离。
所以例如你想要
处的纹素(s,t)=(0.21,0.32)
但是纹素附近的纹理有坐标:
(s0,t0)=(0.20,0.30)
(s0,t1)=(0.20,0.35)
(s1,t0)=(0.25,0.30)
(s1,t1)=(0.25,0.35)
权重是:
ws = (s-s0)/(s1-s0) = 0.2
wt = (t-t0)/(t1-t0) = 0.4
所以在 s
方向
c0 = texture(s0,t0) + (texture(s1,t0)-texture(s0,t0))*ws
c1 = texture(s0,t1) + (texture(s1,t1)-texture(s0,t1))*ws
最后 t
方向:
c = c0 + (c1-c0)*wt
其中 texture(s,t)
returns 纹理颜色在 s,t
而坐标对应于精确的纹理并且 c
是最终的插值纹理颜色。
实际上,s,t
坐标乘以纹理分辨率 (xs,ys
),将它们转换为纹素单位。在那之后 s-s0
和 t-t0
已经归一化,所以不需要除以 s1-s0
和 t1-t0
因为它们等于一。所以:
s=s*xs; s0=floor(s); s1=s0+1; ws=s-s0;
t=t*ys; t0=floor(t); t1=t0+1; wt=t-t0;
c0 = texture(s0,t0) + (texture(s1,t0)-texture(s0,t0))*ws;
c1 = texture(s0,t1) + (texture(s1,t1)-texture(s0,t1))*ws;
c = c0 + (c1-c0)*wt;
我以前从未使用过3D 纹理,但在这种情况下它使用了 8 个文本元素,它被称为 三线性插值,即 2x 双线性插值 只需取 2 个最近的纹理并使用 双线性插值 计算每个纹理,然后根据基于u
以完全相同的方式坐标...所以
u=u*zs; u0=floor(u); u1=u0+1; wu=u-u0;
c = cu0 + (cu1-cu0)*wu;
其中 zs
是纹理的数量,cu0
是 双线性插值 在 u0
和 [=32] 处的纹理的结果=] 在 u1
。同样的原则也适用于 mipmaps...
所有坐标可能都偏移了 0.5 纹素,并且根据您的钳位设置,分辨率倍增可以用 xs-1
而不是 xs
来完成...
除了 Spektre 的回答中概述的双线性插值外,您还应该了解 GL_LINEAR 插值的 精度。许多 GPU(例如 Nvidia、AMD)使用定点算法进行插值,纹理中的 R、G、B、A 值之间只有约 255 个不同的值。
例如,这里是显示 GPU 如何进行插值的伪代码:
float interpolate_red(float red0, float red1, float f) {
int g = (int)(f*256)
return (red0*(256-g) + red1*g)/256;
}
如果您的纹理用于着色并包含 GL_UNSIGNED_BYTE 值,那么它可能适合您。但是,如果您的纹理是用于某些其他计算的查找 table 并且它包含 GL_UNSIGNED_SHORT 或 GL_FLOAT 值,那么这种精度损失对您来说可能是个问题。在这种情况下,您应该使用(浮点)或(双)精度计算的中间值使查找 table 更大。