8

My shaders often share much of the same functionality. For instance calculation of diffuse/specular lighting. I would like to write this one time and then reuse the code across different shaders.

Glsl has no knowledge of files, and no support for a c-like #include preprocessor directive.

I know glsl has support for compiling source from multiple cstrings, but how would you know which cstrings to include? Do you implement your own version of include? Or do you create some sort of metafile for each of your shaders?

bobbaluba
  • 3,584
  • 2
  • 31
  • 45
  • For me GLSL is a bit too low-level to the point where it's practically impossible to use it for complex cases (ex: ones where a PBR albedo channel could be a procedural, a 2D texture, a flat color, or something else) without a code generator, but the alternative solutions are often too high-level and intrusive and never quite make a neat fit for my purposes either. I ended up writing my own little extensions to GLSL with a simple preprocessor. I used to use Lua as the "meta-language" but it was never quite as streamlined until I took the time to write my own little simple parser. –  Mar 25 '18 at 20:42
  • IMO that's the way to go if you're like me and a bit of a control freak. You can add some extensions to the GLSL language which you preprocess yourself. One of the first extensions I added were `channel` keywords. They allow us to do things like `channel4 albedo;` which then signifies that it should appear in the user interface at which point the artist can choose whether albedo is represented with a single texture, a composited stack of textures, a procedural, a flat color, etc. The GLSL code then gets generated on the fly based on what the artist chose. –  Mar 25 '18 at 20:44
  • One of the trickiest things about the code gen is that, at least with the way I did it, the extensions needed to be able to generate code not only outside of `main` but also inside of it. For example, if albedo is defined by a stack of textures, they might each come with their own UV texture coordinates which need to be interpolated in the vert shader and accessible in the frag shader. So the code generation has to be able to not only generate/add code outside of `main` but inside as well. That was the only really tricky part for me though. –  Mar 25 '18 at 20:47

2 Answers2

7

In the large projects shaders often assembled at the first run (or when graphic options are changed) so they will include all vendor specific functional and are optimized for user machine and settings. And not only shader but also some stages of render pipeline.
You can treat GLSL as HTML\CSS\JavaSript code that PHP script vomits in response to the request. And you can use same technics as tampleting, code injections(for example amount of texture lookup) in loops. And it's also good for graphic designers because they have simple control on shader source through parameterization - checkbook, input fields etc and it can produce unique shader for unique cases.

JAre
  • 4,666
  • 3
  • 27
  • 45
3

I have a custom solution based on http://blackpixel.com/blog/494/xcode-using-includes-in-opengl-shaders/ [404 now]. Basically it said that you can use m4 tool to preprocess the files.

In the GLSL source files just include the desired fragment you want to reuse:

include(Utils.glsl)
include(Colors.glsl)

...

void main (void) {
    ...
}

In Xcode, add all glsl files to “Copy Bundle Resources”.

Add a “Run Script” phase with this shell script:

#!/bin/sh

cd ${BUILT_PRODUCTS_DIR}/${WRAPPER_NAME}
find . -name "*.fsh" | while read file; do
    echo Preprocess $file
    m4 "$file" > "$file.tmp"
    mv "$file.tmp" "$file"
done

exit 0

The script assumes your shaders have .fsh extension. It’s trivial to modify it to match your shader extensions.

Be warned: your shaders will be easily accessible to almost anyone. You may use it for development and convert them to strings before releasing them (not a real protection unless you encrypt it...).

Also, if there is no much sharing between shaders, you'll end up with a lot of unused code. I guess the shader compiler will take care of it but I'm not 100% sure if there is some performance penalty.

djromero
  • 19,551
  • 4
  • 71
  • 68