3

I'm trying to implement picking(using colors and readPixels) in a WebGL program of mine. When I start my program I create to seperate shaderProgram. One for phong shading and another that simply give shapes a color to be use to detect which shape has been clicked on.

The phong shader has 2 attributes. Vertex position and vertex normal. The picking one simply has the position.

Now I discovered that for some odd reason, when both of these shaders exist in the same program and I'm using the picking one, my drawArray call seems to fail. The last thing to happen is my gl.vertexAttribPointer call. I've been messing around and found out that when I check for active attrib arrays using: gl.getVertexAttrib(index,gl.VERTEX_ATTRIB_ARRAY_ENABLED);

both 0,1 return true (this is when the picking shader is active with gl.useProgram(picking))

Now if I disable 1 with gl.disableVertexAttribArray(1); Everything works again. Another fix is to draw with the phong shader first and then use the picking shader and somehow that magically makes it ok. I'm guessing that in that case when attaching my vertex normals buffer while using the phong shader, it somehow stays when I then switch to the picking shader and the drawArray call works.

I'd like to know if I'm using gl.enableAttribArray wrong and should disable them when switching shaders or something like that.

I've also tried creating the shader programs in different order with no success.

genpfault
  • 51,148
  • 11
  • 85
  • 139
nkassis
  • 5,285
  • 2
  • 21
  • 22

3 Answers3

3

As you've probably figured out, useProgram doesn't affect anything but the program (shader code) supposed to run in the next draw call. You have to make sure only attributes used by the current program is enabled.

If you've wrapped your WebGL code somehow, a tip is to keep the highest available attribute number for each program stored somewhere in your wrapper, then compare with the latest used program and enable/disable accordingly before the draw call.

MikaelEmtinger
  • 559
  • 3
  • 6
  • That's what I've decided to do sort of, I know which vertex attributes exist for each shader and which shader is active so I'm just wrapping my gl.useProgram calls so that I can do cleanup first. – nkassis Mar 15 '12 at 15:52
  • Actually useProgram effects the uniforms. You can simulate GL_ARB_uniform_buffer_object by just making multiple copies of the same program and in fact may drivers just do this under the hood for GL_ARB_uniform_buffer_object. – gman Mar 19 '12 at 20:07
  • In what way do you mean the uniforms are affected? As far as I understand, uniforms for one program cannot be used inside another program due to security reasons - but their state shouldn't be affected by GL.useProgram, no? – MikaelEmtinger Mar 20 '12 at 10:08
2

It's hard to tell without seeing your code but... WebGL requires that all attributes that will be accessed have enough data to satisfy the draw call. So, if you setup 2 attributes each with 3 vertices of data and draw 3 vertices, then switch shaders and setup 1 attribute with 6 vertices and leave the second attribute with only 3 vertices then attempt to draw with 6 vertices, if the shader you're currently drawing with accesses both attributes WebGL will fail the draw call.

If you run Chrome 19 it should tell you in the JavaScript console if this was the issue.

gman
  • 100,619
  • 31
  • 269
  • 393
  • Yeah chrome 19 does complains with "INVALID_OPERATION: drawArrays: attribs not setup corrrectly" (btw: OMG thank greg for that addition :P) I was under the impression that the enabled vertex attributes get reset when I run gl.useProgram with another shader. Right now I have two vertex attribute enabled when I should have one for this particular shader. Showing the code is a little hard since I wrapped it up in a bunch of objects and functions to make my life easier ;p – nkassis Mar 14 '12 at 20:16
1

OpenGL is a state machine. By selecting the picking shader you put OpenGL in a state where there's no longer the additional attributes of the phong shader.

A lot of people fall into the wrong and bad habbit to assume there was some kind of "one time initialization" with OpenGL. This is not the case. You're supposed to set all the state you need for some drawing operation, just right before that drawing operation, and ideally also to revert the settings once you're done. This means: After binding a shader, you're also supposed to enable and bind the required shader inputs aka vertex attributes.

datenwolf
  • 159,371
  • 13
  • 185
  • 298
  • I enable my vertex attribute arrays right after each gl.useProgram but that doesn't fix it. I still have to explicitly disable the second attribute array with gl.disableAttributeArray(1) – nkassis Mar 14 '12 at 16:47
  • @nkassis: Then just disable it. That's what you're supposed to do anyway. – datenwolf Mar 14 '12 at 17:20
  • @nkassis Just a clarification, the function to be called is spelled gl.disableVertexAttribArray – Robert Monfera Sep 02 '16 at 22:42