Picking with shaders


I’ve been trying to optimize various parts of an application for a couple of weeks now. One of the things I’ve been focusing on was picking. The way this was done was by rendering all geometry in a second pass, only drawing an ID for each primitive. Both this pass and the color pass was using the fixed function pipeline.

I was hoping that by using shaders, I could draw both color and ID in one pass. Said and done, things got slower. Right now, I only have one shader which I only bind once, and this shader has one uniform (a vec3 for the ID) which I only look up the location for once. I set this uniform to a different value for every primitive (sphere, cone, cylinder etc). To me, it seems like this is where the overhead would come from. Is it possible that the pipeline is being flushed in order to not overwrite the uniform while being used by the previous render call?

The shaders doesn’t do anything particularly fancy, so it shouldn’t be that either. Since everything was set up to use the fixed function pipeline, I’m using those attributes (such as gl_Color) as much as possible in the shaders as well. Which btw seems to cause an entirely different problem, namely that several primitives seem to get rendered without gl_Color etc being changed in between them… Less concerning for now, but perhaps you can explain this behaviour as well?

Thank you for your time!

Let me guess, your performance is more than 1000fps? In that case, drop your measurements until you have a really complex scene and FPS < 100fps.

Next, you don’t need the full screen for picking. Just one pixel (where the mouse cursor is) is enough.

Paste your shader code & exact numbers for more help.

I get about 90 fps on one computer when using the old picking, 80 when I’m using the shader picking. I’m not sure about what hardware it has, but I’ve been told that it has a “good graphics card.”

Here’s the shader code:

varying vec3 N;
varying vec3 v;

void main(void)  
   v = vec3(gl_ModelViewMatrix * gl_Vertex);       
   N = normalize(gl_NormalMatrix * gl_Normal);
   gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
   gl_TexCoord[0] = gl_MultiTexCoord0;

uniform vec3 pick_id;

varying vec3 N;
varying vec3 v;

void main (void)  
   vec3 L = normalize(gl_LightSource[0].position.xyz - v);   
   vec3 E = normalize(-v);
   vec3 R = normalize(-reflect(L,N));  
   vec4 Iamb = gl_FrontLightProduct[0].ambient;    

   vec4 Idiff = gl_FrontLightProduct[0].diffuse * max(dot(N,L), 0.0);
   Idiff = clamp(Idiff, 0.0, 1.0);     
   vec4 Ispec = gl_FrontLightProduct[0].specular 
                * pow(max(dot(R,E),0.0),0.3*gl_FrontMaterial.shininess);
   Ispec = clamp(Ispec, 0.0, 1.0); 

   vec4 color = gl_FrontLightModelProduct.sceneColor + Iamb + Idiff + Ispec;

   float pick_alpha = 0.0;

   if(pick_id.r != 0.0 || pick_id.g != 0.0 || pick_id.b != 0.0)
      pick_alpha = 1.0;

   gl_FragData[0] = color;
   gl_FragData[1] = vec4(pick_id.r, pick_id.g, pick_id.b, pick_alpha);

As you can see, I haven’t even tried making it pretty or fast or anything, I just wanted to get a rough estimate of how it would work for now. And as I said, it doesn’t do anything fancy, so it would be weird if this is what’s slowing me down.

I agree that only rendering “one pixel” would probably be a better solution, quite embarrasing that I didn’t think of that… Either way though, I still feel like this picking would be faster than the old one.

I don’t see anything wrong with the code, except the need to get rid of ‘if’. There is no reason why pick_alpha is not passed directly as ‘pick_id.w’. Paste the updated FPS after you finish with this, please.

Although unlikely that a single if-statement would give such an overhead, I did what you said, and it didn’t give any noticable difference. Please keep in mind that I’ve gotten rid of an entire rendering pass through all the geometry, yet it got slower. That’s quite a significant overhead which I can’t seem to track down.
I appreciate any ideas you might have that might explain this!

What is your hardware/OS/driver version?