I'd like to discuss the infrastructure commonly needed / used to make working with shaders as convenient as possible.
Please add your advice, ideas, additional options, advantages and disadvantages or correct me if I'm wrong somewhere.
Also if anyone has any good ideas to avoid the problems marked below I'd love to hear them.
1. Deal with Combinatorial Explosion of Shader Permutations.
a) Use one big Über-Shader with dynamic branching.
- Bad for performance.
- Not feasible for older graphics card that don't support Shader Model 3.0.
b) Use a custom combination system that concatenates snippets of shader code together.
- A lot of additional code to write and maintain.
c) Exploit the preprocessor mechanisms the shader compiler (macros, preprocessor #ifdef tests).
- Messy if you need precompiled shader files(?)
d) Exploit the "uniform" mechanisms of D3DX effects (uniform bool variables per technique).
- Need to trust the system to do the right thing / inspect the output and tweak it.
- Depends on D3DX.
I went with option d) for now and tried two variants that I read about:
d)-i:
float4 PS_DirectBoolParam(float4 inTexCoord : TEXCOORD0, uniform bool configEnabled) : COLOR0 {
if(configEnabled) return pow(inTexCoord,pow(inTexCoord,3));
else return inTexCoord;
}
technique T_DirectBoolParam {
pass Pass0 {
PixelShader = compile ps_3_0 PS_DirectBoolParam(false);
}
}
+ Works.
- Becomes quite messy when you have half a dozen or even more boolean options.
d)-ii:
struct Config { bool Enabled; };
uniform Config std = { false };
Config WithEnabled(Config cfg) { cfg.Enabled=true; return cfg; }
float4 PS_ViaStruct(float4 inTexCoord : TEXCOORD0, uniform Config config) : COLOR0 {
if(config.Enabled) return pow(inTexCoord,pow(inTexCoord,3));
else return inTexCoord;
}
technique T_ViaStruct {
pass Pass0 {
PixelShader = compile ps_3_0 PS_ViaStruct(std);
}
}
+ Leads to quite maintainable code even with a ton of boolean options.
- Doesn't seem to compile to the expected output. Uses dynamic Über-Shader-like branches.
Are there any good tricks to make this work well?
2. Integrate in Visual Studio: Syntax Hilighting and more
a) Simply register .fx files with the C++ syntax highlighting system
+ Easy to do
- Doesn't know about most shader keywords
b) Use IntelliShade.Net plugin
+ Proper syntax highlighting
+ Even has IntelliSense support
- After using it for some time, I find that I'm actually only annoyed by the IntelliSense.
It has NEVER helped and gets in the way often.
c) Use the Cg SDK plugin
?
3. Integrate in Visual Studio Build System
a) Write custom pre-/post build steps
- Messy
- No dependency checking
b) Write a "custom build rules" file
+ Quiet nice and clean
+ Dependency checking
- Only available in C++ projects
- Inter-Project and include file dependency checking is broken/flawed
Are there any good tricks to make this work well?
4. Write Modular Shader Code
a) Use #include directives
- Breaks 3.b) dependency checking
b) ?
5. Write API independent code
a) Use Cg
?
b) Use HLSL and a HLSL-to-GLSL converter
?
___________________________Buggrit, millennium hand and shrimp!