The amount of shaders we have in our current project is too damn high, so i’d like to consolidate some shaders to one. I’m using multiple variants to opt in and out of features, just like the new standard shader coming in 5.0.
All of this works pretty good so far, i’ve got a MaterialEditor going which sets the correct Shader Keywords. In the shader itself i can check if the feature is enabled or not.
This works great, however i’d like to add an outline to this shader. This requires an extra pass, and i’m a bit lost on how to conditionally add a pass. The #ifdefs only seem to work inside a CGPROGRAM block, so i cannot compile that whole pass out. I could add a pass with empty functions if outline is disabled, but that sounds quite wasteful since every object would become 2 draw calls. Or can i somehow trigger a different subshader?
Hey Eideren, thank you for the answer. I did look into tags and shader replacement, although it might be a possible workaround i dont think its a correct way to solve the problem.
With the multiple variants we can actually compile different shaders, so there is no runtime impact at all. In the case of using shader replacement i’d have to run some script in runtime that replaces the shaders with outline, which i’d rather not do.
There isn’t a way I am aware of, #ifdef’s are local to CG. And do not exist inside ShaderLab… which is essentially what deals with all your properties and the passes, the common work around is as Eideren suggests.
I was suspecting that, thank you for pointing it out. There was one more idea i’d like to try, and its not pretty.
What if i abuse the subshader selection; i’d make 2 subshaders, one with outline and one without. Then in each do something totally impossible for the GPU ever if outline is either on or off. This way the subshader would never be selected, causing it to jump to the correct one. That is crazy enough to work right?
Yes it would work as it would try all the subshader variants before simply refusing to compile, but this seems a tremendous waste of time when you can effectively get the passes you need by tagging them. If you have a little bit of money to spare then take a look at the Text Mesh Pro plugin, this uses a combination of scripting and shader tags to do pretty much exactly what you want to do…
Thank you, i will definitely check it out! If that doesnt work out i’ll just create 2 shaders, and have the outline use the pass from the normal shader.
Although sadly compiling different shaders is not possible, i did solve some of my issues.
From the programmer’s perspective you want to share code between the different types of shaders (normal and outline). I used a custom CGinclude to share most of it, though some copying is still involved.
From the artists perspective i changed the custom editor to switch the shader when you enable or disable the option. This way the artists doesnt even notice a difference, so everything looks like its one shader.
if (isKeywordOn(OUTLINE_KEYWORD) && material.shader.name != OUTLINE_SHADER)
SetShader(Shader.Find(OUTLINE_SHADER), false);
The best thing for you: use the MeshRenderer’s materials array. Set first material to your material, and the second, to a special outline material. Yes, this does multi passing. Just ignore the warning.