I’m creating a terrain shader for mobile. It uses texture arrays. In fragment shader I do this to blend multiple textures.
Shader "Test" {
Properties
{
_ctrlTx0("Control (RGBA)", 2D) = "red" {}
_ctrlTx1("Control (RGBA)", 2D) = "red" {}
_ctrlTxArr("Ctrl Array", 2DArray) = "black" {}
_albTxArr("Albedo Array", 2DArray) = "black" {}
_normTxArr("Normal Array", 2DArray) = "bump" {}
_sp0("Layer 3 (A)", 2D) = "white" {}
_nm0("nm 3 (A)", 2D) = "bump" {}
_sp1("Layer 3 (A)", 2D) = "white" {}
_nm1("Layer 3 (A)", 2D) = "bump" {}
_sp2("Layer 3 (A)", 2D) = "white" {}
_nm2("Layer 3 (A)", 2D) = "bump" {}
_sp3("Layer 3 (A)", 2D) = "white" {}
_nm3("Layer 3 (A)", 2D) = "bump" {}
_sp4("Layer 3 (A)", 2D) = "white" {}
_nm4("Layer 3 (A)", 2D) = "bump" {}
_sp5("Layer 3 (A)", 2D) = "white" {}
_nm5("Layer 3 (A)", 2D) = "bump" {}
_sp6("Layer 3 (A)", 2D) = "white" {}
_nm6("Layer 3 (A)", 2D) = "bump" {}
_sp7("Layer 3 (A)", 2D) = "white" {}
_nm7("Layer 3 (A)", 2D) = "bump" {}
// Props
_props0("Props 0", Vector) = (1,0,0,0)
_props1("Props 1", Vector) = (1,0,0,0)
_props2("Props 2", Vector) = (1,0,0,0)
_props3("Props 3", Vector) = (1,0,0,0)
_props4("Props 4", Vector) = (1,0,0,0)
_props5("Props 5", Vector) = (1,0,0,0)
_props6("Props 6", Vector) = (1,0,0,0)
_props7("Props 7", Vector) = (1,0,0,0)
_terrainSize("Terrain Size", Float) = 10000
_terrainScale("Terrain Scale", Float) = 1
_Shininess("Shininess", Range(0.03, 1)) = 0.078125
_SpecColor("Specular Color", Color) = (0.5, 0.5, 0.5, 1)
}
SubShader{
Tags{
"Queue" = "Geometry-99"
"RenderType" = "Opaque"
}
LOD 500
CGPROGRAM
#include "TestInclude.cginc"
#pragma target 3.5
#pragma debug
#pragma surface surf BlinnPhong vertex:vert noforwardadd noinstancing
void surf(Input IN, inout SurfaceOutput o)
{
float2 uv = IN.uuv_ctrlTx0;
half3 alb;
half3 norm;
half smooth, metal;
FastArray(uv, IN.uuv_sp0, IN.uuv_sp1, IN.uuv_sp2, IN.uuv_sp3, IN.uuv_sp4, IN.uuv_sp5, IN.uuv_sp6, alb, norm, metal, smooth);
o.Albedo = fixed3(alb);
o.Normal = fixed3(norm);
o.Gloss = fixed(smooth);
o.Specular = _Shininess;
}
ENDCG
}
}
The include file is:
struct Input
{
float2 uuv_sp0 : TEXCOORD0;
float2 uuv_sp1 : TEXCOORD1;
float2 uuv_sp2 : TEXCOORD2;
float2 uuv_sp3 : TEXCOORD3;
float2 uuv_sp4 : TEXCOORD4;
float2 uuv_sp5 : TEXCOORD5;
float2 uuv_sp6 : TEXCOORD6;
float2 uuv_ctrlTx0: TEXCOORD7;
};
struct appdata {
float4 vertex : POSITION;
float4 tangent : TANGENT;
float3 normal : NORMAL;
float2 texcoord : TEXCOORD0;
float4 texcoord1 : TEXCOORD1;
float4 texcoord2 : TEXCOORD2;
};
half _Shininess;
half4 _props0, _props1, _props2, _props3, _props4, _props5, _props6, _props7;
sampler2D _sp0, _sp1, _sp2, _sp3, _sp4, _sp5, _nm0, _nm1, _nm2, _nm3, _nm4, _nm5;
sampler2D _ctrlTx0, _ctrlTx1;
float _terrainSize, _terrainScale;
UNITY_DECLARE_TEX2DARRAY(_ctrlTxArr);
UNITY_DECLARE_TEX2DARRAY(_albTxArr);
UNITY_DECLARE_TEX2DARRAY(_normTxArr);
void FastArray(float2 uv, float2 uv0, float2 uv1, float2 uv2, float2 uv3, float2 uv4, float2 uv5, float2 uv6, out half3 alb, out half3 norm, out half metal, out half gloss) {
half4 ctrl0 = tex2D(_ctrlTx0, uv);
half4 ctrl1 = tex2D(_ctrlTx1, uv);
//half4 ctrl0 = UNITY_SAMPLE_TEX2DARRAY(_ctrlTxArr, float3(uv, 0));
//half4 ctrl1 = UNITY_SAMPLE_TEX2DARRAY(_ctrlTxArr, float3(uv, 1));
half4 sumNorm = 0;
alb = 0;
sumNorm += ctrl0.x * UNITY_SAMPLE_TEX2DARRAY(_normTxArr, float3(uv0, 0));
alb += ctrl0.x * UNITY_SAMPLE_TEX2DARRAY(_albTxArr, float3(uv0, 0));
sumNorm += ctrl0.y * UNITY_SAMPLE_TEX2DARRAY(_normTxArr, float3(uv1, 1));
alb += ctrl0.y * UNITY_SAMPLE_TEX2DARRAY(_albTxArr, float3(uv1, 1));
sumNorm += ctrl0.z * UNITY_SAMPLE_TEX2DARRAY(_normTxArr, float3(uv2, 2));
alb += ctrl0.z * UNITY_SAMPLE_TEX2DARRAY(_albTxArr, float3(uv2, 2));
sumNorm += ctrl0.w * UNITY_SAMPLE_TEX2DARRAY(_normTxArr, float3(uv3, 3));
alb += ctrl0.w * UNITY_SAMPLE_TEX2DARRAY(_albTxArr, float3(uv3, 3));
sumNorm += ctrl1.x * UNITY_SAMPLE_TEX2DARRAY(_normTxArr, float3(uv4, 4));
alb += ctrl1.x * UNITY_SAMPLE_TEX2DARRAY(_albTxArr, float3(uv4, 4));
sumNorm += ctrl1.y * UNITY_SAMPLE_TEX2DARRAY(_normTxArr, float3(uv5, 5));
alb += ctrl1.y * UNITY_SAMPLE_TEX2DARRAY(_albTxArr, float3(uv5, 5));
sumNorm += ctrl1.z * UNITY_SAMPLE_TEX2DARRAY(_normTxArr, float3(uv6, 6));
alb += ctrl1.z * UNITY_SAMPLE_TEX2DARRAY(_albTxArr, float3(uv6, 6));
sumNorm += ctrl1.w * UNITY_SAMPLE_TEX2DARRAY(_normTxArr, float3(uv6, 7));
alb += ctrl1.w * UNITY_SAMPLE_TEX2DARRAY(_albTxArr, float3(uv6, 7));
gloss = 0.2;
norm.xyz = sumNorm.xyz * 2 - 1;
norm.z = sqrt(1 - saturate(dot(norm.xy, norm.xy)));
metal = 0.2;
}
void vert(inout appdata v, out Input data)
{
UNITY_INITIALIZE_OUTPUT(Input, data);
float2 uv = v.texcoord;
data.uuv_ctrlTx0 = uv;
float2 ouv = (uv - 0.5) * _terrainSize;
data.uuv_sp0 = ouv / _props0.x;
data.uuv_sp1 = ouv / _props1.x;
data.uuv_sp2 = ouv / _props2.x;
data.uuv_sp3 = ouv / _props3.x;
data.uuv_sp4 = ouv / _props4.x;
data.uuv_sp5 = ouv / _props5.x;
data.uuv_sp6 = ouv / _props6.x;
v.tangent.xyz = cross(v.normal, float3(0, 0, 1));
v.tangent.w = -1;
}
Each texture has albedo and normal thus with 4 textures we sample 8 times. The strange thing is performance drops rapidly if more than four texture pairs are sampled.
8 samples =>24 fps
12 samples =>14 fps
16 samples =>7 fps
Why after 4 texture pairs (8 samples) from texture arrays performance drops this much?
Ordinary textures do not have this problems and 12 samples will give 20 fps.