The Monster v2 forum topic is here.
Table of contents
Ever wrote a shader to support one particular setup, then another for another setup, finally ending up with lots of shaders doing almost the same thing?
With #define-s and other preproc. directives, you can have "branching" in compile-time, no need to slow the code down with conditional statements.
This also allows to write ONE shader code that is VERY close to optimal for many situations.
(Of course you need to recompile, but auto-generated versions are far easier this way.)
That is what you'll find here.
Check features below.
- mainly for outdoor rendering, due to hemispherical lighting
(I wanted to have offset-mapping on every side of an object, which is quite hard with directional lights, also they are too stark for an ambient outdoor lighting)
- watch out for light positions rivalizing in distance from object's center:
a typical artifact source /closest light switches between 2 lights/
- avoid crazy parameter combos
- notice how shader instruction count varies with shader complexity:
- HLSL vertex: a full-blown vs is 58, while it is 38 with no normal mapping and only 25 if light0-light2 are disabled also (hemi still on!)
BTW the minimal possible with MONSTER_2 is 4 instr.
- HLSL pixel: full-blown gets to 73, won't compile, just as expected,
with no normal-mapping: 56.
with light0-light2 disabled (hemi and offset on): 29.
with just hemi (but fading, specular gloss, diffusetex): 12.
BTW the minimal is 2 instr. Pretty useless .
As you will notice, many parameters are #define-s, for faster code, but if real-time change is needed, they could be handed as uniforms as well.
(This applies inversely as well, so some parameters might be #defined instead of passing them as uniforms, for faster code.)
I also skipped the Ka, Kd, Ks, etc. constants present in many shaders, to be used as coefficient when summing lighting parts, obviously for performance.
They can be 'faked' by properly adjusting the diffuse/gloss/AO textures' brighness in an image editor. Add them if you wish, but they slow MONSTER down.
(Ka can be coded into AO map, Kd into diffuse map, Ks into gloss map)
They also contribute to instruction count, so beware.
Also note that I placed no lighting restrictions on the user in this release.
It's a free for all. You decide what you want, but do not expect any compiler to create you a shader that does *MAX* candy for *MAX* lights, given the instruction count limits of ps_2_0 / arbfp1.
No directional lights. Hemisphere is better, and leaving them makes syntax clearer too.
One more thing: all lights have diffuse color = specular color as an optimization.
I believe it to be reasonable.
I use 2 UV sets for now, 1 is for auto-generated AOmap, and the other is for diffuse/normal maps. I you are skilled/lucky, you can go with 1 UV set as well.
- improved lighting accuracy on low-poly meshes (2 tri quad for ex)
- clearer code
- 2 uv sets
- faster attenuation
- 1 hemispheric skylight with specular
/tune with: SKY_LIGHT_DIR, SKY_COLOR, GROUND_COLOR, SKY_EXPONENT/
- max. 3 local lights
/diffuse part, specular part, attenuation/
- per-pixel lighting / normal-mapping / offset-mapping
- texturing: (diffuse + gloss), (normal + height), ambient occlusion
- buggy distance-fadeout effect (someone should fix it, I can't get it right)
- oFusion compatibility as usual
- some typos, as usual
I do not compile this file as cg, because that way is not optimal.
Cg compiler sometimes generates longer code than HLSL.
If you need OpenGL, just change the definition in .material file to cg, and the "target" word to "profiles" like:
vertex_program Simple_Perpixel_Vert cg .. profiles vs_1_1 arbvp1 //target vs_1_1
and of course do the same for fragment_program.
Or, for real-time support of both HLSL and GLSL, create 2 versions of MONSTER, on with cg, one with HLSL, and use 2 techniques.
BTW interesting thing is that GLSL code has only ~2/3 instructions. Dunno why.
This lets you have more complex version running with GLSL.
What to do if you want *MORE* dynamic lights affecting a single static mesh?
(obviously this works mainly for large meshes and small area, attenuated lights)
- use deferred shading (needs a good card to be fast enough)
- use multiple passes (costy)
- use cheaper frag shader (looks less cool) or vertex-lights (ugly without tessellation)
- divide mesh to small parts in editor, bake it in static geometry, and you're done
(set up lots of lights swarming around the mesh, and each part will be affected by 2, but the 2 closest, which will differ with the parts position)
- alpha-maps, environment-mapping, detail-texturing (both diffuse-map and offset-map)
- volume-lighting, lightmaps, emissive-texture mapping, spot-lights, fog (volumetric?), skinning, instancing,
- a demo app like GLSLdemo with texture/mesh browser, uniform sliders, and recompile option.
the name is guilderstein, email: forgamedev_AT_yahoo_DOOT_com, insert OGRE into subject please,
private message is better however
That's all for now, go and shade