opengl texture sampling

for a while i’ve noticed a disparity between my subpixel sampling and opengls. i think i’ve decided that i’m doing nothing wrong.

today i think i realized that opengl is sampling pixels from the center rather than the edge. for instance for an identity texture matrix, 0.0 and 1.0 will sample the center of the edge pixels rather than the very edge.

can someone confirm this for me. and assuming this is the case, is there any state i can set so that pixels will be sampled at the corner?

sincerely,

michael

Yes, i can confirm, that this is the default behaviour. AFAIK it is defined to act like this in the OpenGL spec.

D3D samples from the corner, if i’m not mistaken, and that seems to be a problem in some situations.

Anyway, i don´t think there is an extension to change this behaviour in OpenGL. If you need to sample from the corner, you need to change your texture-coordinates, by subtracting (0.5 / texture-width|height).

Hope that helps.
Jan.

Originally posted by Jan:
[b]Yes, i can confirm, that this is the default behaviour. AFAIK it is defined to act like this in the OpenGL spec.

D3D samples from the corner, if i’m not mistaken, and that seems to be a problem in some situations.

Anyway, i don´t think there is an extension to change this behaviour in OpenGL. If you need to sample from the corner, you need to change your texture-coordinates, by subtracting (0.5 / texture-width|height).

Hope that helps.
Jan.[/b]
thanks for confirming my suspicions. i’m still hoping there is a state variable to change this. if anyone knows of such please chime int.

i would think if directx samples from corners there should be someway to augment this behavior in hardware.

its really going to be a headache for me to manage this on the cpu.

sincerely,

michael

use the texture matrix - easy.

Originally posted by knackered:
use the texture matrix - easy.
a pipeline optimization paper someone here suggested i read said that using the texture matrix significantly cuts into performance. that is apparently the hardware is traditionally optimized for an identity texture matrix.

For texel edge sampling, use texture borders.
very simple, instead of a 44 rgb array, define a 66 one in tables :
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 4, 4, 1, GL_RGB, GL_UNSIGNED_BYTE, tables[i]);
Then clamp like this :
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);

Hope it helped.

Originally posted by ZbuffeR:
[b]For texel edge sampling, use texture borders.
very simple, instead of a 44 rgb array, define a 66 one in tables :
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB8, 4, 4, 1, GL_RGB, GL_UNSIGNED_BYTE, tables[i]);
Then clamp like this :
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP);

Hope it helped.[/b]
sorry, but i just don’t see how using a bordered texture would force sampling on the corners?

even if somehow it did, it shouldn’t be necessary.

can anyone else confirm this?

If your problem is edge texel sampling (you haven’t actually said what the problem is), there is state to control that. You can choose from several edge behaviors, read the spec for the core and extensions like ARB_texture_border_clamp and SGIS_texture_edge_clamp.

You guys always make me second guess my own code… which is good, I think. :wink:
I believe the center sampling is the only reasonable way to do it without causing problems on the very edges.
But what about rectangular textures? They do sample from the edges, right? Thats why CLAMP_TO_EDGE does not work with GL_TEXTURE_RECTANGLE_ARB?
This would suggest that hardware supporting GL_TEXTURE_RECTANGLE_ARB can do both sampling methods.

Read the spec. GL_CLAMP, GL_CLAMP_TO_EDGE, and CLAMP_TO_BORDER are supported. Texture borders are not supported though, so you only get the constant border color.

Originally posted by arekkusu:
Read the spec. GL_CLAMP, GL_CLAMP_TO_EDGE, and CLAMP_TO_BORDER are supported. Texture borders are not supported though, so you only get the constant border color.
these only effect behavior on the border texels as i understand them.

i thought i made it clear what the issue was… Jan seemed to pick it up easy at least.

the problem is simple. if you give opengl a texture coordinate of (0.0,1.0) you don’t get the very corner of the map, but rather you get the center of the pixel in the corner of the map. same goes for all other pixels. that is to say that opengl places whole number edges in the center of pixels and not in their corners.

if you are not worried about subpixel sampling, or use this method yourself, you might never notice the difference. but personally i’ve never used this method, and never seen any third party code that uses this sampling method when generating textures.

it is consistant with the opengl rasterizer… but it is at least awkward enough under enough cases, that opengl should provide a state to change this behavior internally.

from what i believe Jan said, directx does not use opengl’s sampling method by default. to me this would either imply that this state can be changed in hardware, and opengl should provide a hook (and probably does) … or that directx does not use an identity texture matrix by default (which is said to be unoptimized). or maybe Jan is wrong, or i read them wrong.

sincerely,

michael

Originally posted by michagl:
[b]i thought i made it clear what the issue was… Jan seemed to pick it up easy at least.

the problem is simple. if you give opengl a texture coordinate of (0.0,1.0) you don’t get the very corner of the map, but rather you get the center of the pixel in the corner of the map.[/b]
It never depends a single vertex’s texture coord, so your example is meaningless. It depends on the interpolated texcoord of the fragment, and that in turn depends on the texture coords that lie on the surface edges and their area, aka magnification or minification “ratio”.

same goes for all other pixels. that is to say that opengl places whole number edges in the center of pixels and not in their corners.
It doesn’t.
OpenGL resolves interpolants at pixel centers. (Viewport) pixel edges lie on whole number positions, pixel centers are 0.5 off. Texcoords are exactly the same.

You might think this doesn’t match, but because of the interpolation stuff it actually fits perfectly.
An exact hit on the bottom left texel of a n*m texture map happens for any fragment where the interpolated texcoord is (1/2n;1/2m).

Or to put it into practice, if you draw a 2x2 pixel quad and want an exact mapping of a 2x2 texture, you do this:

it is consistant with the opengl rasterizer… but it is at least awkward enough under enough cases, that opengl should provide a state to change this behavior internally.
It is never awkward. It guarantees that surface detail doesn’t drift as a result of varying magnification, it guarantees that texturing works independent of viewport sizes and is the only way it can sensibly be specified.

Whatever you’re trying to do, just don’t. You’re only going to break things. The OpenGL way works just fine.

from what i believe Jan said, directx does not use opengl’s sampling method by default.
Direct3D v5 did what you suggested, and because everyone agreed that it sucked, Direct3D was respecced to follow OpenGL’s method.

Go look for an “Alternate pixel center” option hidden somewhere in even current ATI and NVIDIA drivers’ control panels. That’s what’s left of it.

perhaps this is of interest http://www.mindcontrol.org/~hplus/graphics/opengl-pixel-perfect.html

i don’t think you understand zack.

what seems to happen. is if you have for the sake of argument a 4 pixel one dimensional texture (0,1,2,3) and linear filtering is enabled.

if you give opengl the coordinates 0.0 you get the center of pixel 0… if you give it 1.0 you get the center of pixel 3.

so it reasons to follow that if give 0.5 you get the edge between pixel 1 and pixel 2.

so 0.5 is identical, but 0.0, and 1.0 do not hit edges, but hit centers.

now if you do 0.25 and 0.75 you get something not on an edge or center at all.

now i could be wrong, but this seems to be what opengl is doing.


now if i had my way. 0.0 would be the first edge, and 1.0 would be the last edge, and 0.25, 0.5, and 0.75 would all fall on the first edges of pixels (1,2,3) respectively.

this sort of mapping is more natural, and i believe what most people expect.

you won’t notice this at all until you are trying to synchronize subpixel sampling with opengl filtering.


now i might have a bug somewhere, but i don’t think so. this is what appears to be happening.

Originally posted by michagl:
[b]i don’t think you understand zack.

what seems to happen. is if you have for the sake of argument a 4 pixel one dimensional texture (0,1,2,3) and linear filtering is enabled.

if you give opengl the coordinates 0.0 you get the center of pixel 0… if you give it 1.0 you get the center of pixel 3.[/b]
And you still don’t understand interpolation.
I already said it: you don’t get anything if you don’t specify at least a line with two vertices. And that’s the root of your misunderstanding.

If, given your 1D texture, you specify texcoords 0 and 0.25 for a line, you’ll hit somewhere on the first texel. “Somewhere” depends on the viewport size of the line. If the line is exactly one pixel long, you’ll get exactly the color of the first texel, and in this case it won’t even matter if you do linear filtering or point sampling.

Just try the code given above. You can easily modify it to use a 4x4 texture or your 4x1 texture by changing the glViewport parameters appropriately. It just won’t matter. As long as the texture has the same dimensions as the viewport, you’ll get an exact 1:1 mapping from texel to pixel.

now if i had my way. 0.0 would be the first edge, and 1.0 would be the last edge, and 0.25, 0.5, and 0.75 would all fall on the first edges of pixels (1,2,3) respectively.
They do. Try drawing a quad where all vertices have the same texcoords, and see for yourself.

Originally posted by zeckensack:
They do. Try drawing a quad where all vertices have the same texcoords, and see for yourself.
well if you are right, you are in direct opposition to Jan’s original post which references the specifications.

i will check for bugs in my code again as soon as my computer finishes a task… probably tomorrow.

basicly i’m building a height field… the colour map is lower resolution the displacement map. my displacements are off by about a half of a pixel in the y axis, and maybe in the x axis (i haven’t really payed attention to the x axis).

i see something that might make a difference. i will check it asap and get back.

i made a small change which seems to help my situation. not sure if it is perfect, synchronized with opengl, or just counter acting opengl.

sampling a texture in memory is actually pretty tricky.

can someone post some tried and true buffer sampling c pseudo-code for image widthxheightxchannels byte encoded.

also just curious? can opengl upload interleaved and uninterleaved channels? i figure ‘PixelTransfer’ would be the operative command. what is more common and useful? storing images by the channel or by the element?

and i’m still interested in just how opengl samples textures. there appears to be quite conflicting ideas on this matter within this thread.

sincerely,

michael

oops… no that change i made causes a fundamental ‘bug’. i was sure i had tried that before.

i’m not going to give up till i get that straight.

later i think i will try using the texture matrix to see if it can straighten out the situation.

i really don’t think the texture matrix is a good fix though. is the texture matrix automaticly available in shaders lilke i believe the modelview and inverse modelview are supposed to be?

in GLSL the texture matrix is available with
gl_TextureMatrix[i], where i is the texture unit.

and i’m still interested in just how opengl samples textures. there appears to be quite conflicting ideas on this matter within this thread.

…you could always read the spec.

AFAIK texels are sampled from the center, not the edge.

Originally posted by Aeluned:
[b]in GLSL the texture matrix is available with
gl_TextureMatrix[i], where i is the texture unit.

[quote]

and i’m still interested in just how opengl samples textures. there appears to be quite conflicting ideas on this matter within this thread.

…you could always read the spec.

AFAIK texels are sampled from the center, not the edge.[/b][/QUOTE]i will be away for a little while i’m sorry to say.

yes, i think i may’ve confused some people at some point when mixing the terms ‘texels’ and ‘pixels’ up. later i realized that this might be a way to diffrentiate between texture pixels and screen space pixels.

finally i don’t understand ‘gl_TextureMatrix[i]’.

is that accessing a single element of the texture matrix?

for cg for instance would mul(gl_TextureMatrix,texcoords) work?

i understand that the modelview and inverse modelview are automaticly accessible as constants. that is they are always up to date and do not use up ‘constant’ memory? assuming this is correct, is the texture matrix the same way. and what sort of matrix is the texture matrix? 4x4 i figure. is there anyway to use a 2 dimensional texture matrix to save cycles?

as for reading core opengl specs… i think i might try to start with opengl2.0.