Making shader_feature depend on another shader_feature

I just created a shader that takes around 10min. to compile each time a single change is made(it has like 12 shader_features). Some of the shader_features:

#pragma shader_feature ENABLED_NORMAL
#pragma shader_feature ENABLED_NORMAL_STRENGTH
#pragma shader_feature ENABLED_NORMAL_AFFECTS_RIM
#pragma shader_feature ENABLED_RIM_LIGHT

In this case both ENABLED_NORMAL_STRENGTH and ENABLED_NORMAL_AFFECTS_RIM depend on ENABLED_NORMAL - if ENABLED_NORMAL exist then they can exist otherwise they won’t be used. I tried to do the following:

#pragma shader_feature ENABLED_NORMAL
#ifdef ENABLED_NORMAL
#pragma shader_feature ENABLED_NORMAL_STRENGTH
#pragma shader_feature ENABLED_NORMAL_AFFECTS_RIM
#endif
#pragma shader_feature ENABLED_RIM_LIGHT

but it looks like it slows the compilation even more. Why is it happening? Can you please help? Thank you in advance!

The usual solution to this is to not make them separate shader feature lines.

#pragma shader_feature _ ENABLED_NORMAL ENABLED_NORMAL_STRENGTH ENABLED_NORMAL_AFFECTS_RIM ENABLED_NORMAL_STRENGTH_AFFECTS_RIM

If you’re using a custom shader editor, you can choose the option you need from the options the user has selected. If you’re not using a custom editor, you’d need to use a [KeywordEnum()] material property drawer, as well as modify the keyword names slightly to conform to how that feature functions.

The other thing to think about is if having this many variants is actually helpful or not. It may be faster to not have unique variants for everything. Using just a basic if() {} in your shader code to enable and disable features can end up being faster in real usage than having hundreds of keywords on modern GPUs.

1 Like

I am pretty sure I can make this idea work quite well with a custom editor. Thank you, you just saved me so much time!

and

produce exactly the same set of variants.
Pragma directives cannot depend on other pragma directives, so #ifdef ENABLED_NORMAL is ignored.

Hypothetically, what would determine this? I’d imagine that if you had lots of materials rendering with different variants, that would likely be slower than just causing branches with if() {}. But if your materials were all using the same variant or your objects were sharing a material, then variants would be faster. Even if you had hundreds of variants, it would only use a few. Am I accurate in my thinking?

Basically, yeah.

I would say yes when it comes to SRP Batcher (batching object by shader), having one variant should be faster than having many shader variants.

1 Like