I've been really struggling trying to get two different shader programs working. Each works fine alone, that's not the issue. But I can't seem to switch between them to use them on two different objects. I.e. I want to use shaderFOO on triangleFOO and shaderBAR on triangleBAR. From what I understand, it's not only possible but is supposed to be relatively simple.
I've been scouring the internet for help, but have come up with bupkis. For the sake of thoroughness, these are the links I've checked here on SO:
- OpenGL ES 2.0 - Multiple Programs or Shaders
- OpenGL ES 2.0 Multiple shader programs - texture rendering not working anymore
- OpenGL ES 2.0 Multiple Programs or Multiple Shaders or what? How does it work?
The following is my relevant code. I'll let the in-code comments do most the talking.
My onSurfaceCreated() method:
int textureHandle = -1;
@Override
public void onSurfaceCreated(GL10 unused, EGLConfig config) {
// My ShaderLoader class handles all the attaching, binding, linking, etc
// of my shaders. Any and all necessary shader handles are stored in these
// objects.
shaderFOO = new ShaderLoader(context, ShaderLoader.Type.TEXTURE);
shaderBAR = new ShaderLoader(context, ShaderLoader.Type.COLOR);
// If I don't call glUseProgram() here on one of my shaders,
// no shader program is ever used...
GLES20.glUseProgram(shaderFOO.getProgramHandle());
textureHandle = TextureLoader.load(context, R.drawable.uvmap);
}
And here is onDrawFrame():
@Override
public void onDrawFrame(GL10 unused) {
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
// The glUseProgram() calls have no effect here, I don't understand why.
// The only time it seems to work is in onSurfaceCreated(). Debugging has
// shown that the program handles are still valid at this point.
GLES20.glUseProgram(shaderFOO.getProgramHandle());
//Log.v(TAG, "err:" + GLES20.glGetError()); /* no help, returns 0 */
renderFOO();
GLES20.glUseProgram(shaderBAR.getProgramHandle());
renderBAR();
}
And finally, both renderFOO() and renderBAR():
int textureUniformHandle = -1;
int textureCoordHandle = -1;
public void renderFOO() {
textureUniformHandle = GLES20.glGetUniformLocation(shaderFOO.getProgramHandle(), "u_Texture");
textureCoordHandle = GLES20.glGetAttribLocation(shaderFOO.getProgramHandle(), "a_TextureCoordinate");
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureHandle);
GLES20.glUniform1i(textureUniformHandle, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, verticesFOOBufferHandle);
GLES20.glEnableVertexAttribArray(shaderFOO.getPositionHandle());
GLES20.glVertexAttribPointer(shaderFOO.getPositionHandle(), 3, GLES20.GL_FLOAT, false, 0, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, textureBufferHandle);
GLES20.glEnableVertexAttribArray(textureCoordHandle);
GLES20.glVertexAttribPointer(shaderFOO.getAttributeHandle(), 2, GLES20.GL_FLOAT, false, 0, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
}
public void renderBAR() {
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, verticesBARBufferHandle);
GLES20.glEnableVertexAttribArray(shaderBAR.getPositionHandle());
GLES20.glVertexAttribPointer(shaderBAR.getPositionHandle(), 3, GLES20.GL_FLOAT, false, 0, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, colorBufferHandle);
GLES20.glEnableVertexAttribArray(shaderBAR.getAttributeHandle());
GLES20.glVertexAttribPointer(shaderBAR.getAttributeHandle(), 3, GLES20.GL_FLOAT, false, 0, 0);
GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, 0);
GLES20.glDrawArrays(GLES20.GL_TRIANGLES, 0, 3);
}
I've kept the setup as simple as possible. 6 verts, 2 triangles, one shader for each triangle. One shader uses color to render the triangle, the other uses texture. The only shader that ever works is the one (or the last one, if I call both) I call in the onSurfaceCreated()
method.
So as I've said, each shader works fine alone, but I'm hitting a roadblock when trying to switch back and forth between the two.