Unable to define/use my own macro on HLSL Unity3D (951902)

I defined a macro like: #define UNITY_SAMPLE_TEX2DARRAY_GRAD(tex, coord, dx, dy) tex.SampleGrad(sampler##tex, coord, dx, dy) from this topic which @bgolus answered

To be used on this code which is part from Iñigo Quilez textureNoTile tutorial, which I’m porting to Unity to be used with Texture2DArrays

fixed3 textureArrayNoTileNormal( UNITY_ARGS_TEX2DARRAY(texArray), in NoTileUVs ntuvs, in half normalScale )
{
    // Use modified UVs to sample a normal map, also inverting red and green channels where needed due to mirroring
    return lerp( lerp( fixed3( ntuvs.ofa.z, ntuvs.ofa.w, 1 ) * UnpackNormalWithScale( UNITY_SAMPLE_TEX2DARRAY_GRAD( UNITY_PASS_TEX2DARRAY(texArray), ntuvs.uva, ntuvs.ddxa, ntuvs.ddya ), normalScale ),
                       fixed3( ntuvs.ofb.z, ntuvs.ofb.w, 1 ) * UnpackNormalWithScale( UNITY_SAMPLE_TEX2DARRAY_GRAD( UNITY_PASS_TEX2DARRAY(texArray), ntuvs.uvb, ntuvs.ddxb, ntuvs.ddyb ), normalScale ), ntuvs.b.x ),
                 lerp( fixed3( ntuvs.ofc.z, ntuvs.ofc.w, 1 ) * UnpackNormalWithScale( UNITY_SAMPLE_TEX2DARRAY_GRAD( UNITY_PASS_TEX2DARRAY(texArray), ntuvs.uvc, ntuvs.ddxc, ntuvs.ddyc ), normalScale ),
                       fixed3( ntuvs.ofd.z, ntuvs.ofd.w, 1 ) * UnpackNormalWithScale( UNITY_SAMPLE_TEX2DARRAY_GRAD( UNITY_PASS_TEX2DARRAY(texArray), ntuvs.uvd, ntuvs.ddxd, ntuvs.ddyd ), normalScale ), ntuvs.b.x ), ntuvs.b.y );
}

The following error prompts: Unexpected token '('. Expected one of: ',' ')' at Assets/Resources/Shaders/Terrain/textureNoTile.cginc(93)

I have two questions:

  • Can I see the character position where the errors occur? on Unity3D)
  • I understand that is caused because tex.SampleGrad isn’t allowed,
    but why? 'm running under DX11.

Also, behind the code above I have these conditions:

#if defined(SHADER_API_D3D11) || defined(SHADER_API_XBOXONE) || defined(SHADER_API_GLES3) || defined(SHADER_API_GLCORE)
    #define UNITY_SAMPLE_TEX2DARRAY_GRAD(tex, coord, dx, dy) tex.SampleGrad(sampler##tex, coord, dx, dy)
#else
    #if defined(UNITY_COMPILER_HLSL2GLSL) || defined(SHADER_TARGET_SURFACE_ANALYSIS)
        #define UNITY_SAMPLE_TEX2DARRAY_GRAD(tex, coord, dx, dy) tex2DArray(tex, coord, dx, dy)
    #endif
#endif

But if I use this code, then I’m unable to use the function because the undeclared identifier UNITY_SAMPLE_TEX2DARRAY_GRAD error prompts, why? Don’t I meet any of the defined preprocessor directives? How can I check them in Unity3D?

I don’t think that’s the case. Check the balance of ‘(’ and ‘)’ in your code.

Hello,

The balance of (…) is correct, as the IDE suggest here, you can see the starting and final parenthesis correctly colored in brown:

I see.

I just noticed this - this means UNITY_SAMPLE_TEX2DARRAY_GRAD is actually not defined.

UNITY_COMPILER_HLSL2GLSL is not in use for a very long time already, so the second condition will only be true when importing a surface shader, but not during shader compilation. So if your shader is being compiled for any graphics API that is not listed in the first condition, you get this error about it being an undeclared identifier.

Ye, I see, but now the error is this: undeclared identifier ‘tex2DArray’ at Assets/Resources/Shaders/Terrain/textureNoTile.cginc(88) (on d3d11)

Maybe some of the other preprocessor directives are also missing?

defined(SHADER_API_D3D11) || defined(SHADER_API_XBOXONE) || defined(SHADER_API_GLES3) || defined(SHADER_API_GLCORE)

I’ll test.

What are you trying to achieve with these conditionals? Just make the surface shader compile, or something else?

I tried this, it compiles:

#if defined(SHADER_TARGET_SURFACE_ANALYSIS)
#define UNITY_SAMPLE_TEX2DARRAY_GRAD(tex, coord, dx, dy) 0
#else
#define UNITY_SAMPLE_TEX2DARRAY_GRAD(tex, coord, dx, dy) tex.SampleGrad(sampler##tex, coord, dx, dy)
#endif

What I’m trying to do is to convert this Iñigo Quilez shader to be used with texture2DArrays

What’s the error you’re getting?

It was the red one was failing, now compiles, I was passing too many arguments to the lerp function. Now works. Thanks

The point is that the shader isn’t working as expected. Idk if I need to create a new topic or if I can continue this one.

Maybe I should continue this one because of the migration (at least, this one won’t be deleted)

It should be shown as this.

But, it shows like this:

I’m unsure what I should check because I’m unable to check the initialization. I don’t how can I debug or which values should I expect to have.

        float3 getAlbedo(Input IN, UNITY_ARGS_TEX2DARRAY(side), UNITY_ARGS_TEX2DARRAY(top), int arrayIndex, float2x2 rotationMatrix) {
            // @todo: lod
            NoTileUVs ntuvs0 = textureNoTileCalcUVs(frac(IN.worldPos.zy * _Tiling));
            NoTileUVs ntuvs1 = textureNoTileCalcUVs(frac(IN.worldPos.zx * _Tiling));
            NoTileUVs ntuvs2 = textureNoTileCalcUVs(frac(IN.worldPos.xy * _Tiling));
          
            float3 xAlbedo = textureNoTile(UNITY_PASS_TEX2DARRAY(side), ntuvs0, arrayIndex) * abs(IN.worldNormal.x);
            float3 yAlbedo = textureNoTile(UNITY_PASS_TEX2DARRAY(top), ntuvs1, arrayIndex) * abs(IN.worldNormal.y);
            float3 zAlbedo = textureNoTile(UNITY_PASS_TEX2DARRAY(side), ntuvs2, arrayIndex) * abs(IN.worldNormal.z);

            //float3 xAlbedo = UNITY_SAMPLE_TEX2DARRAY(side, float3(frac(IN.worldPos.zy * _Tiling), arrayIndex)) * abs(IN.worldNormal.x);
            //float3 yAlbedo = UNITY_SAMPLE_TEX2DARRAY(top, float3(frac(IN.worldPos.zx * _Tiling), arrayIndex)) * abs(IN.worldNormal.y);
            //float3 zAlbedo = UNITY_SAMPLE_TEX2DARRAY(side, float3(frac(IN.worldPos.xy * _Tiling), arrayIndex)) * abs(IN.worldNormal.z);

            float3 projNormal = saturate(pow(IN.worldNormal * 1.4, 4));

            float3 texAlbedo = zAlbedo;
            texAlbedo = lerp(texAlbedo, xAlbedo, projNormal.x);
            texAlbedo = lerp(texAlbedo, yAlbedo, projNormal.y);

            return texAlbedo;
        }

There is the call I do, the commented part is the original one. This are the translated calls:

fixed4 textureNoTile( UNITY_ARGS_TEX2DARRAY(texArray), in NoTileUVs ntuvs, in int arrayIndex )
{
    // Use modified UVs to sample a texture
    return lerp( lerp( UNITY_SAMPLE_TEX2DARRAY_GRAD( texArray, float3(ntuvs.uva, arrayIndex), ntuvs.ddxa, ntuvs.ddya ),
                       UNITY_SAMPLE_TEX2DARRAY_GRAD( texArray, float3(ntuvs.uvb, arrayIndex), ntuvs.ddxb, ntuvs.ddyb ), ntuvs.b.x ),
                 lerp( UNITY_SAMPLE_TEX2DARRAY_GRAD( texArray, float3(ntuvs.uvc, arrayIndex), ntuvs.ddxc, ntuvs.ddyc ),
                       UNITY_SAMPLE_TEX2DARRAY_GRAD( texArray, float3(ntuvs.uvd, arrayIndex), ntuvs.ddxd, ntuvs.ddyd ), ntuvs.b.x ), ntuvs.b.y );
}

fixed3 textureArrayNoTileNormal( UNITY_ARGS_TEX2DARRAY(texArray), in NoTileUVs ntuvs, in half normalScale, in int arrayIndex )
{
    // Use modified UVs to sample a normal map, also inverting red and green channels where needed due to mirroring
    return lerp( lerp( fixed3( ntuvs.ofa.z, ntuvs.ofa.w, 1 ) * UnpackNormalWithScale( UNITY_SAMPLE_TEX2DARRAY_GRAD( texArray, float3(ntuvs.uva, arrayIndex), ntuvs.ddxa, ntuvs.ddya ), normalScale ),
                       fixed3( ntuvs.ofb.z, ntuvs.ofb.w, 1 ) * UnpackNormalWithScale( UNITY_SAMPLE_TEX2DARRAY_GRAD( texArray, float3(ntuvs.uvb, arrayIndex), ntuvs.ddxb, ntuvs.ddyb ), normalScale ), ntuvs.b.x ),
                 lerp( fixed3( ntuvs.ofc.z, ntuvs.ofc.w, 1 ) * UnpackNormalWithScale( UNITY_SAMPLE_TEX2DARRAY_GRAD( texArray, float3(ntuvs.uvc, arrayIndex), ntuvs.ddxc, ntuvs.ddyc ), normalScale ),
                       fixed3( ntuvs.ofd.z, ntuvs.ofd.w, 1 ) * UnpackNormalWithScale( UNITY_SAMPLE_TEX2DARRAY_GRAD( texArray, float3(ntuvs.uvd, arrayIndex), ntuvs.ddxd, ntuvs.ddyd ), normalScale ), ntuvs.b.x ), ntuvs.b.y );
}

What should I do?

One of the differences in the screenshots is the checkbox for Draw alpha is checked on one and not checked on another.
If that just controls the display in the top left, I guess you should proceed with debugging the shader.

I did another two shaders in order to see how they work:

The left one is one that uses a sampler2D/Texture2D and the right one is the one that uses a texture2DArray.

I cans hare them:

Shader "Custom/z3nth10n/Tests/2DArray_TextureNoTile_Array" {
    Properties {
        _MainTex ("Main Texture", 2DArray) = "" { }
        _Tiling ("Tiling", Float) = 0.5
        _Color ("Color", Color) = (1, 1, 1, 1)
        _DoDistortion ("Do Distortion", Range(0, 1)) = 0
        _ArrayIndex ("Array Index", Range(0, 2)) = 0
    }
   
    SubShader {
        Tags { "RenderType" = "Opaque" }
        LOD 200
        Offset[_ZOffset], [_ZOffset]

        CGPROGRAM
        #pragma surface surf Standard vertex:vert
        #pragma require 2darray
        #pragma target 3.5

        #define numTextures 24
       
        #include "UnityCG.cginc"
        #include "../textureNoTile.cginc"
       
        UNITY_DECLARE_TEX2DARRAY(_MainTex);

        half _Tiling;
        fixed4 _Color;
        int _DoDistortion;
        int _ArrayIndex;

        struct Input {
            float2 uv_MainTex;
            float3 worldPos;
            float3 worldNormal;

            // https://discussions.unity.com/t/683469/4
            float3 texcoord_MainTex;

            INTERNAL_DATA
        };

        void vert(inout appdata_full v, out Input o) {
            UNITY_INITIALIZE_OUTPUT(Input, o);

            o.worldPos = v.texcoord;
            o.worldNormal = v.normal;
        }

        void surf(Input IN, inout SurfaceOutputStandard o) {
            if (_DoDistortion == 1) {
                NoTileUVs ntuvs0 = textureNoTileCalcUVs(IN.worldPos * _Tiling);
                float3 albedo = textureNoTile(UNITY_PASS_TEX2DARRAY(_MainTex), ntuvs0, _ArrayIndex); // * abs(IN.worldNormal.x);
                o.Albedo = albedo.rgb * _Color;
            } else {
                o.Albedo = UNITY_SAMPLE_TEX2DARRAY(_MainTex, float3(frac(IN.worldPos.zx * _Tiling), _ArrayIndex));
            }
        }
        ENDCG
    }
    FallBack "Diffuse"
}
Shader "Custom/z3nth10n/Tests/TextureNoTile" {
    Properties {
        _MainTex ("Main Texture", 2D) = "white" { }
        _Tiling ("Tiling", Float) = 0.5
        _Color ("Color", Color) = (1, 1, 1, 1)
        _DoDistortion ("Do Distortion", Range(0, 1)) = 0
    }
   
    SubShader {
        Tags { "RenderType" = "Opaque" }
        LOD 200
        Offset[_ZOffset], [_ZOffset]

        CGPROGRAM
        #pragma surface surf Standard vertex:vert
        #pragma require 2darray
        #pragma target 3.5

        #define numTextures 24
       
        #include "UnityCG.cginc"
        #include "../textureNoTile.cginc"
       
        sampler2D _MainTex;
        half _Tiling;
        fixed4 _Color;
        int _DoDistortion;

        struct Input {
            float2 uv_MainTex;
            float3 worldPos;
            float3 worldNormal;

            // https://discussions.unity.com/t/683469/4
            float3 texcoord_MainTex;

            INTERNAL_DATA
        };

        void vert(inout appdata_full v, out Input o) {
            UNITY_INITIALIZE_OUTPUT(Input, o);

            o.worldPos = v.texcoord;
            o.worldNormal = v.normal;
        }

        void surf(Input IN, inout SurfaceOutputStandard o) {
            if (_DoDistortion == 1) {
                NoTileUVs ntuvs0 = textureNoTileCalcUVs(IN.worldPos * _Tiling);
                float3 albedo = textureNoTile(_MainTex, ntuvs0); //  * abs(IN.worldNormal.x);
                o.Albedo = albedo.rgb * _Color;
            } else {
                o.Albedo = tex2D(_MainTex, IN.worldPos * _Tiling);
            }
        }
        ENDCG
    }
    FallBack "Diffuse"
}

CGINC:

// UNITY_SAMPLE_TEX2DARRAY_GRAD from https://discussions.unity.com/t/633594/7
#if defined(SHADER_TARGET_SURFACE_ANALYSIS)
   #define UNITY_SAMPLE_TEX2DARRAY_GRAD(tex, coord, dx, dy) 0
#else
   #define UNITY_SAMPLE_TEX2DARRAY_GRAD(tex, coord, dx, dy) tex.SampleGrad(sampler##tex, coord, dx, dy)
#endif

// The MIT License (MIT) (see LICENSE.txt)
// Copyright © 2015 Inigo Quilez
// Copyright © 2021 Jens Neitzel
// Copyright © z3nth10n: implementing texture arrays

// One simple way to avoid texture tile repetition, at the cost of 4 times the amount of
// texture lookups (still much better than https://www.shadertoy.com/view/4tsGzf)
//
// More info: http://www.iquilezles.org/www/articles/texturerepetition/texturerepetition.htm

struct NoTileUVs
{
    fixed4 ofa, ofb, ofc, ofd;
    fixed2 uva, uvb, uvc, uvd, b;
    fixed2 ddxa, ddxb, ddxc, ddxd;
    fixed2 ddya, ddyb, ddyc, ddyd;
};

fixed4 hash4( fixed2 p ) { return frac(sin(fixed4( 1.0 + dot(p, fixed2(37.0, 17.0)),
                                                   2.0 + dot(p, fixed2(11.0, 47.0)),
                                                   3.0 + dot(p, fixed2(41.0, 29.0)),
                                                   4.0 + dot(p, fixed2(23.0, 31.0)))) * 103.0); }

NoTileUVs textureNoTileCalcUVs( in fixed2 uv )
{
    NoTileUVs ntuvs;
    fixed2 iuv = floor( uv );
    fixed2 fuv = frac( uv );

    // generate per-tile transform
    ntuvs.ofa = hash4( iuv + fixed2(0, 0) );
    ntuvs.ofb = hash4( iuv + fixed2(1, 0) );
    ntuvs.ofc = hash4( iuv + fixed2(0, 1) );
    ntuvs.ofd = hash4( iuv + fixed2(1, 1) );

    fixed2 uvddx = ddx( uv );
    fixed2 uvddy = ddy( uv );

    // transform per-tile uvs
    ntuvs.ofa.zw = sign(ntuvs.ofa.zw - 0.5);
    ntuvs.ofb.zw = sign(ntuvs.ofb.zw - 0.5);
    ntuvs.ofc.zw = sign(ntuvs.ofc.zw - 0.5);
    ntuvs.ofd.zw = sign(ntuvs.ofd.zw - 0.5);

    // uv's, and derivatives (for correct mipmapping)
    ntuvs.uva = uv*ntuvs.ofa.zw + ntuvs.ofa.xy; ntuvs.ddxa = uvddx * ntuvs.ofa.zw; ntuvs.ddya = uvddy * ntuvs.ofa.zw;
    ntuvs.uvb = uv*ntuvs.ofb.zw + ntuvs.ofb.xy; ntuvs.ddxb = uvddx * ntuvs.ofb.zw; ntuvs.ddyb = uvddy * ntuvs.ofb.zw;
    ntuvs.uvc = uv*ntuvs.ofc.zw + ntuvs.ofc.xy; ntuvs.ddxc = uvddx * ntuvs.ofc.zw; ntuvs.ddyc = uvddy * ntuvs.ofc.zw;
    ntuvs.uvd = uv*ntuvs.ofd.zw + ntuvs.ofd.xy; ntuvs.ddxd = uvddx * ntuvs.ofd.zw; ntuvs.ddyd = uvddy * ntuvs.ofd.zw;

    // fetch and blend
    ntuvs.b = smoothstep(0.25, 0.75, fuv);

    return ntuvs;
}

fixed4 textureNoTile( sampler2D samp, in NoTileUVs ntuvs )
{
    // Use modified UVs to sample a texture
    return lerp( lerp( tex2D( samp, ntuvs.uva, ntuvs.ddxa, ntuvs.ddya ),
                       tex2D( samp, ntuvs.uvb, ntuvs.ddxb, ntuvs.ddyb ), ntuvs.b.x ),
                 lerp( tex2D( samp, ntuvs.uvc, ntuvs.ddxc, ntuvs.ddyc ),
                       tex2D( samp, ntuvs.uvd, ntuvs.ddxd, ntuvs.ddyd ), ntuvs.b.x ), ntuvs.b.y );
}

fixed3 textureNoTileNormal( sampler2D sampNorm, in NoTileUVs ntuvs, in half normalScale )
{
    // Use modified UVs to sample a normal map, also inverting red and green channels where needed due to mirroring
    return lerp( lerp( fixed3( ntuvs.ofa.z, ntuvs.ofa.w, 1 ) * UnpackNormalWithScale( tex2D( sampNorm, ntuvs.uva, ntuvs.ddxa, ntuvs.ddya ), normalScale ),
                       fixed3( ntuvs.ofb.z, ntuvs.ofb.w, 1 ) * UnpackNormalWithScale( tex2D( sampNorm, ntuvs.uvb, ntuvs.ddxb, ntuvs.ddyb ), normalScale ), ntuvs.b.x ),
                 lerp( fixed3( ntuvs.ofc.z, ntuvs.ofc.w, 1 ) * UnpackNormalWithScale( tex2D( sampNorm, ntuvs.uvc, ntuvs.ddxc, ntuvs.ddyc ), normalScale ),
                       fixed3( ntuvs.ofd.z, ntuvs.ofd.w, 1 ) * UnpackNormalWithScale( tex2D( sampNorm, ntuvs.uvd, ntuvs.ddxd, ntuvs.ddyd ), normalScale ), ntuvs.b.x ), ntuvs.b.y );
}

fixed4 textureNoTile( UNITY_ARGS_TEX2DARRAY(texArray), in NoTileUVs ntuvs, in int arrayIndex )
{
    // Use modified UVs to sample a texture
    return lerp( lerp( UNITY_SAMPLE_TEX2DARRAY_GRAD( texArray, float3(ntuvs.uva, arrayIndex), ntuvs.ddxa, ntuvs.ddya ),
                       UNITY_SAMPLE_TEX2DARRAY_GRAD( texArray, float3(ntuvs.uvb, arrayIndex), ntuvs.ddxb, ntuvs.ddyb ), ntuvs.b.x ),
                 lerp( UNITY_SAMPLE_TEX2DARRAY_GRAD( texArray, float3(ntuvs.uvc, arrayIndex), ntuvs.ddxc, ntuvs.ddyc ),
                       UNITY_SAMPLE_TEX2DARRAY_GRAD( texArray, float3(ntuvs.uvd, arrayIndex), ntuvs.ddxd, ntuvs.ddyd ), ntuvs.b.x ), ntuvs.b.y );
}

fixed3 textureArrayNoTileNormal( UNITY_ARGS_TEX2DARRAY(texArray), in NoTileUVs ntuvs, in half normalScale, in int arrayIndex )
{
    // Use modified UVs to sample a normal map, also inverting red and green channels where needed due to mirroring
    return lerp( lerp( fixed3( ntuvs.ofa.z, ntuvs.ofa.w, 1 ) * UnpackNormalWithScale( UNITY_SAMPLE_TEX2DARRAY_GRAD( texArray, float3(ntuvs.uva, arrayIndex), ntuvs.ddxa, ntuvs.ddya ), normalScale ),
                       fixed3( ntuvs.ofb.z, ntuvs.ofb.w, 1 ) * UnpackNormalWithScale( UNITY_SAMPLE_TEX2DARRAY_GRAD( texArray, float3(ntuvs.uvb, arrayIndex), ntuvs.ddxb, ntuvs.ddyb ), normalScale ), ntuvs.b.x ),
                 lerp( fixed3( ntuvs.ofc.z, ntuvs.ofc.w, 1 ) * UnpackNormalWithScale( UNITY_SAMPLE_TEX2DARRAY_GRAD( texArray, float3(ntuvs.uvc, arrayIndex), ntuvs.ddxc, ntuvs.ddyc ), normalScale ),
                       fixed3( ntuvs.ofd.z, ntuvs.ofd.w, 1 ) * UnpackNormalWithScale( UNITY_SAMPLE_TEX2DARRAY_GRAD( texArray, float3(ntuvs.uvd, arrayIndex), ntuvs.ddxd, ntuvs.ddyd ), normalScale ), ntuvs.b.x ), ntuvs.b.y );
}