Bilinear Interpolation

Started by
-1 comments, last by trzy 13 years, 1 month ago
Hi all,

I'm revisiting some code that has been bugging me for a long time. I need to do bilinear interpolation manually in my fragment shader and I use the following code:


/*
* Bilinear Filtering
*
* In order to get this working on ATI, the number of operations is
* reduced by putting everything into vec4's. uv_top holds the UV
* coordinates for the top two texels (.xy=left, .zw=right) and uv_bot
* is for the lower two.
*/

// Compute fractional blending factor, r, and lower left corner of texel 0
uv_bot.xy = gl_TexCoord[0].st-vec2(0.5,0.5); // move into the lower left blending texel
r = uv_bot.xy-floor(uv_bot.xy); // fractional part
uv_bot.xy = floor(uv_bot.xy); // integral part

// Compute texel coordinates
uv_bot.xy += vec2(0.5,0.5); // offset to center of pixel (shouldn't be needed but it fixes a lot of glitches, esp. on Nvidia)
uv_bot.zw = uv_bot.xy + vec2(1.0,0.0); // compute coordinates of the other three neighbors
uv_top = uv_bot + vec4(0.0,1.0,0.0,1.0);

// Compute the properly wrapped texel coordinates
uv_top = WrapTexelCoords(uv_top,vec4(fsSubTexture.xy,fsSubTexture.xy),vec4(fsSubTexture.zw,fsSubTexture.zw), vec4(fsTexParams.zw,fsTexParams.zw));
uv_bot = WrapTexelCoords(uv_bot,vec4(fsSubTexture.xy,fsSubTexture.xy),vec4(fsSubTexture.zw,fsSubTexture.zw), vec4(fsTexParams.zw,fsTexParams.zw));

// Fetch the texels and blend them
c[0]=texture2D(textureMap,uv_bot.xy); // bottom-left (base texel)
c[1]=texture2D(textureMap,uv_bot.zw); // bottom-right
c[2]=texture2D(textureMap,uv_top.xy); // top-left
c[3]=texture2D(textureMap,uv_top.zw); // top-right
fragColor = c[0]*(1.0-r.s)*(1.0-r.t) + c[1]*r.s*(1.0-r.t) + c[2]*(1.0-r.s)*r.t + c[3]*r.s*r.t;


The problem is, I can't really account for the "uv_bot.xy+=vec2(0.5,0.5);" statement. I have set my texture map to use GL_NEAREST sampling, which, if my understanding is correct, will sample a texel color even if the coordinate is at the bottom-left of the texel. Nevertheless, this offset into the center of the texel (note that it is normalized to [0,1] later by WrapTexelCoords()) is absolutely necessary, otherwise unwanted bleeding into adjacent texels occurs.

What the code above basically does is:

1. Locate the lower-left pixel of the four pixel set we will be interpolating. Subtracting 0.5,0.5 puts us somewhere in there.
2. The fractional part of this will be used in our weighting factors later on.
3. The integral part (floor) references the lower left pixel.
4. The positions of the adjacent three pixels can be readily computed.

Neglecting the floor() operation for the lower-left pixel does not solve the problem, by the way.

I'm hoping to find a better way to do this. Seems like it should be doable in a much simpler, more compact, and more optimal fashion...

Any ideas?

Thanks!
----Bart

This topic is closed to new replies.

Advertisement