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

Texture2DArray won't compile in surface shader

Discussion in 'Shaders' started by TheCelt, Sep 29, 2018.

  1. TheCelt

    TheCelt

    Joined:
    Feb 27, 2013
    Posts:
    741
    Hi

    I have a surface shader where I am trying to use a Texture2DArray for the textures.

    I essentially used the same syntax as the documentation shows but it gives me this error:



    Code (CSharp):
    1. cannot implicitly convert from 'const float2' to 'float3'
    2. Compiling Vertex program with UNITY_PASS_FORWARDBASE DIRECTIONAL
    3. Platform defines: UNITY_ENABLE_REFLECTION_BUFFERS UNITY_USE_DITHER_MASK_FOR_ALPHABLENDED_SHADOWS UNITY_PBS_USE_BRDF1 UNITY_SPECCUBE_BOX_PROJECTION UNITY_SPECCUBE_BLENDING UNITY_ENABLE_DETAIL_NORMALMAP SHADER_API_DESKTOP UNITY_COLORSPACE_GAMMA UNITY_LIGHT_PROBE_PROXY_VOLUME UNITY_LIGHTMAP_FULL_HDR
    It takes me to the surf shader but the line number doesn't match since it says line number 192 and my shader only goes to 50.

    This is my shader code currently:

    Code (CSharp):
    1. Shader "Custom/TextureArrayStandard" {
    2.     Properties {
    3.         _Color ("Color", Color) = (1,1,1,1)
    4.         _TextureArray ("Albedo (RGB)", 2DArray) = "" {}
    5.         _Glossiness ("Smoothness", Range(0,1)) = 0.5
    6.         _Metallic ("Metallic", Range(0,1)) = 0.0
    7.    
    8.     }
    9.     SubShader {
    10.         Tags { "RenderType"="Opaque" }
    11.         LOD 200
    12.  
    13.         CGPROGRAM
    14.         #pragma surface surf Standard fullforwardshadows
    15.         #pragma require 2darray // support the use of 2DTexture Arrays
    16.          
    17.         struct Input {
    18.             float3 uv_MainTex; // we use float3 the Z will define the texture array index
    19.         };
    20.  
    21.         half _Glossiness;
    22.         half _Metallic;
    23.         fixed4 _Color;
    24.         UNITY_DECLARE_TEX2DARRAY(_TextureArray); //required to use as a texture array
    25.  
    26.         UNITY_INSTANCING_BUFFER_START(Props)        
    27.         UNITY_INSTANCING_BUFFER_END(Props)
    28.  
    29.         void surf (Input IN, inout SurfaceOutputStandard o) {
    30.  
    31.             fixed4 c = UNITY_SAMPLE_TEX2DARRAY (_TextureArray, IN.uv_MainTex) * _Color;
    32.             o.Albedo = c.rgb; //error occurs on this line, not sure why however
    33.  
    34.             o.Metallic = _Metallic;
    35.             o.Smoothness = _Glossiness;
    36.        
    37.             o.Alpha = c.a;
    38.         }
    39.         ENDCG
    40.     }
    41.     FallBack "Diffuse"
    42. }

    Hope some one can help explain the problem :)
     
    Last edited: Sep 29, 2018
  2. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Surface shaders will always internally use a float2 for Input variables with the uv prefix. That means even though you’re writing:

    float3 uv_MainTex;

    It’ll calculate the UV value as a float2 in the vertex shader, and only pass that float2 value to the fragment shader. The error is it’s then trying to set the Input’s float3 value with the float2 it has.

    The solution is you’ll need to transfer the z component, or potentially the full float3 UV, using a custom Input which you set using a custom vertex function.

    As for why you’re getting an error on line 192 from a shader that’s only 42 lines long... it’s because your shader is actually several hundred lines long, at least the one that's being compiled. Surface Shaders are vertex fragment shader generators, the error is in the full generated shader file, not within your Surface Shader. If you select your shader in the editor, then click on “Show Generated Code” you’ll likely find something like this:

    surfIN.uv_MainTex = IN.pack0.xy;

    Since you defined uv_MainTex as a float3, the shader compiler is upset. This won't be on the line the error says either, but that's because of shader code that was added so that the line the compiler returns is relative to the surface shader you wrote, and not the actual shader it's compiling. Scroll up and you'll find a line like this:

    #line 11 ""

    That makes the line number match up with the code you wrote in your shader rather than in the generated shader. Normally the error is in your code, and it nicely returns a the line within your shader file. But for the cases the error occuring within the written code it is very confusing.
     
  3. TheCelt

    TheCelt

    Joined:
    Feb 27, 2013
    Posts:
    741
    Ah okay, so this sounds a little bit complicated to fix then ? Or is there an easy way for me to fix this problem ?

    I am not sure what steps i need to make to fix it. Kinda wish unity supported them already included as i imagine a lot of people use them.

    Do you have any advice on how to make the include to have it work ?
     
  4. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
  5. TheCelt

    TheCelt

    Joined:
    Feb 27, 2013
    Posts:
    741
    I'm not sure i understand how i would get the z value from the uv data in the custom vertex shader, if the standard shader won't expose the 3rd value? Unless i am misunderstanding you. Am still quite new to the world of shaders.
     
  6. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    It won’t expose the third value if you use the auto generated uv variable. So you don’t rely on it.

    Code (csharp):
    1. #pragma surface ... vertex:vert
    2.  
    3. Input
    4. {
    5.     float2 uv_MainTex;
    6.     float texIndex;
    7. };
    8.  
    9. void vert(inout appdata_ full v, out Input o)
    10. {
    11.     UNITY_INITIALIZE_OUTPUT(Input,o);
    12.     o.texIndex = v.texcoord.z;
    13. }
    14.  
    15. void surf (Input IN, inout SurfaceOutputStandard o) {
    16.     fixed4 c = UNITY_SAMPLE_TEX2DARRAY (_TextureArray, float3(IN.uv_MainTex, IN.texIndex));
    17. ...
     
  7. TheCelt

    TheCelt

    Joined:
    Feb 27, 2013
    Posts:
    741
    Hi thanks for the reply. I tried that but i seem to have issues with my albedo.

    I got the same vertex shader as yours but i was getting a grey colour, so i did a test on my uv output in albedo like below:

    Code (CSharp):
    1.         void surf (Input IN, inout SurfaceOutputStandard o) {
    2.  
    3.             float3 uv = float3(IN.uv_MainTex,IN.texIndex);
    4.             //not using sample whilst debugging uvs
    5.             fixed4 c = UNITY_SAMPLE_TEX2DARRAY (_TextureArray, uv) * _Color;
    6.             o.Albedo.r = uv.x;
    7. ...
    It comes out completely black, so it seems the uv's are not interpolating and that x is always 0. Same goes for the y value when i tested it.

    Output testing uvs on x or y on red channel:



    I tried:

    Code (csharp):
    1. o.Albedo.r = uv.z // tex index test
    to check my texIndex was correct, and it is which you can see here (red tiles show that they are marked as tex index = 1 and black = 0):



    So this has confused me for why my UVs are not interpolating (or they are but are always zero for other reasons).

    This is my current Shader code:
    http://hatebin.com/mrkjvqqfti

    And this is my UV code generation in C# just encase it stems from that some how:

    Code (CSharp):
    1.        
    2.         _uvs.Clear();
    3.         for (int row = 0; row < _chunkSize; row++)
    4.         {
    5.             for (int column = 0; column < _chunkSize; column++)
    6.             {
    7.                 Random.InitState(DateTime.UtcNow.Millisecond + Random.Range(0, 1500));
    8.                 var value = Random.Range(0, 2); //randomise which texture array id [0 or 1]
    9.                 _uvs.Add(new Vector3(0, 0, value)); //bottom left
    10.                 _uvs.Add(new Vector3(0, 1, value)); // top left
    11.                 _uvs.Add(new Vector3(1, 1, value)); // top right
    12.                 _uvs.Add(new Vector3(1, 0, value)); // bottom right
    13.             }
    14.         }
    15.         mesh.SetUVs(0, _uvs);
     
  8. bgolus

    bgolus

    Joined:
    Dec 7, 2012
    Posts:
    12,329
    Ah, right. You’re not using a texture named _MainTex, so Unity skips passing the UVs from the vertex to the fragment. Try renaming uv_MainTex to uv_TextureArray.
     
  9. TheCelt

    TheCelt

    Joined:
    Feb 27, 2013
    Posts:
    741
    Oh ok it works great now, thanks! So many weird things with surf shaders that are not obvious =/
     
  10. jister

    jister

    Joined:
    Oct 9, 2009
    Posts:
    1,749
    hey sorry to revive this thread, but I'm stuck with the same problem and changing my uv name doesn't fix it...

    Code (CSharp):
    1. struct Input {
    2.             float2 uv_MainTex;
    3.             float2 uv_TextureArray;
    4.             UNITY_VERTEX_INPUT_INSTANCE_ID
    5.         };
    6. ...
    7. UNITY_DECLARE_TEX2DARRAY(_MyArr);
    8.  
    9.         void vert(inout appdata_full v, out Input o)
    10.         {
    11.             UNITY_INITIALIZE_OUTPUT(Input, o);
    12.             UNITY_SETUP_INSTANCE_ID(v);
    13.             UNITY_TRANSFER_INSTANCE_ID(v, o);
    14.            
    15.             o.uv_TextureArray = v.texcoord1.xy * unity_LightmapST.xy + unity_LightmapST.zw;
    16.         }
    17.  
    18.         void surf (Input IN, inout SurfaceOutputStandard o)
    19.         {
    20.             UNITY_SETUP_INSTANCE_ID(IN);
    21.             // Albedo comes from a texture tinted by color
    22.             fixed4 main_color = tex2D (_MainTex, IN.uv_MainTex);
    23.             half4 paint = UNITY_SAMPLE_TEX2DARRAY(_MyArr, float3(IN.uv_TextureArray, UNITY_ACCESS_INSTANCED_PROP(Props, _ID)));
    24.             o.Albedo = lerp(main_color, main_color + UNITY_ACCESS_INSTANCED_PROP(Props, _Color)*_Intensity, paint.r);
    25.             // Metallic and smoothness come from slider variables
    26.             o.Normal = UnpackNormal(tex2D(_BumpMap, IN.uv_MainTex));
    27.             o.Metallic = _Metallic;
    28.             o.Smoothness = _Glossiness;
    29.             o.Alpha = main_color.a;
    30.         }
    31.         ENDCG
    if i change
    Code (CSharp):
    1. UNITY_SAMPLE_TEX2DARRAY(_MyArr, float3(IN.uv_TextureArray, UNITY_ACCESS_INSTANCED_PROP(Props, _ID)));
    to
    Code (CSharp):
    1. UNITY_SAMPLE_TEX2DARRAY(_MyArr, float3(IN.uv_MainTex, UNITY_ACCESS_INSTANCED_PROP(Props, _ID)));
    i can see it work but in the wrong place.
     
  11. jister

    jister

    Joined:
    Oct 9, 2009
    Posts:
    1,749
    eurhm ok nevermind...
    documents say:
    "The input structure Input generally has any texture coordinates needed by the shader. Texture coordinates must be named “uv” followed by texture name (or start it with “uv2” to use second texture coordinate set)."
    changed
    Code (CSharp):
    1. uv_TextureArray
    to
    Code (CSharp):
    1. uv2_MyArr
    as in
    Code (CSharp):
    1. UNITY_DECLARE_TEX2DARRAY(_MyArr);