Shader Compilation

Import time – when you create a .shader file

  • compile the shader variants only when needed, etc. platform, variants

Build time – when you build a player

  • [level 1] ShaderLab -> glsl or hlsl or …etc
    • if platform supports, from [level 2] hlsl -> IL or MetalSL to AIR…etc
  • Cache identical shaders under Library/ShaderCache
  • compile only not-yet-ever-compiled shaders (variants for this platform only)

Run time – when you open the app

  • [level 3] glsl or hlsl or IL or AIR…etc -> driver (GPU bytecode)
    • because target device is unknown for PC/mobile at buildtime
  • Depends on driver, when to compile these codes e.g. only when it’s used
    • use shader pre-warm to “use” shaders to trigger compilation


Sources from lukasc, robs, Unity Manual and

UnityObjectToClipPos(use float4 instead of float3)

In the past, we uses mul(UNITY_MATRIX_MVP, v.vertex) to convert vertex position from local to world space. v.vertex is float4 which has w component.

But in most cases w is = 1. To make vertex shader run faster, Unity replaced it with UnityObjectToClipPos(float3 pos), which ignores w component even you pass a float4 position instead of float3.

For some advanced users who still need the w component in their custom shaders, here is a cheaper UnityObjectToClipPos() function which respects the w component!😄

// More efficient than computing M*VP matrix product
inline float4 UnityObjectToClipPosRespectW(in float4 pos)
    return mul(UNITY_MATRIX_VP, mul(unity_ObjectToWorld, pos));

This is provided by one of the Unity graphics developer, Yao.