views:

987

answers:

3

i need to get the color at a particular coordinate from a texture. There are 2 ways i can do this, by getting and looking at the raw png data, or by sampling my generated opengl texture. Is it possible to sample an opengl texture to get the color (RGBA) at a given UV or XY coord? If so, how?

+2  A: 

The most efficient way I've found to do it is to access the texture data (you should have our PNG decoded to make into a texture anyway) and interpolate between the texels yourself. Assuming your texcoords are [0,1], multiply texwidth*u and texheight*v and then use that to find the position on the texture. If they're whole numbers, just use the pixel directly, otherwise use the int parts to find the bordering pixels and interpolate between them based on the fractional parts.

Here's some HLSL-like psuedocode for it. Should be fairly clear:

float3 sample(float2 coord, texture tex) {
    float x = tex.w * coord.x; // Get X coord in texture
    int ix = (int) x; // Get X coord as whole number
    float y = tex.h * coord.y;
    int iy = (int) y;

    float3 x1 = getTexel(ix, iy); // Get top-left pixel
    float3 x2 = getTexel(ix+1, iy); // Get top-right pixel
    float3 y1 = getTexel(ix, iy+1); // Get bottom-left pixel
    float3 y2 = getTexel(ix+1, iy+1); // Get bottom-right pixel

    float3 top = interpolate(x1, x2, frac(x)); // Interpolate between top two pixels based on the fractional part of the X coord
    float3 bottom = interpolate(y1, y2, frac(x)); // Interpolate between bottom two pixels

    return interpolate(top, bottom, frac(y)); // Interpolate between top and bottom based on fractional Y coord
}
Cody Brocious
+2  A: 

Off the top of my head, your options are

  1. Fetch the entire texture using glGetTexImage() and check the texel you're interested in.
  2. Draw the texel you're interested in (eg. by rendering a GL_POINTS primitive), then grab the pixel where you rendered it from the framebuffer by using glReadPixels.
  3. Keep a copy of the texture image handy and leave OpenGL out of it.

Options 1 and 2 are horribly inefficient (although you could speed 2 up somewhat by using pixel-buffer-objects and doing the copy asynchronously). So my favourite by FAR is option 3.

Edit: If you have the GL_APPLE_client_storage extension (ie. you're on a Mac or iPhone) then that's option 4 which is the winner by a long way.

Outside of option 2, you need a method for sampling based on the texcoords, though, which is the hard part -- this is described in my answer.
Cody Brocious
My understanding was that the poster was asking how to implement the 'getTexel' part of your example, not how to replicate the filtering (which depends on what kind of filtering he wants to replicate anyway).
I was sort of asking about the getTexel part, but, he's right that 1 and 2 are too slow, esp considering i'm working on a mobile device.Thanks :)
DavidG
Mobile device? Would that be an iPhone by any chance? See updated answer.
indeed it would Mike F, thanks for the tip... altho in this case it does turn out that the data can be pre processed as raw image data before the creation of the openGL texture.
DavidG
A: 

As others have suggested, reading back a texture from VRAM is horribly inefficient and should be avoided like the plague if you're even remotely interested in performance.

Two workable solutions as far as I know:

  1. Keep a copy of the pixeldata handy (wastes memory though)
  2. Do it using a shader
korona