Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

I'm currently studying opengl shaders but I can't figure out something: how to apply different shaders to the objects, for example, a teapot rendered using toon shader and another one in the same scene using a very reflective surface and other distorted from a noise function, like in this video

http://www.youtube.com/watch?v=1ogg4ZfdBqU

Another one is applying a bloom shader in a scene and a motion blur shader afterwards. How to achieve those effects when you can only have one vertex shader and one fragment shader? Is there any trick such as using more than one shader program?

share|improve this question
    
Re Nathan and David's good answers, this is why you see the term render pass or shader pass; there are multiple passes required to compose the final image/frame. One of the reasons why GPU processing has become so damned parallel and thus so fast is the need for multiple passes per frame. Go back to the Quake II or Half Life software renderers to remind yourself just how much love shader passes add to the whole 3D graphics experience. –  Nick Wiggill Jan 11 '12 at 2:36

4 Answers 4

up vote 31 down vote accepted

The simple answer is you change them between each draw call. Set a shader, draw a teapot, set another shader, draw another teapot.

For more complex stuff where you need to apply multiple shaders to just one object such blur, glow and so on. You basically have everything rendered to texture(s). Then you render a quad over your entire screen with that texture applied while using another shader.

For example if you want to render a glow effect, you first need to render your regular non-glowing scene, then render just the colored silhouette of the stuff that you want to glow on a texture then you switch to a blur shader and render your quad with that texture attached over your non-glowing scene.

There is another technique called Deferred shading where you render the scene without lighting and apply it later in screen space. The core goal is to reduce the expense of per pixel lighting.

Normally you render a color buffer which is put on the screen. With deferred shading you instead render a color buffer as well as a normal and depth buffer in one shader pass (you can store the normal vectors and the depth in a texture like with normal and height mapping).

This means that, for every pixel, you know the position of the nearest piece of non transparent geometry (depth or distance from eye) the color and the normal. Because of this you can apply lighting to each pixel on the screen instead of to each visible pixel of every object you render. Remember that some object will be drawn over the top of other objects if the scene isn't perfectly rendered in front to back order.

For shadows you actually render just the depth buffer from the point of view of your light then use that depth information to work out where the light strikes. That's called shadow mapping (there is also another approach called shadow volumes that works out a siluet of the geometry and extrudes it, but your still going to be using shaders.).

With more modern OpenGL (3.0+) you use a Framebuffer Object with Renderbuffers Objects attached. Since renderbuffers can be treated like a texture. You might do things like have 1 shader render to multiple different renderbuffers (so you don't have to render your texture then your normals then the glow components) but the underlying practice is still the same.

Also it's desirable to minimize the number of shader switches as much as possible to save on overhead. So some engines will group everything with the same material together so it can all be drawn at once.

share|improve this answer

Another way of doing that I have discovered is through something called glsl subroutines, where each type of shader is defined in one function, and in the OpenGL application, we can define the current subroutine, draw the vertex of a buffer, change the subroutine and rendering another buffer

share|improve this answer
1  
This requires GL 4.x-capable hardware, which is DX11-class hardware. –  Nicol Bolas Jan 30 '12 at 0:59

Using more than one shader in a scene is quite simple; change the shader, set the values for it, then render the object.

Beware, however, switching shaders can be costly, so shader switching should be kept to a bare minimum. There are a few ways to reduce this impact while getting all of the effects you want.

The first method, and usually the most desirable, is to add the functionality for all your shader techniques to just one shader and use conditions you set to render each object in a different way with the same shader. I don't know about OpenGL and GLSL shaders but with HLSL shaders and DirectX these can be grouped together as a "technique" and you can set the technique instead of changing the shader. This allows you to actually have several different pixel and vertex shaders in the same file.

The second way to reduce performance impact is to set the shader, render every object that uses that shader, then repeat. In other words, batching your rendering.

If you wish to apply two different effects to the same object (i.e. apply say a toon shader then some lighting) you can do it in two different ways. The first is to write a shader that applies multiple effects in the same function. The second way is to render the model once with each shader and blend the results by setting different blend options. However, this is a lot more work, and not achievable in all circumstances. Therefore the best option is to combine all your effects into one shader.

share|improve this answer

You just bind one shader, render all the objects using that shader, then bind the next shader, render the objects using that one, etc.

You can have as many shader objects (shaders loaded into memory and compiled) as you want; only one can be bound (active) at a time.

share|improve this answer
2  
In terms of implementation, in every frame I use glUseProgram(1) and glUseProgram(2) to change shaders? How costly for performance is that? –  ibrabeicker Jan 11 '12 at 12:09
    
It's a nontrivial cost (although less on recent GPUs than earlier ones). That's why most people sort their objects by material, rendering all the objects with the same material together. But you can certainly afford to change programs tens to hundreds of times per frame, if not more. –  Nathan Reed Jan 11 '12 at 17:34

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.