I have a few ShaderLab questions

I’m looking at the standard.shader and I’m noticing some conventions that are throwing me off a bit…

  1. Why are there individual underscores in some of these prama statements and why does one of them have more than one underscore. What do they mean?

#pragma shader_feature _NORMALMAP
#pragma shader_feature _ _ALPHATEST_ON _ALPHABLEND_ON _ALPHAPREMULTIPLY_ON
#pragma shader_feature _METALLICGLOSSMAP
#pragma shader_feature ___ _DETAIL_MULX2
#pragma shader_feature _PARALLAXMAP

  1. Also, why are blend states in this shader added as hidden properties and then referenced in the pass structure? Are these special and overriden by the engine/editor or is it done this way to allow script to temporarily change them?

// Blending state
[HideInInspector] _Mode (“__mode”, Float) = 0.0
[HideInInspector] _SrcBlend (“__src”, Float) = 1.0
[HideInInspector] _DstBlend (“__dst”, Float) = 0.0
[HideInInspector] _ZWrite (“__zw”, Float) = 1.0

Blend [_SrcBlend] [_DstBlend]
ZWrite [_ZWrite]

  1. I’m never sure if a shader feature define is just for the shader, for the core shader functions or a switchable feature of the engine. Is there a list of what shader_feature or defines are exposed for the engine? Or are they mostly used so the material inspector UI can dynamically change based on what’s selected.

  2. Is there any plans to make the core shader code more abstracted so others can build their own shaders around your core shader functionality? Right now almost every support functions ( lighting etc ) all have external dependencies like global defines, vertex input structs ( which also have their members defined on/off ) and global variables. This makes it almost impossible to tie into with without having to completely duplicate every last bit of code. Besides being very time consuming, every time you change some core functionality, this needs to be ported back into our custom shaders.

  3. Why ship the builtin shaders separately and simply not expose them in the installed folder so that users could experiment with the shader code? I’m guessing to play around with a variant of the Standard shader, you’d need to copy the whole BuiltinShader folder into your project and change the paths around or something.

  4. Last question, is it possible to put our custom shaders outside of our Unity project so that you don’t have to copy shaders around between projects when they change?

Hey I have the exact same issues, have you gotten any of this answered ?

So far it seems with the introduction of U5 standard shader, it has become too streamlined for end-user.
Feels impossible to do any high level code editing by middleman, and only accessible by low-level shader coding guru.

  1. An individual or many underscores by themselves is stand in for adding a variant with no keyword from that group. If you read the documentation on shader variants it says that:
    #pragma shader_feature KEYWORD
    is actually a shortcut for:
    #pragma shader_feature _ KEYWORD

As for the underscore prefix, for the most part that’s just a coding style Unity uses to denote a value coming from the material rather than explicitly in the shader. It’s not required. Multiple underscores is likely also due to a coding style, but it’s plausible it was originally to overcome some kind of bug or requirement to have different “nothings” when calculating the variant keyword combinations.
http://docs.unity3d.com/Manual/SL-MultipleProgramVariants.html

  1. Generally the various render state flags (Blend, Zwrite, etc) are defined with some set of text values. These are values can alternatively be defined as material properties using brackets (documentation says the properties must be integer, but the standard shader uses floats so clearly it doesn’t matter which you use). The values are mapped to enums, generally in the order listed in the documentation, though On / Off is usually 1.0 and 0.0. This again is hidden in the documentation under ShaderLab: Properties, Details.
    http://docs.unity3d.com/Manual/SL-Properties.html

In the case of the standard shader they also store addition “mode” value to track the editor modifying the blend mode, Zwrite, and render queue. You can see what they’re doing if you look at the custom editor.

  1. Shader features as they’re currently used come from the material settings, either from a property or set from script. Multi compile are from the engine. The above link goes into detail as to how they differ, but there’s no diffinitive list of values as there are special multi_compile_somefeature pragmas that are shortcuts for a multitude of possible values. There are also platform specific defines or values coming from cginc files.

  2. I’m not a Unity employee so I can’t answer this one for real, but I suspect the answer is a combination of “no” and “that’s what surface shaders are for”. The standard shader is a major change from past ways they’ve gone about handling shaders where each option exists as a unique shader which makes things a little cleaner from a usability standpoint but does make it more complicated to modify.

  3. Again, not a Unity employee, but I’m guessing this is to protect the Unity editor from the equivalent of “deleting the Windows system folder” user error bugs where less informed users may modify or remove files they don’t know the importance of under the assumption they’re useless or unneeded. Requiring users to download it keeps it available while keeping things slightly more dummy proof.

  4. Yes and no. Unity’s asset system requires files to be under the asset folder, but that doesn’t mean the folders under the asset folder have to really be there. For Windows you can use a symbolic link folder using mklink /j fakeFolder c:\realFolder and there are similar commands for Mac and Linux. Basically you can create a folder that acts as a shortcut to another folder, but will be seen as an actual sub folder in the hierarchy. At my work we use symlink folders frequently for keeping everyone uniformly having a “projects” folder on their C drive even though our machine specs aren’t consistent and may require users to store some data on alternative drives depending on how much of the project they need and how big their main drive is (usually an SSD, but some are as small as 120gb with some newer machines with 500gb depending on how old the machine is).

For something like shaders it’s probably better to handle these like code and manually integrate changes and fixes as sometimes a project might need unique modifications that shouldn’t necessarily be back ported or the look of the project may actually benefit from what could be considered a bug in a shader for another.

1 Like