Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Vert vs Frag efficiency

Discussion in 'Shaders' started by tmcthee, Feb 27, 2020.

  1. tmcthee

    tmcthee

    Joined:
    Mar 8, 2013
    Posts:
    119
    I have a shader that uses textures to create an Ambient occlusion/shadowing effect in certain regions of the scene. (for mobile)

    I'm using magic numbers to position the textures in the world space. So I thought it would be more efficient to calculate the scaling and offset in the vert function. But I've recently read that passing interpolators from the vert to the frag has some overhead worth considering.

    So given that the calculation to offset the UVs is pretty simply. Would I have been better off just passing the world position though in one go and calculating the offsets in the frag?

    Should I just do it and look at the profiler? Or are there any heuristics that can help plan in advance?

    The object this shader operates on is about 800 verts. It's usually quite small on the screen, but sometimes it can be quite large (which I assume increases the work the frag has to do)


    Code (CSharp):
    1. Shader "TMCShaderQuarantine/efficiencyQ" {
    2.     Properties
    3.     {
    4.     _MainTex("Base (RGB)", 2D) = "white" {}
    5.     _boundaryAO("boundaryAO", 2D) = "white" {}
    6.     _boundaryAOMask("boundaryAO mask", 2D) = "white" {}
    7.  
    8.     }
    9.  
    10.     Subshader
    11.     {
    12.         Tags{ "RenderType" = "Opaque" }
    13.  
    14.         Pass
    15.     {
    16.  
    17.     CGPROGRAM
    18.     #pragma vertex vert
    19.     #pragma fragment frag
    20.     #pragma fragmentoption ARB_precision_hint_fastest
    21.     #include "UnityCG.cginc"
    22.     struct appdata
    23.     {
    24.         float4 vertex    : POSITION;
    25.         float2 uv     : TEXCOORD0;
    26.         float3 color : COLOR;
    27.     };
    28.     struct v2f
    29.     {
    30.         float4 vertex    : SV_POSITION;
    31.         float2 uv     : TEXCOORD0;
    32.         float3 worldRefl : TEXCOORD1;
    33.  
    34.         float3 objectOrigin : TEXCOORD3;
    35.         float3 boundaryAOUV : TEXCOORD4;
    36.         float3 boundaryAOUV2 : TEXCOORD5;
    37.         float3 boundaryAOUV3 : TEXCOORD6;
    38.         float3 boundaryAOUV4 : TEXCOORD7;
    39.         float3 boundaryAOMaskUV : TEXCOORD8;
    40.  
    41.         float3 color : COLOR;
    42.     };
    43.  
    44.     v2f vert(appdata v)
    45.     {
    46.         v2f o;
    47.         o.vertex = UnityObjectToClipPos(v.vertex);
    48.         o.uv = v.uv;
    49.  
    50.         float3 worldPos = mul(unity_ObjectToWorld, v.vertex).xyz;
    51.  
    52.         o.boundaryAOMaskUV.x = (worldPos.x / 130.6) + 0.08;
    53.         o.boundaryAOMaskUV.z = (worldPos.z / 236.4) + 0.026;
    54.  
    55.         o.boundaryAOUV.x = (worldPos.x / 12) + 0.1;
    56.         o.boundaryAOUV.y = (worldPos.y / 3.85) - 7.84;
    57.         o.boundaryAOUV2.x = (worldPos.x / -12) + 9.4;
    58.         o.boundaryAOUV2.y = (worldPos.y / 3.85) - 7.84;
    59.         o.boundaryAOUV3.z = (worldPos.z / -12) + 18.75;
    60.         o.boundaryAOUV3.y = (worldPos.y / 3.85) - 7.84;
    61.         o.boundaryAOUV4.z = (worldPos.z / 12) + 0.06;
    62.         o.boundaryAOUV4.y = (worldPos.y / 3.85) - 7.84;
    63.  
    64.         return o;
    65.     }
    66.  
    67.     sampler2D _MainTex;
    68.     sampler2D _boundaryAO;
    69.     sampler2D _boundaryAOMask;
    70.  
    71.  
    72.     fixed4 frag(v2f i) : SV_Target
    73.     {
    74.         fixed4 boundaryAO = tex2D(_boundaryAO, i.boundaryAOUV.xy);
    75.         boundaryAO *= tex2D(_boundaryAO, i.boundaryAOUV2.xy);
    76.         boundaryAO *= tex2D(_boundaryAO, i.boundaryAOUV3.zy);
    77.         boundaryAO *= tex2D(_boundaryAO, i.boundaryAOUV4.zy);
    78.         boundaryAO += tex2D(_boundaryAOMask, i.boundaryAOMaskUV.zx);
    79.         boundaryAO = clamp(0, 1, boundaryAO);
    80.  
    81.         fixed4 tex = tex2D(_MainTex, i.uv);
    82.         tex *= boundaryAO;
    83.         return tex;
    84.     }
    85.  
    86.         ENDCG
    87.  
    88.     }
    89. }
    90.         Fallback "Transparent/VertexLit"
    91.  
    92. }
    I've realise since that I can pack the UVs into float4s to reduce the number of interpolators. But I'd still be interested if there's any rules of thumb to estimate this in advance.
     
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Yes.

    Especially since they're hardcoded in the shader, each of those lines will be simplified by the compiler to a single MAD.

    Passing 10 vertex properties, even compacted into 3 interpolators, is going to be way more expensive than 10 MADs on anything built in the last 10 years.
     
    tmcthee likes this.