Predefined Functions with #ifdef KEYWORD

I have this shader and what I want to do is set the param for ColorMask based on a keyword.

I use this Occlusion Shader to enhance the experience with HoloLens but it’s really annoying while developing and I would like to make an option to turn on and off the mask from a menu item.

Shader "Hololens/Occlusion"
{
Properties
{
}

SubShader
{
Tags
{
"RenderType" = "Opaque"
"Queue" = "Geometry-1"
}

Pass
{
ColorMask 0 //[ColourMask]

CGPROGRAM
#pragma vertex vert
#pragma fragment frag

#pragma target 5.0
#pragma only_renderers d3d11
#pragma multi_compile HOLOLENS_OCCLUSION_OFF HOLOLENS_OCCLUSION_ON

#include "UnityCG.cginc"

struct v2f
{
float4 pos : SV_POSITION;
};

v2f vert(appdata_base v)
{
v2f o;
o.pos = UnityObjectToClipPos(v.vertex);
return o;
}

half4 frag(v2f i) : COLOR
{
#ifdef HOLOLENS_OCCLUSION_OFF
discard;
#endif
return float4(1, 1, 1, 1);
}
ENDCG
}
}
}

basically this

#ifdef HOLOLENS_OCCLUSION_ON
ColorMask 0
#else
ColorMask RGBA
#endif

The discard should work, though you don’t need to define _ON and _OFF versions of the keyword in that case, just define #pragma multi_compile __ _HOLOLENS_OCCLUSION as the multi compile and check #ifdef for it.

Also, there’s another route you can go. Remove the multi-compile option. Instead, change your ColorMask line to ColorMask [_HOLOLENS_OCCLUSION_MASK]

Now, from a script, instead of setting keyword, you can do:
Shader.SetGlobalInt("_HOLOLENS_OCCLUSION_MASK", 0);
That will set it invisible.
And
Shader.SetGlobalInt("_HOLOLENS_OCCLUSION_MASK", 16);
This will set the mask to “RGBA”.

This will change the value on all materials using the shader, and avoid creating any extra shader variants.

1 Like

Amazing stuff. Thank you very much. Exactly what I was looking for! Any chance you know how to do tags based on defined keywords?

As far as I’m aware, the compile conditionals only work within the CGPROGRAM/HLSLPROGRAM section, since that is where they are defined too.

What in your Tags section do you need to control with a keyword? Tags aren’t really part of the shader for the most part, they are properties Unity uses for the default settings a material should have that dictates how Unity should render those materials, such as a render queue value and if it should be included in projector passes, it’s not a value that gets changed in the shader itself, thus shader variants can’t affect that part, but you can manually set that stuff on a given material from code.

I was wondering if I can change the RenderType and Queue. It’s not that I needed now just wanted to know if it is possible for further use.

Naw, not with keywords. You can set the render queue on the material from code though. And same for RenderType.

A good example of how to do this can be found with Unity’s builtin shaders for the ‘Standard’ shaders ( i.e physically based rendering ones ). If you grab the Unity BuiltIn shaders download ( from the archives ) and check out both the shader but more importantly the editor script ‘StandardShaderGUI.cs’ you’ll see how Unity allows you to change render type ( and by virtue queue ) in the code.

Just for reference, the docs actually state a double underscore for no definition;

#pragma multi_compile __ HOLOLENS_OCCLUSION

https://docs.unity3d.com/Manual/SL-MultipleProgramVariants.html

True. For some reason I had thought I’d read this wasn’t needed anymore in a recent update, but I just tried and I guess it is, lame.

Doesn’t have to be a double underscore, can be a single, or triple, or any number of underscores. Official Unity shaders use many different numbers of underscores, the only important part is that it is only underscores.

Not needed for #pragma shader_feature, and there’s been some talk of making #pragma multi_compile work the same, but I’d guess it never actually made it to a live version due to worries about backwards compatibility (mainly, someone somewhere a sometime writing a shader with #pragma multi_compile _JUST_ONE_KEYWORD and that now sometimes compiling versions of the shader without that keyword potentially causing compiler issues.

1 Like

Interesting. Have always used doubles as per the doc.

So, although this wouldn’t work;

#pragma multi_compile _HOLOLENS_OCCLUSION

These will;

#pragma multi_compile __ HOLOLENS_OCCLUSION```