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.

What is the most accepted way for keeping a shader's matrices up to date, and why?

For example, at the moment I have a Shader class that stores the handles to the GLSL shader program & uniforms. Every time I move the camera I then have to pass the new view matrix to the shader, then every different world object I must pass it's model matrix to the shader.

This severely limits me as I can't do anything without having access to that shader object.

I thought of creating a singleton ShaderManager class that is responsible for holding all active shaders. I can then access that from anywhere and a world object wouldn't have to know about what shaders are active just that it needs to let the ShaderManager know the desired matrices but I'm not sure this is the best way and there's probably some issues that will arise from taking this approach.

share|improve this question
    
Why not pass the data to the shaders when it's time to render? –  Nick Caplinger Jun 9 '13 at 20:47
    
That's what I intend but how? If one object creates a shader then how are world objects meant to know about that shader's existance and to pass it the necessary matrices? –  Lerp Jun 9 '13 at 20:59
add comment

2 Answers

up vote 3 down vote accepted

Use uniform buffers (ie constant buffers in D3D lingo).

So long as all your shaders agree on the layout and binding point of each such buffer then updating becomes a breeze. Models have no need to know anything about shaders at all. They need only update the model-view matrix in their constant buffer and the rendering pipeline will use it automatically.

At a minimum I would argue you should have two such buffers. The first should store your projection matrix, camera matrix, the concatenated camera-projection matrix, viewport information, frustrum details, and matrix inverses. You only need to update this buffer once per scene.

Then give each model another buffer to store its model-view matrix, normal matrix, inverses, and material properties. This is updated once for each model and can be done in a different update pass (if/when appropriate). The material information can/should be moved to a third material-specific buffer if you have the ability to share materials between multiple objects.

In a forward-shading setup it makes some sense to put all the lights in another buffer and in deferred-shading it likewise makes sense to use a per-light buffer for the light pass (in place of a model/material buffer used in the geometry pass).

Note that you need a moderately up-to-date version of GL to use uniform buffers at all (3.1 or an extension; common enough today except on some older but still-in-service laptops) and you need a fairly recent version to be able to bind uniform buffers to specific binding locations from inside the shader code (4.2; still uncommon but getting better) otherwise you have to do more work in your CPU-side code to set things up (your CPU code needs to know the right binding points anyway, so it's more of an API smell than a serious issue). OpenGL|ES didn't add uniform buffers until 3.0 which is still unsupported on most popular mobile platforms, unfortunately.

If buffers aren't an option then you will need some global place to store index locations for the active shader. You can use glGetUniformLocation after loading your shader to find the indices for well-known names (like ModelViewMatrix or the like) then store these indices. Your render can map enum values like MODEL_VIEW passed to a SetUniform wrapper function to look into the bound shader, find the index, and call glUniform properly. It's not a particular huge change in client code usage from buffers other than needing to set each uniform individually if you get it all wrapped up nicely.

See GLSL Inteface Blocks and Uniform Buffer Objects.

share|improve this answer
    
I knew their would be a built-in way. Thanks! –  Lerp Jun 9 '13 at 22:32
add comment

The simplest way to do this is to just standardize uniform names between your shaders and just send all the data over right before you draw. The overhead isn't insane, but you can optimize it later to not always send lesser-updated uniforms.

The way I do this in my game is that I have an abstract Material class. Materials act as a bridge between the game and shaders. Each Material has a Shader and various properties that can be set, including textures. When it's time to draw an object, its Material is bound. The Bind method has a GraphicsState parameter that contains all the current graphics state - matrices, lights, etc. The Bind method binds the shader and textures and sets all the uniforms, using whatever it needs from the GraphicsState.

share|improve this answer
add comment

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.