There have been strong requests lately to be able to tweak shader parameters in a more convenient and uniform way than we’re currently doing. Right now, we have to tweak shaders directly, which is not an ideal situation.
These settings are generally floating point numbers.
I’m proposing a scheme which can work with any of the shader backends. It’s also important that we can use these shaders without having to use presets.
There are formats which support these things already (CgFX, FX), but we cannot rely on such solutions as they cannot be supported everywhere.
For example, we can expose a setting which sets brightness in a trivial shader:
#pragma parameter BRIGHTNESS "Brightness" 1.0 0.25 2.0 0.1 // default, minimum, maximum, optional step
#ifdef PARAMETER_UNIFORM // If the shader implementation understands #pragma parameters, this is defined.
uniform float BRIGHTNESS;
// More parameters here
#else
// Fallbacks if parameters are not supported.
#define BRIGHTNESS 1.0 // Default
#endif
// Shader code
OUT.color = BRIGHTNESS * tex2D(s0, tex);
#pragmas which are unknown are ignored by the compiler. It is trivial for us to parse all lines in the shader and find all such #pragmas, but they cannot be hidden behind #includes. After parsing, we know all the uniforms we are allowed to tweak, along with a human readable description as well as defaults, min/max and step sizes.
By embedding which parameters are supported inside the shader file, we allow a mix-and-match model that automatically detects all parameters and exposes them to RGUI. In a shader preset, we can then store parameters. For example:
parameters = BRIGHTNESS;FOO
BRIGHTNESS = 1.2
FOO = 0.5
Using uniforms, we allow RGUI or other UIs to provide sliders to on-the-fly tweak shader parameters. This makes it very easy to tune shaders to your liking.
In addition to that, I’ve looked at shader pass aliases. With current multi-pass shaders, it can get complicated when shaders are referring to each other. You can use the PASS%u convention where you reference passes directly, or PASSPREV, where you do the same, but negative relative indicing. To make it more maintainable for shader writers, you can now give a name to a pass, and shaders can then refer directly to that pass. This also allows shaders to be reused across multiple presets where such absolute/relative references might not be possible without tons of copy-pasta shaders.
// Preset
shader0 = foo.cg
alias0 = FOO
shader5 = resolve.cg // Refers to PASS1 in this preset, i.e. output of shader0.
// Shader code
OUT.color = tex2D(FOO.texture, tex);
Again, to be able to function without a preset, all aliases which are recognized will add certain #defines to the shader.
#ifndef FOO_ALIAS // The FOO pass is not known
#define FOO PASS1 // Fallback
#endif
The shader-parameter branch on GitHub implements this as well as RGUI support.