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 );
}