RE: bilinear filtering from sample point (not center of pixel)?

"Pat Brown \(OpenGL\)" <[email protected]> Tue, 16 May 2006 19:09:25 -0800
Newsgroups gmane.games.devel.opengl
Organization Fat City Network Services, San Diego, California
Message-ID <[email protected]>
Matt,

Your shader isn't doing anything close to what you think it's doing.

You are adding +/- 0.5 to the (s,t) texture coordinates.  

For TEXTURE_2D, this does not move your sample point by half a pixel.
It moves it by half a TEXTURE.  

For 2D textures, texture coordinates of (0,0) means the lower left
corner of the texture; (1,1) means the upper right corner of the
texture.  (0.5, 0.5) is smack dab in the middle of your texture.

Let's say you have a pixel whose texture coordinate is at (0,0).  You
will take four samples at (+/-0.5, +/-0.5).  If you are using the REPEAT
wrap modes, all four of these samples will end up in exactly the same
location -- half way across your texture from where it "should" be.  

If your pixel and texture coordinates are 1:1 (say a 64x64 texture with
a 64x64-pixel square), your sample points are all smack dab on the
center of a texel, so LINEAR filtering will be weighted 100% on the
texel you do end up picking.  So it looks like you're point sampling
(you're not).

If your texture is 64x64, try adding +/- 1/128 instead.  I think that
will work much better for you.

FWIW, many OGL vendors support an extension called
ARB_texture_rectangle, where textures are addressed in (0,0) - (w,h)
coordinates instead of (0,0) - (1,1).  Rectangle textures have a bunch
of limitations (e.g, no mipmapping, not all wrap modes supported,
etc...), however.  Using rectangle textures, adding +/-0.5 would do what
you wanted.

Hope this helps.

Pat

-----Original Message-----
Matt Franklin
Sent: Tuesday, May 16, 2006 6:19 PM
To: Multiple recipients of list OPENGL-GAMEDEV-L

This is a rather long post.  First, my question in brief: is there a way
to get GLSL's texture sample to return an interpolated value from the
specified texture coordinate, and NOT from the center of the destination
pixel?



I'm attempting to port a simple box filter from DirextX+HLSL to
OpenGL+GLSL.  In the HLSL version, I sample four points: plus or minus
.5 from the center of the texel, along x and y.  By sampling at the
corners of the texel, this allows me to exploit bilinear filtering to
essentially get four samples per sample.  I then average the four points
together, and bingo-- box filter suitable for blurring.  (I've enclosed
the shader at the end of this e-mail, in case that's clearer.)

The same technique is not working for me in GLSL.  I'm using
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN/MAG_FILTER, GL_LINEAR) to
enable bilinear filtering, but it appears I need something further.

Here's the key bit of documentation:

"GL_LINEAR: Returns the weighted average of the four texture elements
that are closest to the center of the pixel being textured."

Well, there's the issue.  My source and destination line up perfectly
(I'm not magnifying or minifying, and they aren't offset).  Since the
center of the pixel being textured lines up perfectly with the texture,
it doesn't sample four texture elements-- it just samples one.  When I
attempt to offset the sample point by .5, .5 (which should put me at the
corner of the texel), it simply point samples the next texel over!

Is there a way to prevent OpenGL/GLSL from "snapping" to the center of
the texel, and instead get it to interpolate appropriately?  Or do I
need to manually implement the interpolation within my shader?  It's not
that writing the full box filter with the 9 samples is difficult, but if
there's a more optimized method that's supported by OpenGL, I'd prefer
to use that.


GLSL SHADER:

The behavior of this shader is to point sample the current texel, the
texel next to it in the positive x direction, the texel next to it in
the positive y direction, and the texel diagonal from it in the positive
x, y.

uniform sampler2D tex0;
void main() {
	const float2 cg_vPixelOffset[4] =
	{
		{-0.5,  -0.5 }, { 0.5,  -0.5 },
		{-0.5,   0.5 }, { 0.5,   0.5 },
	};
	float4 vColor = 0;
	for (int i = 0; i < 4; i++)
	{
		vColor += texture2D(tex0,
gl_TexCoord[0].st+cg_vPixelOffset[i]);
	}
	gl_FragColor = vColor * (1.0f / 4.0f);
}

----- 
FAQ and OpenGL Resources at:
  http://www.geocities.com/SiliconValley/Hills/9956/OpenGL

-- 
Author: Matt Franklin
  INET: [email protected]

Fat City Hosting, San Diego, California -- http://www.fatcity.com
---------------------------------------------------------------------
To REMOVE yourself from this mailing list, send an E-Mail message
to: [email protected] (note EXACT spelling of 'ListGuru') and in
the message BODY, include a line containing: UNSUB OPENGL-GAMEDEV-L
(or the name of mailing list you want to be removed from).  You may
also send the HELP command for other information (like subscribing).
-----------------------------------------------------------------------------------
This email message is for the sole use of the intended recipient(s) and may contain
confidential information.  Any unauthorized review, use, disclosure or distribution
is prohibited.  If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.
-----------------------------------------------------------------------------------

----- 
FAQ and OpenGL Resources at:
  http://www.geocities.com/SiliconValley/Hills/9956/OpenGL

-- 
Author: Pat Brown \(OpenGL\)
  INET: [email protected]

Fat City Hosting, San Diego, California -- http://www.fatcity.com
---------------------------------------------------------------------
To REMOVE yourself from this mailing list, send an E-Mail message
to: [email protected] (note EXACT spelling of 'ListGuru') and in
the message BODY, include a line containing: UNSUB OPENGL-GAMEDEV-L
(or the name of mailing list you want to be removed from).  You may
also send the HELP command for other information (like subscribing).