ShaderTool
This tool parses GLSL shader files (mainly *.vert, *.frag, *.geom and *.comp) and generates C++ source files for them.
You automatically get the shaders added back to the code after saving a shader file and trigger a re-build.
The cmake macros expect the shader source below the module in a shaders/ directory.
set(SHADERS first second)
engine_generate_shaders(mymodulename ${SHADERS})
The shaders given in this example would be located at src/modules/mymodulename/shaders/first.*. The tool automatically detects the type of programs that should be connected in the final shader.
The code is generated into the build directory in generated/shaders.
Description
The generator uses ShaderTemplate.h.in and UniformBufferTemplate.h.in as a base to generate the C++ source files.
There are several variables in the template file that are replaced by the generator.
$includes$$namespace$-
$name$ -
$setters$ $attributes$$uniforms$-
$uniformarrayinfo$ -
$shutdown$ $uniformbuffers$
The parser includes a preprocessor.
You can export constants from the GLSL shader code to the generated C++ code by using $constant.
Use $constant varname 42 to generate a method that returns 42 with a name getVarname
Uniform Buffer Objects (UBO)
Uniform buffer objects allow you to share uniform data between multiple shaders efficiently. The shadertool generates C++ structs that match the GLSL memory layout.
layout(std140) uniform MaterialBlock {
vec4 diffuseColor;
vec4 specularColor;
float shininess;
};
This generates a MaterialBlockData struct with proper std140 alignment and padding. The generated code includes:
- A struct with correct padding for the memory layout
- Methods to create and update the uniform buffer
- Static assertions to verify struct size at compile time
Shader Storage Buffer Objects (SSBO)
SSBOs allow read/write access to buffer data in shaders. They are parsed using the buffer keyword and support the std430 layout which has tighter packing rules than std140.
layout(std430, binding = 0) buffer ParticleBuffer {
vec4 positions[64];
vec4 velocities[64];
float masses[]; // Dynamic array (must be last member)
};
This generates:
- A ParticleBufferData struct with std430 alignment
- A separate header file YourShaderSSBO.h with the buffer wrapper class using video::ShaderStorageBuffer
- Methods for creating, updating, and binding the buffer
- The binding index as a static constexpr
Generated SSBO Class
The generated SSBO wrapper class provides:
// Create the buffer with initial data
ssbo.create(&data, count);
// Update the buffer
ssbo.update(&data, count);
// Bind to the shader binding point
ssbo.bind();
// Access the underlying video::ShaderStorageBuffer
ssbo.getParticleBufferBuffer();
std430 vs std140 Layout
The key difference between std430 (SSBOs) and std140 (UBOs) is array padding: - std140: Arrays of scalars (float, int) are padded to vec4 boundaries (16 bytes) - std430: Arrays use natural alignment without vec4 padding
// std430 example - tighter packing
layout(std430, binding = 1) buffer DataBuffer {
mat4 transforms[16];
int count;
uint flags;
};
Dynamic Arrays
SSBOs support unsized arrays as the last member:
layout(std430, binding = 0) buffer DynamicBuffer {
int fixedData;
float dynamicArray[]; // Size determined at runtime
};
The generated struct uses [1] as a placeholder, and you allocate the actual size when creating the buffer.