在图形学渲染中,由于采样频率不足会导致信号失真的问题。其中有两类问题比较常见:
- 由于纹理尺寸过小而导致的失真问题
- 由于纹理尺寸过大而导致的失真问题
上面的过大和过小都是和我们的视口相比较而言的。也就是最终我们绘制到屏幕上或者缓冲区对应的大小。
这里介绍的是应用解决上述第一种:由于纹理尺寸过小(绘制的分辨率而言)而导致的锯齿问题。第二种问题可以参照图形学抗锯齿:多重采样(二)
纹理尺寸过小产生锯齿的原因
当纹理尺寸过小,即相较而言绘制的分辨率较大。纹理上某个像素点对应到绘制目标上将覆盖多个像素点。因此,在绘制过程中,我们将绘制目标上这些区域的像素点映射到纹理上对应的位置进行采样得到的像素值将是一样的。这也是产生锯齿的原因。也就是说这时候,咱们提高传统意义上的采样频率(目标像素值)是无法解决这个失真问题。这个失真是由于采样源信号已经是失真信号导致的。此时,为了使绘制目标平滑过渡,我们可以使用插值的方法
插值法
下面进行一个实验,来看一下插值法在解决因为纹理本身过小导致的锯齿问题的效果。
如上所示,我们先把原图()进行尺寸压缩(压缩成),使其信号失真。得到的图作为我们的实验输入图。并绘制回512*512的尺寸并显示,如下图:
上面是我压缩到的压缩图。接着,我们应用双线性插值对结果图进行平滑,并重新绘制回的尺寸。代码如下:
uniform sampler2D inputTexture0;
uniform vec2 material_size;
varying vec2 v_texCoord;
void main()
{
vec2 st = v_texCoord * material_size;
vec2 f_co = fract(st);
vec2 i_co = (st - f_co);
vec2 i_co00 = i_co / material_size;
vec2 i_co10 = (i_co + vec2(1.0, 0.0)) / material_size;
vec2 i_co01 = (i_co + vec2(0.0, 1.0)) / material_size;
vec2 i_co11 = (i_co + vec2(1.0, 1.0)) / material_size;
vec3 x_color1 = mix(texture2D(inputTexture0, i_co00).rgb, texture2D(inputTexture0, i_co01).rgb, f_co.y);
vec3 x_color2 = mix(texture2D(inputTexture0, i_co10).rgb, texture2D(inputTexture0, i_co11).rgb, f_co.y);
vec3 res_color = mix(x_color1, x_color2, f_co.x);
gl_FragColor = vec4(mix(
mix(texture2D(inputTexture0, i_co00).rgb, texture2D(inputTexture0, i_co01).rgb, f_co.y),
mix(texture2D(inputTexture0, i_co10).rgb, texture2D(inputTexture0, i_co11).rgb, f_co.y),
f_co.x), 1.0);
}
其中,material_size为vec2(25, 25),表示被采样纹理的分辨率。
平滑过后的图如下:
相较于上面的图,这张图更加平滑,锯齿问题没那么突出了。
总结:
插值法可以优化由于纹理尺寸过小而产生的锯齿问题