Typically when writing shaders, you'd have some code like this:
```cs
public void CreateShader()
{
string fragmentShader = @"
uniform vec4 uColour;
out vec4 outColour;
void main()
{
outColour = uColour;
}
";
// Create the shader
Gl.ShaderSource(ID, fragmentShader);
...
// Get the uniform location
int location = Gl.GetUniformLocation(Handle, "uColour");
// Set the uniform
Gl.Uniform4(location, 1.0f, 0.0f ,0.0f, 1.0f);
}
```
For a simple shader like this, it's not too bad. But when you have dozens of uniforms with different types, it's a lot to keep track of.
To reduce the amount of code you need to write, and to ensure you're setting the right data types on each uniform, create a new class that overrides [[ShaderUniformGroup]]:
```cs
public class ExampleUniforms : ShaderUniformGroup
{
public ExampleUniforms() : base("")
{
colour = AddVec4("uColour");
}
public ShaderUniformVec4 colour;
}
```
Define your uniforms in the constructor using the `Add*()` functions, and they'll be automatically inserted into the fragment and vertex shader strings.
To use these uniforms in your shader, pass them to the `AddUniforms` function:
```cs
public class ExampleShader : ScreenShader
{
protected override void Initialise()
{
AddUniforms(ref uniforms);
}
public ExampleUniforms uniforms;
protected override string FragmentOuter => "out vec4 oColor;";
protected override string FragmentInner => "oColor = uColour;";
}
```
> The uniforms are passed as `ref` variables so that they can be hot-reloaded (see below)
To set a value on the uniform, you can call the `Set()` function:
```cs
ExampleShader shader;
public void RenderStuff()
{
shader.UseProgram();
shader.uniforms.colour.Set(Color.Green);
// Render a model
...
}
```
## Hot Reloading
If any part of the shader code changes (uniforms, fragment shader, vertex shader), the shader will be recompiled when [[Hot Reload|hot reloading]]. If there's a syntax error in the shader code, it will log the error and revert back to the previous working version of the shader.