56

The Problem (TL;DR)

My problem, fundamentally, is that I do not know how OpenGL ES 2.0 expects me to write and use multiple shaders; or if it is even advisable/expected that a person will do so.

The fundamental question here is: if I have an apple, a glowing rock and a fuzzy mesh, all in the same 3D world, all best drawn with different shader programs but using the same mvpMatrix then how would I go about using all of them in the same OpenGL render such that they all use their most appropriate shaders that I have written?

What Have I done

So I have written a basic OpenGL ES 2.0 program for my Android Game that works perfectly in that it can draw the outline of the objects to the screen. But it does nothing else; pretty much because the shaders look like this:

Vertex Shader

uniform mat4 uMVPMatrix;
attribute vec4 aPosition;

void main() {
    gl_Position = uMVPMatrix * aPosition;
}

Fragment Shader

void main() {
    gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0);
}

Now they are pretty basic. The reason that I have not gone further is because I cannot figure out if I am supposed to write one shader to apply to all of my different objects or if I am supposed to use multiple shaders. And if I am supposed to use multiple shaders to draw multiple different objects then how do I go about doing that in an efficient way?

I get the feeling that this must be basic knowledge to anybody that does OpenGL ES 2.0 day in and day out so I am hoping that somebody can answer my question or point me in the right direction.

I have:

  • Looked at multiple tutorials; none of which use anything but the most basic shaders.
  • Read the entire OpenGL ES 2.0 GLSL Spec (none of which mentioned how it was intended to be used; it was just about what everything did rather than how it fits together).
  • Tried to modify my shaders a bit.

So I'm hoping that I am close to understanding the OpenGL workflow but I don't seem to be there yet.

Edit: I found this well afterwards:

If your application is written for OpenGL ES 2.0, do not create a single shader with lots of switches and conditionals that performs every task your application needs to render the scene. Instead, compile multiple shader programs that each perform a specific, focused task.

That is from the iOS OpenGL ES 2.0 guidelines.

Robert Massaioli
  • 13,379
  • 7
  • 57
  • 73
  • could you mention how you implemented this? – Ashika Umanga Umagiliya May 02 '12 at 09:51
  • @AshikaUmangaUmagiliya: I was thinking of writing a blog post about it soon. Or a sample app. If I do write one I will update this Question. – Robert Massaioli May 02 '12 at 22:44
  • I was wondering,do you use the same vertex shader and multiple fragment shaders?if so,you have to detach the current fragment shader from the "shader program" and attach the new one.i think it's not possible.other way I can think is ,you write all fragment shader logic in one shader ,separating different effects in functions .and during runtime the current "shader function" is executed by setting parameters ? – Ashika Umanga Umagiliya May 06 '12 at 10:07
  • @AshikaUmangaUmagiliya Just like in a normal program you can use any combination of vertex and fragment shaders that you want; so long as they will validly compile together. You just compile them both together into different programs and deal with the programs as whole objects. So during runtime you use the correct "Shader Program" for what you are currently trying to render. – Robert Massaioli May 06 '12 at 12:39
  • Isnt the logic of Vertex shader same everytime?(handling matrices,lighting and fog ) .i was thinking if it's possible to change only the "fragment shader" logic ,I could avoid code duplication? – Ashika Umanga Umagiliya May 06 '12 at 14:31
  • The Vertex shader can be the same if that is what you want; but by no means does it 'have' to be the same every time. And there is no reason why you cannot write just one vertex shader and multiple fragment shaders. But you will have to compile a different Shader Program for every vertex/fragment shader combination. – Robert Massaioli May 07 '12 at 04:26

1 Answers1

21

You can use multiple shaders, but to switch between them can be quite costly so the recommended practise is to draw every object of a shader, then switch to the next shader and draw all the objects using that one and so on.
To switch between shaders, you call glUseProgram().

Jave
  • 31,598
  • 14
  • 77
  • 90
  • Okay. That is good to know. It will require slight rework on my part to make sure that each object of a certain shader gets drawn one after another bit it should certainly be possible. – Robert Massaioli Feb 09 '12 at 20:18
  • 3
    Followup question: Say I have my two programs, Foo and Bar. I alternate drawing some things with each of them. Say I call glUseProgram(Foo), set Foo's uniforms, textures, etc, and draw; then I call glUseProgram(Bar), set Bar's uniforms, textures, etc, and draw. Next time I call glUseProgram(Foo), will the GL state (eg, active/bound texture unit) reflect how Foo was set up last time I used it, or will I have to reset everything I may have changed while using Bar? – Nicu Stiurca Aug 02 '12 at 22:52
  • @SchighSchagh I believe you have to reset everything but I am not sure about that. If you don't have to reset something then they should mention it in the Spec. – Robert Massaioli Aug 02 '12 at 23:01
  • 2
    I just wanted to come back and say that this is the exact way that I ended up doing it. This works fantastically and you don't have to draw in any particular order to get the correct depth in OpenGL thanks to the z-buffer. – Robert Massaioli Aug 02 '12 at 23:02