Reusing shaders on a 3dengine

Hi all!

I am developing a small and simple 3d engine, just for fun. One of the basic functionality of this 3d engine is (obviously) loading 3d models and render them, each 3d model has a shader associated to it, basically, in pseudocode:

// Loads the 3d model (with required materials / textures) and a shader associated to it
void drawScene::Load() {
  // The managers help to reuse models and shaders, so if the model has been
  // previously loaded, it returns the ID, and the same for the shader: if the shader
  // has been loaded before, it will return the ID of the shader, so we avoid loading
  // multiple times the same stuff
  my_3dmodel = modelManager.LoadModel(some_path);
  my_shader = shaderManager.LoadShader(some_pathVS, some_pathFS);

  // Once the data is loaded, we set the values of the uniform variables that will never change, like samplers:
  my_shader.setUniform("name_var", some_value);
  my_shader.setUniform("shadowMap", 1); // as an example... we can tell to store the sampler2D named "shadowMap" in tex unit 1

void drawScene::Render() {
  my_3dmodel = modelManager.GetModel();
  my_shader = shaderManager.GetShader();

  // Now we set the values that normally change on every frame, like matrix values, time, etc...
  my_shader.setUniform("model", model);
  my_shader.setUniform("perspective", perspective);
  my_shader.setUniform("view", view);
  my_shader.setUniform("time", time);

  // And finally render our model

The “drawScene” class is being called several times in my engine, with different parameters, but is quite common to have different drawScene’s with different 3dModels, but with the same shader, for example:

 // scene1: This can use a "cube.3ds" model, and some "shadowMapping.vs/fs shader"
drawScene scene1;
 // scene 2: This can use a "sphere.3ds" model, and the same "shadowMapping.vs/fs shader",
 // so in this case, during the loading and render, will share the ID of the shader of scene1
drawScene scene2;

So, here comes my question…
Since I am reusing the same shader for multiple scenes (that’s why I am using the shaderManager, mainly), I think that some Uniform values that where set during the “Load” stage, are being overwritten by other scenes.
Giving to that point I have 2 options:

  • Call the “setUniform” on Render time for all the variables (even the ones that are never changed, like the “shadowMap” tex unit) -> This will probably have impacts in performance, because will mean more GL calls on Render time.
  • Stop sharing shaders, and generate new shaders for each scene, even if the shader has been previously loaded -> This will generate lots of shaders in memory but I don’t know if this can impact also in performance…

So… what is your advice? :slight_smile:
If you think in a 3rd option, please go ahead! :stuck_out_tongue:

Thanks a lot in advance!!

Use uniform buffer objects (UBOs) rather than using the default uniform block. Then you can change the uniforms by binding a different buffer.

1 Like

Thanks for your reply!
I have just read about UBO’s, and that would essentially reduce the number of “glUniform” calls, although adds some complexity to the code.
It’s really recommended to use UBO’s for just replacing a few glUniform calls?

It’s up to you which approach you want to use. I’m just pointing out that there is another option.

1 Like

sure sure, thanks a lot GClements!