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

Is shader optimisation presenting a problem here?

Discussion in 'Shaders' started by HNessReg, Aug 23, 2016.

  1. HNessReg

    HNessReg

    Joined:
    Aug 22, 2016
    Posts:
    4
    [Unity 5.4]

    Hi,

    I've been working the last two days trying to get a texture array shader working. I tried asking about it yesterday on Answers but it's been in the moderation queue for 22 hours. I've removed it now as I've figured out the problem and want to redirect the question.

    If you were to create this shader...

    Code (Surface):
    1. Shader "Custom/TextureArray"
    2. {
    3.    Properties
    4.    {
    5.      _MyTextureArray("Texture Array", 2DArray) = ""
    6.      {
    7.  
    8.      }
    9.    }
    10.  
    11.    SubShader
    12.    {
    13.      Tags
    14.      {
    15.        "RenderType" = "Opaque"
    16.      }
    17.  
    18.      LOD 200
    19.  
    20.      CGPROGRAM
    21.  
    22.      #pragma surface surf Standard fullforwardshadows
    23.      #pragma target 3.5
    24.  
    25. #if SHADER_TARGET >= 35
    26.      UNITY_DECLARE_TEX2DARRAY(_MyTextureArray);
    27. #endif
    28.  
    29.      struct Input
    30.      {
    31.        float2 uv_MyTextureArray;
    32.      };
    33.  
    34.      void surf(Input IN, inout SurfaceOutputStandard o)
    35.      {
    36.      #if SHADER_TARGET >= 35
    37.        o.Albedo = UNITY_SAMPLE_TEX2DARRAY(_MyTextureArray, float3(IN.uv_MyTextureArray, 0)).rgb;
    38.      #else
    39.        // Anything in here will not actually be executed.
    40.        o.Albedo.yz = IN.uv_MyTextureArray.rg;
    41.        o.Albedo = float4(1, 0, 1, 1);
    42.      #endif
    43.      }
    44.  
    45.      ENDCG
    46.    }
    47.  
    48.    FallBack "Diffuse"
    49. }
    You'll find it doesn't work. Why? Apparently because...

    Code (Surface):
    1. o.Albedo.yz = IN.uv_MyTextureArray.rg;
    Gets optimised away. Okay, so that should be fine, it was only going to be overwritten by the next line. However, it actually invalidates this line too...

    Code (Surface):
    1. o.Albedo = UNITY_SAMPLE_TEX2DARRAY(_MyTextureArray, float3(IN.uv_MyTextureArray, 0)).rgb;
    The shader will act as if though all UV coordinates are (0, 0). Why? I don't know. If you swap the two bottom lines around, the shader will work fine.

    Here are the expanded shader instructions.

    http://imgur.com/a/OriD6

    Is this intended behaviour that I haven't found any note on in many hours of searching? In which case, what is the appropriate solution? Or is a bug with shader optimisation? It's literally changing the behaviour of my program.

    Thanks.
     
    Last edited: Aug 23, 2016
  2. mj321

    mj321

    Joined:
    Aug 23, 2016
    Posts:
    21
  3. HNessReg

    HNessReg

    Joined:
    Aug 22, 2016
    Posts:
    4
    To my understanding, Unity passes all UVs in as float4's with it's default vertex inputs. Take a look at https://docs.unity3d.com/Manual/SL-VertexProgramInputs.html. It's just converted to the type you specify in your Input structure. I will eventually be using float3 when I have array indices to provide, but for now the graphics pipeline will automatically set the .z component to 0, or the first index.

    Anyway, the actual texture array sampling does indeed work as intended. I'm just concerned over the optimisation part and how it's discarding my variables unless I redundantly use them. I can still make progress on my project knowing this but it would be nice to have an understanding of what is happening.
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Unity passes float4 values for the mesh UVs, but if you specify a float2 it'll be treated as a float2 in the shader. Like you said it shouldn't matter since you're expanding it back to a float3 on use.

    However I suspect the problem you're having is surface shaders are overly zealous when it comes to optimizing away uv values that are actually needed. You have to work around it by not using the automatic uv_TextureName Inputs and instead either use myUV0 : TEXCOORD0; and apply any scale / offset (if needed) in the surf function or by using a custom Input variable that you fill in with a custom vertex function.
     
  5. HNessReg

    HNessReg

    Joined:
    Aug 22, 2016
    Posts:
    4
    Yes, writing a custom vertex routine has done the trick.

    Thanks. :)