Thanks for helping guide me here. Gave that a try. Here is pretty much the complete preprocessed code (lines 39-41, 52-53 are the relevant ones):
Texture2D _SplatTileNormalTex;
SamplerState sampler_SplatTileNormalTex;
Texture2D _SplatTex;
SamplerState sampler_SplatTex;
Texture2D _WorldTangentTex;
SamplerState sampler_WorldTangentTex;
Texture2D _WorldBinormalTex;
SamplerState sampler_WorldBinormalTex;
cbuffer SplatShaderLitBuffer {
float4 _SplatTileNormalTex_ST;
float _SplatTileBump;
float _SplatEdgeBump;
float _SplatEdgeBumpWidth;
float4 _SplatTex_ST;
float4 _SplatTex_TexelSize;
};
struct Attributes
{
float4 positionOS : POSITION;
float3 normalOS : NORMAL;
float4 tangentOS : TANGENT;
float2 uv : TEXCOORD0;
float2 uvLM : TEXCOORD1;
};
struct Varyings
{
float2 uv : TEXCOORD0;
float2 uvLM : TEXCOORD1;
float4 positionWSAndFogFactor : TEXCOORD2;
half3 normalWS : TEXCOORD3;
half3 tangentWS : TEXCOORD4;
half3 bitangentWS : TEXCOORD5;
float2 uv_SplatTex : TEXCOORD7;
float4 positionCS : SV_POSITION;
};
void ComputeSplat (out float4 splatMask, out half3 splatNormal, float2 uv_SplatTex, half3 tangentWS, half3 binormalWS)
{
float4 splatSDF = _SplatTex . Sample (sampler_SplatTex, uv_SplatTex);
float4 splatSDFx = _SplatTex . Sample (sampler_SplatTex, uv_SplatTex + float2 (_SplatTex_TexelSize . x, 0));
float4 splatSDFy = _SplatTex . Sample (sampler_SplatTex, uv_SplatTex + float2 (0, _SplatTex_TexelSize . y));
half splatDDX = length (ddx (uv_SplatTex * _SplatTex_TexelSize . zw));
half splatDDY = length (ddy (uv_SplatTex * _SplatTex_TexelSize . zw));
half clipDist = sqrt (splatDDX * splatDDX + splatDDY * splatDDY);
half clipDistHard = max (clipDist * 0.01, 0.01);
half clipDistSoft = 0.01 * _SplatEdgeBumpWidth;
static const float _Clip = 0.5;
splatMask = smoothstep ((_Clip - 0.01) - clipDistHard, (_Clip - 0.01) + clipDistHard, splatSDF);
float splatMaskTotal = max (max (splatMask . x, splatMask . y), max (splatMask . z, splatMask . w));
float4 splatMaskInside = smoothstep (_Clip - clipDistSoft, _Clip + clipDistSoft, splatSDF);
splatMaskInside = max (max (splatMaskInside . x, splatMaskInside . y), max (splatMaskInside . z, splatMaskInside . w));
float4 offsetSplatX = splatSDF - splatSDFx;
float4 offsetSplatY = splatSDF - splatSDFy;
float2 offsetSplat = lerp (float2 (offsetSplatX . x, offsetSplatY . x), float2 (offsetSplatX . y, offsetSplatY . y), splatMask . y);
offsetSplat = lerp (offsetSplat, float2 (offsetSplatX . z, offsetSplatY . z), splatMask . z);
offsetSplat = lerp (offsetSplat, float2 (offsetSplatX . w, offsetSplatY . w), splatMask . w);
offsetSplat = normalize (float3 (offsetSplat, 0.0001)) . xy;
offsetSplat = offsetSplat * (1.0 - splatMaskInside) * _SplatEdgeBump;
float2 splatTileNormalTex = _SplatTileNormalTex . Sample (sampler_SplatTileNormalTex, uv_SplatTex * 10.0) . xy;
offsetSplat += (splatTileNormalTex . xy - 0.5) * _SplatTileBump * 0.2;
float3 worldTangentTex = _WorldTangentTex . Sample (sampler_WorldTangentTex, uv_SplatTex) . xyz * 2.0 - 1.0;
float3 worldBinormalTex = _WorldBinormalTex . Sample (sampler_WorldBinormalTex, uv_SplatTex) . xyz * 2.0 - 1.0;
float3 offsetSplatWorld = offsetSplat . x * worldTangentTex + offsetSplat . y * worldBinormalTex;
float2 offsetSplatLocal = 0;
offsetSplatLocal . x = dot (tangentWS, offsetSplatWorld);
offsetSplatLocal . y = dot (binormalWS, offsetSplatWorld);
splatNormal = offsetSplatWorld * splatMaskTotal;
}
Varyings LitPassVertex (Attributes input)
{
Varyings output;
VertexPositionInputs vertexInput = GetVertexPositionInputs (input . positionOS . xyz);
VertexNormalInputs vertexNormalInput = GetVertexNormalInputs (input . normalOS, input . tangentOS);
float fogFactor = ComputeFogFactor (vertexInput . positionCS . z);
output . uv = ((input . uv . xy) * _BaseMap_ST . xy + _BaseMap_ST . zw);
output . uvLM = input . uvLM . xy * unity_LightmapST . xy + unity_LightmapST . zw;
output . uv_SplatTex = ((input . uvLM . xy) * _SplatTex_ST . xy + _SplatTex_ST . zw);
output . positionWSAndFogFactor = float4 (vertexInput . positionWS, fogFactor);
output . normalWS = vertexNormalInput . normalWS;
output . tangentWS = vertexNormalInput . tangentWS;
output . bitangentWS = vertexNormalInput . bitangentWS;
output . positionCS = vertexInput . positionCS;
return output;
}
half4 LitPassFragment (Varyings input) : SV_Target
{
SurfaceData surfaceData;
InitializeStandardLitSurfaceData (input . uv, surfaceData);
float4 splatMask;
half3 splatNormal;
ComputeSplat (splatMask, splatNormal, input . uv_SplatTex, input . tangentWS, input . bitangentWS);
float3 splatAlbedo = surfaceData . albedo;
splatAlbedo = lerp (splatAlbedo, float3 (1.0, 0.5, 0.0), splatMask . x);
splatAlbedo = lerp (splatAlbedo, float3 (1.0, 0.0, 0.0), splatMask . y);
splatAlbedo = lerp (splatAlbedo, float3 (0.0, 1.0, 0.0), splatMask . z);
splatAlbedo = lerp (splatAlbedo, float3 (0.0, 0.0, 1.0), splatMask . w);
half3 normalWS = TransformTangentToWorld (surfaceData . normalTS,
half3x3 (input . tangentWS, input . bitangentWS, input . normalWS));
normalWS = normalize (normalWS + splatNormal);
half3 bakedGI = SampleSH (normalWS);
float3 positionWS = input . positionWSAndFogFactor . xyz;
half3 viewDirectionWS = SafeNormalize (GetCameraPositionWS () - positionWS);
BRDFData brdfData;
InitializeBRDFData (splatAlbedo, surfaceData . metallic, surfaceData . specular, surfaceData . smoothness, surfaceData . alpha, brdfData);
Light mainLight = GetMainLight ();
half3 color = GlobalIllumination (brdfData, bakedGI, surfaceData . occlusion, normalWS, viewDirectionWS);
color += LightingPhysicallyBased (brdfData, mainLight, normalWS, viewDirectionWS);
color += surfaceData . emission;
float fogFactor = input . positionWSAndFogFactor . w;
color = MixFog (color, fogFactor);
return half4 (color, surfaceData . alpha);
}
ComputeSplat() gets called from the fragment shader and right at the beginning the texture is sampled. Looks pretty straightforward to me.
The original shader once preprocessed looks like this:
void surf (Input IN, inout SurfaceOutputStandard o) {
float4 splatSDF = tex2D (_SplatTex, IN . uv2_SplatTex);
float4 splatSDFx = tex2D (_SplatTex, IN . uv2_SplatTex + float2 (_SplatTex_TexelSize . x, 0));
float4 splatSDFy = tex2D (_SplatTex, IN . uv2_SplatTex + float2 (0, _SplatTex_TexelSize . y));
half splatDDX = length (ddx (IN . uv2_SplatTex * _SplatTex_TexelSize . zw));
half splatDDY = length (ddy (IN . uv2_SplatTex * _SplatTex_TexelSize . zw));
half clipDist = sqrt (splatDDX * splatDDX + splatDDY * splatDDY);
half clipDistHard = max (clipDist * 0.01, 0.01);
half clipDistSoft = 0.01 * _SplatEdgeBumpWidth;
float4 splatMask = smoothstep ((_Clip - 0.01) - clipDistHard, (_Clip - 0.01) + clipDistHard, splatSDF);
float splatMaskTotal = max (max (splatMask . x, splatMask . y), max (splatMask . z, splatMask . w));
float4 splatMaskInside = smoothstep (_Clip - clipDistSoft, _Clip + clipDistSoft, splatSDF);
splatMaskInside = max (max (splatMaskInside . x, splatMaskInside . y), max (splatMaskInside . z, splatMaskInside . w));
float4 offsetSplatX = splatSDF - splatSDFx;
float4 offsetSplatY = splatSDF - splatSDFy;
float2 offsetSplat = lerp (float2 (offsetSplatX . x, offsetSplatY . x), float2 (offsetSplatX . y, offsetSplatY . y), splatMask . y);
offsetSplat = lerp (offsetSplat, float2 (offsetSplatX . z, offsetSplatY . z), splatMask . z);
offsetSplat = lerp (offsetSplat, float2 (offsetSplatX . w, offsetSplatY . w), splatMask . w);
offsetSplat = normalize (float3 (offsetSplat, 0.0001)) . xy;
offsetSplat = offsetSplat * (1.0 - splatMaskInside) * _SplatEdgeBump;
float3 worldTangentTex = tex2D (_WorldTangentTex, IN . uv2_SplatTex) . xyz * 2.0 - 1.0;
float3 worldBinormalTex = tex2D (_WorldBinormalTex, IN . uv2_SplatTex) . xyz * 2.0 - 1.0;
float3 offsetSplatWorld = offsetSplat . x * worldTangentTex + offsetSplat . y * worldBinormalTex;
float3 worldTangent = float3 (1, 0, 0);
float3 worldBinormal = float3 (0, 1, 0);
float2 offsetSplatLocal = 0;
offsetSplatLocal . x = dot (worldTangent, offsetSplatWorld);
offsetSplatLocal . y = dot (worldBinormal, offsetSplatWorld);
float4 normalMap = tex2D (_BumpTex, IN . uv_MainTex);
normalMap . xyz = UnpackNormal (normalMap);
float3 tanNormal = normalMap . xyz;
tanNormal . xy += offsetSplatLocal * splatMaskTotal;
tanNormal = normalize (tanNormal);
float4 MainTex = tex2D (_MainTex, IN . uv_MainTex);
half4 c = MainTex * _Color;
c . xyz = lerp (c . xyz, float3 (1.0, 0.5, 0.0), splatMask . x);
c . xyz = lerp (c . xyz, float3 (1.0, 0.0, 0.0), splatMask . y);
c . xyz = lerp (c . xyz, float3 (0.0, 1.0, 0.0), splatMask . z);
c . xyz = lerp (c . xyz, float3 (0.0, 0.0, 1.0), splatMask . w);
o . Albedo = c . rgb;
o . Albedo = offsetSplatX . xyz * 20;
o . Metallic = _Metallic;
o . Smoothness = lerp (_Glossiness, 0.7, splatMaskTotal);
o . Alpha = c . a;
}
Seems effectively identical?