Well, I have this triplanar shader:
Shader "Custom/z3nth10n/Tests/MultiTriplanar" {
Properties {
_MainTex ("Main Texture", 2D) = "white" { }
_Top ("Top Main Texture", 2DArray) = "" { }
_TopHeightmap ("Top Heightmap Texture", 2DArray) = "" { }
_TopNormal ("Top Normal Texture", 2DArray) = "" { }
_Side ("Side Main Texture", 2DArray) = "" { }
_SideHeightmap ("Side Heightmap Texture", 2DArray) = "" { }
_SideNormal ("Side Normal Texture", 2DArray) = "" { }
_Color ("Color", Color) = (1, 1, 1, 1)
_Glossiness ("Smoothness", Range(0, 1)) = 0.5
_Metallic ("Metallic", Range(0, 1)) = 0.0
_Occlusion ("Occlusion", Range(0, 1)) = 1.0
_Tiling ("Tiling", Float) = 0.5
}
SubShader {
Tags { "RenderType" = "Opaque" }
LOD 200
Offset[_ZOffset], [_ZOffset]
CGPROGRAM
#pragma surface surf Standard vertex:vert
#pragma vertex vert
#pragma require 2darray
#pragma target 3.5
#include "UnityCG.cginc"
sampler2D _MainTex;
UNITY_DECLARE_TEX2DARRAY(_Top);
UNITY_DECLARE_TEX2DARRAY(_Side);
UNITY_DECLARE_TEX2DARRAY(_TopHeightmap);
UNITY_DECLARE_TEX2DARRAY(_SideHeightmap);
UNITY_DECLARE_TEX2DARRAY(_TopNormal);
UNITY_DECLARE_TEX2DARRAY(_SideNormal);
struct Input {
float2 uv_MainTex;
float3 worldPos;
float3 worldNormal;
INTERNAL_DATA
};
float4 _MainTex_TexelSize;
float _DisplacementStrength;
float _DisplacementStrength2;
half _Glossiness, _Metallic, _Tiling, _Occlusion;
fixed4 _Color;
void vert(inout appdata_full v, out Input o) {
UNITY_INITIALIZE_OUTPUT(Input, o);
o.worldPos = v.texcoord;
o.worldNormal = v.normal;
}
float3 getAlbedo(Input IN, int arrayIndex) {
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;
}
void surf(Input IN, inout SurfaceOutputStandard o) {
// https://gamedev.stackexchange.com/a/186384/76780
float2 rightNeighbour = IN.uv_MainTex + float2(_MainTex_TexelSize.x, 0);
float2 leftNeighbour = IN.uv_MainTex - float2(_MainTex_TexelSize.x, 0);
float2 topNeighbour = IN.uv_MainTex + float2(0, _MainTex_TexelSize.y);
float2 bottomNeighbour = IN.uv_MainTex - float2(0, _MainTex_TexelSize.y);
float4 texCenter = tex2D(_MainTex, IN.uv_MainTex);
float4 texRight = tex2D(_MainTex, rightNeighbour);
float4 texLeft = tex2D(_MainTex, leftNeighbour);
float4 texTop = tex2D(_MainTex, topNeighbour);
float4 texBottom = tex2D(_MainTex, bottomNeighbour);
int arrayIndex0 = min(255, max(floor(texCenter.a * 255), 0));
int arrayIndex1 = min(255, max(floor(texRight.a * 255), 0));
int arrayIndex2 = min(255, max(floor(texLeft.a * 255), 0));
int arrayIndex3 = min(255, max(floor(texTop.a * 255), 0));
int arrayIndex4 = min(255, max(floor(texBottom.a * 255), 0));
float3 albedo0 = getAlbedo(IN, arrayIndex0);
float3 albedo1 = getAlbedo(IN, arrayIndex1);
float3 albedo2 = getAlbedo(IN, arrayIndex2);
float3 albedo3 = getAlbedo(IN, arrayIndex3);
float3 albedo4 = getAlbedo(IN, arrayIndex4);
o.Albedo =
(albedo0.rgb * _Color) * 0.2 +
(albedo1.rgb * _Color) * 0.2 +
(albedo2.rgb * _Color) * 0.2 +
(albedo3.rgb * _Color) * 0.2 +
(albedo4.rgb * _Color) * 0.2;
o.Metallic = _Metallic;
o.Smoothness = _Glossiness;
o.Occlusion = _Occlusion;
}
ENDCG
}
FallBack "Diffuse"
}
As you can see, I linked this answer which gives me the solution to get the neighbor UVs. The idea behind this is that I could get the different arrayIndexes from the main texture (from their alpha channel) by looking up from their 4 neighbor and mixing their rgb (by multiplying per 0.2 or the same that dividing it by 5, because we have the center texture + 4 neighbors).
I would like to change this part, by smoothing it.
o.Albedo =
(albedo0.rgb * _Color) * 0.2 +
(albedo1.rgb * _Color) * 0.2 +
(albedo2.rgb * _Color) * 0.2 +
(albedo3.rgb * _Color) * 0.2 +
(albedo4.rgb * _Color) * 0.2;
Because of this result:
I would like to smooth these transitions, they are too "square". I tried to use UVs rotation/displacement, in the vert function:
float random(float2 uv) {
return frac(sin(dot(uv, float2(12.9898, 78.233))) * 43758.5453123);
}
Vert function:
float r = random(v.texcoord);
float sinX = sin(r * _DisplacementStrength);
float cosX = cos(r * _DisplacementStrength);
float sinY = sin(r * _DisplacementStrength);
float2x2 rotationMatrix = float2x2(cosX, -sinX, sinY, cosX);
v.texcoord.xy = frac(mul(v.texcoord.xy, rotationMatrix);
But this outputs this:
It is useful, but I still can see the different albedos being mixed. How could I smooth these transitions?

