Files
2025-06-09 23:23:13 +08:00

310 lines
9.9 KiB
Plaintext

BEGIN_OPTIONS
name "Hidden/ProceduralRoad_Base"
END_OPTIONS
BEGIN_PROPERTIES
[Header(Main)]
_Asphalt_Albedo("Albedo", 2D) = "white" {}
_AlphaThreshold("Alpha Threshold", Range(0,1)) = 0.0
_Asphalt_Tint("Tint", Color) = (1,1,1,1)
_Asphalt_NormalSAO("NSAO (Smoothness, NormalY, AO, NormalX)", 2D) = "bump" {}
_Asphalt_MaskMap("Mask Map", 2D) = "black" {}
_Asphalt_NormalStrength("Normal Strength", Range(0,1)) = 1
_Asphalt_Smoothness("Smoothness Modifier", Range(-1,1)) = 0
_Asphalt_Metallic ("Metallic Modifier", Range(-1,1)) = 0
_AsphaltStochasticContrast("Asphalt Stochastic Contrast", Range(0.01, 0.99)) = 0.7
_AsphaltStochasticScale("Asphalt Stochastic Scale", Range(0,2)) = 1
_Mask("LineA/LineB/WearUV/WearWorld", 2D) = "black" {}
[Header(Lines)]
_LineColorA("Line Color A", Color) = (1,1,1,1)
_LineColorB("Line Color B", Color) = (1,1,0,1)
_LineEmissiveA("Line Emission", Float) = 0
_LineEmissiveB("Line Emission", Float) = 0
[Header(Wear Noise)]
_WearNoise("Wear Noise Texture", 2D) = "black" {}
_LineWear("Line Wear", Range(0,1)) = 0.5
[Header(WearA)]
_WearMapA("Normal", 2D) = "bump" {}
_WearA_Tint("Tint", Color) = (0.5,0.5,0.5,0.5)
_WearA_PBR("Smoothness, Occlusion, Normal", Vector) = (0, 0, 0, 1)
_WearA_NoiseParams("Contrast, Invert", Vector) = (8, 0, 0, 0)
[Header(WearB)]
_WearMapB("Normal", 2D) = "bump" {}
_WearB_Tint("Tint", Color) = (0.5,0.5,0.5,0.5)
_WearB_PBR("Smoothness, Occlusion, Normal, Strength", Vector) = (0, 0, 0, 1)
_WearB_NoiseParams("Contrast, Invert", Vector) = (8, 0, 0, 0)
[Header(Overlay)]
_Overlay_Albedo("Overlay Albedo", 2D) = "white" {}
_Overlay_Normal("Overlay Normal", 2D) = "bump" {}
_Overlay_Mask("Overlay Mask", 2D) = "black" {}
_Overlay_VariationMask("Variation Mask", 2D) = "white" {}
END_PROPERTIES
BEGIN_DEFINES
#pragma shader_feature_local _ _WEAR_A
#pragma shader_feature_local _ _WEAR_B
#pragma shader_feature_local _ _PACKEDFAST
#pragma shader_feature_local _ _ASPHALTSTOCHASTIC
#pragma shader_feature_local _ _ASPHALT_WORLDTRIPLANAR
#pragma shader_feature_local _ _OVERLAY
#pragma shader_feature_local _ _ALPHACUT
#define __ROADSHADER__ 1
#define _ROADWEAR 1
END_DEFINES
BEGIN_CBUFFER
half4 _Asphalt_Tint;
half _Asphalt_Metallic;
half _Asphalt_Smoothness;
float4 _Asphalt_Albedo_ST;
half _AlphaThreshold;
half _Asphalt_NormalStrength;
half _AsphaltStochasticScale;
half _AsphaltStochasticContrast;
half4 _WearA_Tint;
half4 _WearA_PBR;
float4 _WearMapA_ST;
half4 _WearA_NoiseParams;
half4 _WearB_Tint;
half4 _WearB_PBR;
float4 _WearMapB_ST;
half4 _WearB_NoiseParams;
float4 _WearNoise_ST;
half4 _LineColorA;
half4 _LineColorB;
half _LineEmissiveA;
half _LineEmissiveB;
half _LineWear;
float4 _Mask_TexelSize;
float4 _Overlay_Albedo_ST;
float4 _Overlay_VariationMask_ST;
END_CBUFFER
BEGIN_BLACKBOARD
half roadWear;
END_BLACKBOARD
BEGIN_CODE
sampler2D _Asphalt_Albedo;
sampler2D _Asphalt_NormalSAO;
sampler2D _Asphalt_MaskMap;
TEXTURE2D(_WearMapA);
TEXTURE2D(_WearMapB);
TEXTURE2D(_WearNoise);
sampler2D _Mask;
TEXTURE2D(_Overlay_Albedo);
TEXTURE2D(_Overlay_Normal);
TEXTURE2D(_Overlay_Mask);
TEXTURE2D(_Overlay_VariationMask);
SamplerState road_linear_repeat_sampler;
SamplerState road_linear_clamp_sampler;
void SurfaceFunction(inout Surface o, inout ShaderData d)
{
float2 uv = d.texcoord0.xy;
#if _ASPHALT_WORLDTRIPLANAR
// base layer, triplanar
half3 triblend = saturate(pow(d.worldSpaceNormal, 4));
triblend /= max(dot(triblend, half3(1,1,1)), 0.0001);
float2 uvX = d.worldSpacePosition.zy * _Asphalt_Albedo_ST.xy + _Asphalt_Albedo_ST.zy;
float2 uvY = d.worldSpacePosition.xz * _Asphalt_Albedo_ST.xy + _Asphalt_Albedo_ST.zy;
float2 uvZ = d.worldSpacePosition.xy * _Asphalt_Albedo_ST.xy + _Asphalt_Albedo_ST.zy;
uvY += 0.33;
uvZ += 0.67;
half3 axisSign = d.worldSpaceNormal < 0 ? -1 : 1;
uvX.x *= axisSign.x;
uvY.x *= axisSign.y;
uvZ.x *= -axisSign.z;
// 1 sample triplanar
float2 uvT = uvZ;
if (triblend.x > triblend.y && triblend.x > triblend.z)
{
uvT = uvX;
}
else if (triblend.y > triblend.z)
{
uvT = uvY;
}
#else
float2 uvT = uv * _Asphalt_Albedo_ST.xy + _Asphalt_Albedo_ST.zy;
#endif
#if _ASPHALTSTOCHASTIC
float w1, w2, w3;
int2 vertex1, vertex2, vertex3;
float2 dx = ddx(uvT);
float2 dy = ddy(uvT);
TriangleGrid(uv, _AsphaltStochasticScale, w1, w2, w3, vertex1, vertex2, vertex3);
// Assign random offset to each triangle vertex
float2 uv0 = uvT;
float2 uv1 = uvT;
float2 uv2 = uvT;
uv0.xy += SimpleHash2(vertex1);
uv1.xy += SimpleHash2(vertex2);
uv2.xy += SimpleHash2(vertex3);
half3 weights = half3(w1, w2, w3);
half4 albedo0 = tex2Dgrad(_Asphalt_Albedo, uv0, dx, dy);
half4 albedo1 = tex2Dgrad(_Asphalt_Albedo, uv1, dx, dy);
half4 albedo2 = tex2Dgrad(_Asphalt_Albedo, uv2, dx, dy);
weights = BaryWeightBlend(weights, albedo0.a, albedo1.a, albedo2.a, _AsphaltStochasticContrast);
half4 col = albedo0 * weights.x + albedo1 * weights.y + albedo2 * weights.z;
half4 norm0 = tex2Dgrad(_Asphalt_NormalSAO, uv0, dx, dy);
half4 norm1 = tex2Dgrad(_Asphalt_NormalSAO, uv1, dx, dy);
half4 norm2 = tex2Dgrad(_Asphalt_NormalSAO, uv2, dx, dy);
half4 nsao = norm0 * weights.x + norm1 * weights.y + norm2 * weights.z;
half metallic = 0;
#if !_PACKEDFAST
half4 mmap0 = tex2Dgrad(_Asphalt_MaskMap, uv0, dx, dy);
half4 mmap1 = tex2Dgrad(_Asphalt_MaskMap, uv1, dx, dy);
half4 mmap2 = tex2Dgrad(_Asphalt_MaskMap, uv2, dx, dy);
half4 mmap = mmap0 * weights.x + mmap1 * weights.y + mmap2 * weights.z;
nsao.r = mmap.a;
nsao.b = mmap.g;
metallic = mmap.r;
#endif
#else
half4 col = tex2D(_Asphalt_Albedo, uvT);
half4 nsao = tex2D(_Asphalt_NormalSAO, uvT);
half metallic = 0;
#if !_PACKEDFAST
half4 mmap = tex2D(_Asphalt_MaskMap, uvT);
nsao.r = mmap.a;
nsao.b = mmap.g;
metallic = mmap.r;
#endif
#endif
#if _ALPHACUT
clip(col.a - _AlphaThreshold);
#endif
o.Albedo = col.rgb * _Asphalt_Tint.rgb;
o.Height = col.a;
fixed3 normal;
normal.xy = nsao.wy * 2 - 1;
normal.xy *= _Asphalt_NormalStrength;
normal.z = sqrt(1 - saturate(dot(normal.xy, normal.xy)));
o.Normal = normal;
o.Smoothness = saturate(nsao.r + _Asphalt_Smoothness);
o.Metallic = metallic + _Asphalt_Metallic;
o.Occlusion = nsao.b;
// lines
float fw = fwidth(d.texcoord0.xy);
float lod = saturate(fw * _Mask_TexelSize.zw);
half4 mask = tex2D(_Mask, d.texcoord0.xy);
// soften in mips to prevent aliasing
mask.xy = lerp(smoothstep(0.25-fw, 0.75+fw, mask.xy), mask.xy, lod);
half4 noise = _WearNoise.Sample(road_linear_repeat_sampler, d.worldSpacePosition.xz * _WearNoise_ST.xy + _WearNoise_ST.zw);
float2 maskStr = (1.0 - (smoothstep(0., 0.8, noise.z) * _LineWear)) * mask.xy;
o.Albedo = lerp(o.Albedo, _LineColorA.rgb, mask.x * maskStr.x * _LineColorA.a);
o.Albedo = lerp(o.Albedo, _LineColorB.rgb, mask.y * maskStr.y * _LineColorB.a);
o.Normal.xy = lerp(o.Normal, float3(0,0,1), maskStr);
o.Smoothness = lerp(o.Smoothness, 0, maskStr);
o.Metallic *= 1.0 - maskStr;
o.Occlusion = lerp(o.Occlusion, 1, maskStr);
o.Emission += _LineColorA.rgb * maskStr.x * _LineEmissiveA;
o.Emission += _LineColorB.rgb * maskStr.y * _LineEmissiveB;
// wear
#if _WEAR_A
mask.z = abs(_WearA_NoiseParams.y - mask.z);
float2 wAUV = d.worldSpacePosition.xz;
wAUV = wAUV * _WearMapA_ST.xy + _WearMapA_ST.zw;
float noiseA = saturate(lerp(0.5, noise, _WearA_NoiseParams.x)).x;
half3 wearA = UnpackNormal(_WearMapA.Sample(road_linear_repeat_sampler, wAUV));
half heightA = (wearA.x < 0.5 ? (2.0 * wearA.x * wearA.y) : (1.0 - 2.0 * (1.0 - wearA.x) * (1.0 - wearA.y)));
heightA = saturate(heightA * 4);
half wearAWeight = _WearA_PBR.w * noiseA * mask.z;
o.Albedo = lerp(o.Albedo, o.Albedo * _WearA_Tint.rgb * 2, wearAWeight * heightA);
o.Normal = lerp(o.Normal, wearA, _WearA_PBR.z * wearAWeight);
o.Occlusion += wearAWeight * _WearA_PBR.y;
o.Smoothness += wearAWeight * _WearA_PBR.x;
d.blackboard.roadWear = wearAWeight;
#endif
#if _WEAR_B
mask.w = abs(_WearB_NoiseParams.y - mask.w);
float2 wBUV = d.worldSpacePosition.xz;
wBUV = wBUV * _WearMapB_ST.xy + _WearMapB_ST.zw;
float noiseB = saturate(lerp(0.5, noise, _WearB_NoiseParams.x)).y;
half3 wearB = UnpackNormal(_WearMapB.Sample(road_linear_repeat_sampler, wBUV));
half heightB = (wearB.x < 0.5 ? (2.0 * wearB.x * wearB.y) : (1.0 - 2.0 * (1.0 - wearB.x) * (1.0 - wearB.y)));
heightB = saturate(heightB * 4);
half wearBWeight = _WearB_PBR.w * noiseB * mask.w;
o.Albedo = lerp(o.Albedo, o.Albedo * _WearB_Tint.rgb * 2, wearBWeight * heightB);
o.Normal = lerp(o.Normal, wearB, _WearB_PBR.z * wearBWeight);
o.Occlusion += wearBWeight * _WearB_PBR.y;
o.Smoothness += wearBWeight * _WearB_PBR.x;
#endif
#if _OVERLAY
float2 ouv = d.worldSpacePosition.xz * _Overlay_Albedo_ST.xy + _Overlay_Albedo_ST.zw;
half4 oAlbedo = _Overlay_Albedo.Sample(road_linear_repeat_sampler, ouv);
half3 oNormal = UnpackNormal(_Overlay_Normal.Sample(road_linear_repeat_sampler, ouv));
half4 oMask = _Overlay_Mask.Sample(road_linear_repeat_sampler, ouv);
float2 vwsUV = d.worldSpacePosition.xz * _Overlay_VariationMask_ST.xy + _Overlay_VariationMask_ST.zw;
half varyWorldSpace = _Overlay_VariationMask.Sample(road_linear_repeat_sampler, vwsUV).g;
oAlbedo.a *= varyWorldSpace;
o.Albedo = lerp(o.Albedo, oAlbedo.rgb, oAlbedo.a);
o.Normal = lerp(o.Normal, oNormal.rgb, oAlbedo.a);
o.Smoothness = lerp(o.Smoothness, oMask.a, oAlbedo.a);
o.Occlusion = lerp(o.Occlusion, oMask.g, oAlbedo.a);
o.Metallic = lerp(o.Metallic, oMask.r, oAlbedo.a);
#endif
o.Albedo = saturate(o.Albedo);
o.Smoothness = saturate(o.Smoothness);
o.Occlusion = saturate(o.Occlusion);
}
END_CODE