推荐一个网页:Shader - Shadertoy BETA
在网页中测试发现了如下关系:
测试过程很简单,纹理图使用Linear,然后texture2D,限定pos位置,如果得出的颜色不是插值出来的颜色,则说明找对了。
大致关系如上图,由于纹理坐标是[0,1],乘上宽高之后,等于 分别为[0,width] 和 [0,height]
一张宽为width的图片,实际一行是width个像素,序号从0到width-1,而[0,width]有width+1个像素,所以,每个实际的像素偏移了0.5,即对应关系为:
texture2D((0.5*(i+1)/width,0.5*(j+1)/height)) == rgba[i][j]
如果是Nearest,就是floor(xy) + 0.5
如果是Linear,需要找四个邻近点,进行线性插值
由于非预乘的纹理,进行二次线性插值时,会有偏色的问题,通过模拟二次线性插值,可解决(仅供学习,实际操作还是尽可能对纹理进行预乘alpha的好)
vec4 premul(vec4 c){
return vec4(c.rgb * c.a,c.a);
}
vec4 nopremul(vec4 c){
if(c.a == .0)
return vec4(0,0,0,0);
return vec4(clamp(c.rgb / c.a,.0,1.0),c.a);
}
vec4 my_texture2D(sampler2D tex,vec2 size,vec2 pos){
vec2 ixy = (pos * size) - .5;
vec2 i_base = floor(ixy) + .5;
vec2 xy_base0 = i_base / size;
vec2 xy_base1 = vec2(i_base.x + 1.0,i_base.y) / size;
vec2 xy_base2 = vec2(i_base.x,i_base.y+1.0) / size;
vec2 xy_base3 = (i_base + 1.0) / size;
vec2 xy_fract = fract(ixy);
vec4 c_base0 = premul(texture2D(tex,xy_base0));
vec4 c_base1 = premul(texture2D(tex,xy_base1));
vec4 c_base2 = premul(texture2D(tex,xy_base2));
vec4 c_base3 = premul(texture2D(tex,xy_base3));
vec4 ret0 = mix(c_base0,c_base1,xy_fract.x);
vec4 ret1 = mix(c_base2,c_base3,xy_fract.x);
vec4 ret = mix(ret0,ret1,xy_fract.y);
return nopremul(ret);
return texture2D(tex,pos);
}
测试main函数如下:
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// Normalized pixel coordinates (from 0 to 1)
vec2 uv = fragCoord/iResolution.xy;
vec4 c = my_texture2D(iChannel1,iChannelResolution[1].xy,uv);
// Time varying pixel color
vec3 col = c.rgb;
if(c.a < 0.5)
c = vec4(1,0,0,1);
// Output to screen
fragColor = c;
}
对比未预乘的线性插值效果:
未预乘alpha的图片边缘效果明显偏白。