Coloring picking id out of render buffer?

I’m trying to figure out the ‘best’ way to get a color picking id (unsigned int) through the shader and to a render buffer that I can glReadPixels() from.

Ideally it would work for both mac 10.6 (opengl 2.1) and opengl es 2.0.

Right now I have something like the following.

Vertex shader has:

attribute unsigned int itemId;
flat varying unsigned int itemIdent;
void main() {

itemIdent = itemId;

The fragment shader seems like the tricky part, potentially I’d use unpackUnorm4x8() but it doesn’t seem available on my platform.
What I have currently is:

flat varying unsigned int itemIdent;

void main() {

vec4 convertedColorId = vec4(
(itemIdent >> 24u) & 0x0FFu,
(itemIdent >> 16u) & 0x0FFu,
(itemIdent >> 8u) & 0x0FFu,
(itemIdent >> 0u) & 0x0FFu);

gl_FragData[0] = convertedColorId / 255.0;

And finally my setup and read from buffer code:

// setup

glBindRenderbuffer(GL_RENDERBUFFER, _renderItemId);
glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8, width, height);

// reading
GLuint itemId;
glReadPixels(pt.x, pt.y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &itemId);

Is this really the best way? It seems convoluted in that I need to convert to and from a float vec4 to do the gl_FragData assignment.


That’s a perfectly valid way of doing it. I would avoid using integer data types in your shader if you are targeting GL 2.1 and GL ES 2.0, and send a vec4 into your vertex shader as the ID. You can just cast your GLuint ID as an unsigned byte vec4 vertex attribute. Also, I don’t think the “flat” interpolation keyword is supported in GL ES 2.0, so you’ll have to ensure that each vertex gets the same value the hard way. Be careful with anti-aliasing, too (users can override your settings through the driver).

This may not help, but if you don’t mind limiting yourself to 255 possible IDs, using the stencil buffer is extremely simple and completely avoids any floating point stuff. That’s assuming stencil buffers are still limited to 8-bits, last time I checked.