Is it typical to duplicate code between shaders?

I’m in the process of better understanding shaders specifically the ability to chain/combine shaders together currently I have a simple scene with cascading shadows and phong lighting (thanks to learnopengl) now if I wanted to have a plant with a wind effect or a animated character that also has shadows and lighting it seems like the solution is duplicating code is that really the answer?

My current code is this

LoadShaderProgram("CSMPhong", "Resources/Shaders/CSMPhong.vert", "Resources/Shaders/CSMPhong.frag");
LoadShaderProgram("ShadowDepth", "Resources/Shaders/ShadowDepth.vert", "Resources/Shaders/ShadowDepth.frag", "Resources/Shaders/ShadowDepth.geom");

LoadShaderProgram("CSMPhongWind", "Resources/Shaders/CSMPhongWind.vert", "Resources/Shaders/CSMPhong.frag");
LoadShaderProgram("ShadowDepthWind", "Resources/Shaders/ShadowDepthWind.vert", "Resources/Shaders/ShadowDepth.frag", "Resources/Shaders/ShadowDepth.geom");

I did realize that I could reuse other shaders so CSMPhongWind is reusing the fragment shader from CSMPhong but still this feels very error prune if I update something I’ll need to make sure every variant is also updated. So yeah is this typical or are there better alternatives?

It’s up to you.

Duplicating code is almost always the wrong solution. We all know the maintenance headache caused by copy/paste/modify coders. For toy simple 2 shader demos, fine. For a large code base? Not a good idea.

You can provide multiple source strings to glShaderSource().

You can use #include directives in shaders, pointing to custom code you attach to those included “files” (with ARB_shading_language_include).

You can write your own string concatenation and/or string preprocessing to “plug in” shared code.

Up to you which one works best for your scenario.


Whoa that information might be game changer. Does this mean instead of creating CSMPhongWind.vert (which is a variant of CSMPhong.vert) I can just have CSMPhong.vert and then when loading shaders add on Wind.glsl which just provides the necessary data instead.

1 Like


If you have shared decls or functions used between one or more shaders, that’s a perfect thing to put in these shared files. Just “call” them whereever you need them. The GLSL compiler+linker will inline them, toss out any unused code and code paths, and optimize your shader for max performance.