1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205
| Shader "Custom/URP/InfiniteFloor" { Properties { _MainTex ("地面主纹理", 2D) = "white" {} _NormalMap ("法线贴图", 2D) = "bump" {} _DetailTex ("细节纹理(小尺度)", 2D) = "white" {} _TileSize ("瓷砖大小(世界单位)", Float) = 2.0 _DetailTileSize ("细节瓷砖大小", Float) = 0.25 _NormalStrength ("法线强度", Range(0, 3)) = 1.0 _Roughness ("粗糙度", Range(0, 1)) = 0.8 _Metallic ("金属度", Range(0, 1)) = 0.0
// 视距渐变(避免远处重复感) _FarBlendStart ("远距渐变开始", Float) = 20.0 _FarBlendEnd ("远距渐变结束", Float) = 50.0 _FarColor ("远处颜色", Color) = (0.5, 0.5, 0.5, 1)
// 随机化强度 _RandomColorVariation ("颜色随机变化强度", Range(0, 0.3)) = 0.05 }
SubShader { Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" }
Pass { Name "ForwardLit" Tags { "LightMode" = "UniversalForward" }
HLSLPROGRAM #pragma vertex vert #pragma fragment frag #pragma multi_compile _ _MAIN_LIGHT_SHADOWS _MAIN_LIGHT_SHADOWS_CASCADE #pragma multi_compile _ _SHADOWS_SOFT #pragma multi_compile _ _ADDITIONAL_LIGHTS
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); TEXTURE2D(_NormalMap); SAMPLER(sampler_NormalMap); TEXTURE2D(_DetailTex); SAMPLER(sampler_DetailTex);
CBUFFER_START(UnityPerMaterial) float4 _MainTex_ST; float4 _NormalMap_ST; float4 _DetailTex_ST; float _TileSize; float _DetailTileSize; float _NormalStrength; float _Roughness; float _Metallic; float _FarBlendStart; float _FarBlendEnd; float4 _FarColor; float _RandomColorVariation; CBUFFER_END
struct Attributes { float4 positionOS : POSITION; float3 normalOS : NORMAL; float4 tangentOS : TANGENT; float2 uv : TEXCOORD0; };
struct Varyings { float4 positionHCS : SV_POSITION; float3 worldPos : TEXCOORD0; float3 worldNormal : TEXCOORD1; float3 worldTangent : TEXCOORD2; float3 worldBitangent : TEXCOORD3; float4 shadowCoord : TEXCOORD4; };
// 无 sin 快速哈希 float Hash(float2 p) { p = frac(p * float2(0.1031, 0.1030)); p += dot(p, p.yx + 33.33); return frac((p.x + p.y) * p.x); }
// 域重复:基于世界位置的随机翻转瓷砖 UV float2 RepeatTileUV(float2 worldXZ, float tileSize) { float2 cellID = floor(worldXZ / tileSize); float2 cellUV = frac(worldXZ / tileSize);
// 随机翻转(每个单元格独立) float rx = Hash(cellID * 1.731); float ry = Hash(cellID * 2.537 + 5.0);
if (rx > 0.5) cellUV.x = 1.0 - cellUV.x; if (ry > 0.5) cellUV.y = 1.0 - cellUV.y;
return cellUV; }
// 每个瓷砖的随机颜色偏移(轻微颜色变化打破单调感) float3 GetTileColorVariation(float2 worldXZ, float tileSize) { float2 cellID = floor(worldXZ / tileSize); float rand = Hash(cellID + 100.0); // 在中性灰周围随机扰动 return float3(rand, Hash(cellID + 200.0), Hash(cellID + 300.0)) * 2.0 - 1.0; }
Varyings vert(Attributes input) { Varyings output; VertexPositionInputs posInputs = GetVertexPositionInputs(input.positionOS.xyz); VertexNormalInputs norInputs = GetVertexNormalInputs(input.normalOS, input.tangentOS);
output.positionHCS = posInputs.positionCS; output.worldPos = posInputs.positionWS; output.worldNormal = norInputs.normalWS; output.worldTangent = norInputs.tangentWS; output.worldBitangent = norInputs.bitangentWS; output.shadowCoord = GetShadowCoord(posInputs); return output; }
half4 frag(Varyings input) : SV_Target { float3 worldPos = input.worldPos; float2 worldXZ = worldPos.xz;
// ---- 域重复 UV(大瓷砖)---- float2 tileUV = RepeatTileUV(worldXZ, _TileSize);
// ---- 域重复 UV(细节层,更小的瓷砖)---- float2 detailUV = RepeatTileUV(worldXZ, _DetailTileSize);
// ---- 采样主纹理和细节纹理 ---- float3 mainColor = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, tileUV).rgb; float3 detailColor = SAMPLE_TEXTURE2D(_DetailTex, sampler_DetailTex, detailUV).rgb;
// 细节叠加(overlay 混合:增强细节而不改变整体色调) float3 albedo = mainColor * (detailColor * 2.0);
// 每格轻微颜色变化(在视觉敏感的中距离特别有效) float3 colorVar = GetTileColorVariation(worldXZ, _TileSize); albedo += colorVar * _RandomColorVariation; albedo = saturate(albedo);
// ---- 法线贴图 ---- float4 normalSample = SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, tileUV); float3 normalTS = UnpackNormalScale(normalSample, _NormalStrength);
float3x3 TBN = float3x3( normalize(input.worldTangent), normalize(input.worldBitangent), normalize(input.worldNormal) ); float3 worldNormal = normalize(mul(normalTS, TBN));
// ---- 与相机的距离(用于远距离 LOD 渐变)---- float camDist = length(worldPos - GetCameraPositionWS()); float farBlend = smoothstep(_FarBlendStart, _FarBlendEnd, camDist);
// 远处渐变到纯色(避免远处纹理噪点和重复感) albedo = lerp(albedo, _FarColor.rgb, farBlend); worldNormal = lerp(worldNormal, normalize(input.worldNormal), farBlend);
// ---- URP 标准 PBR 光照 ---- InputData lightingInput; lightingInput.positionWS = worldPos; lightingInput.normalWS = worldNormal; lightingInput.viewDirectionWS = normalize(GetCameraPositionWS() - worldPos); lightingInput.shadowCoord = input.shadowCoord; lightingInput.fogCoord = 0; lightingInput.vertexLighting = half3(0, 0, 0); lightingInput.bakedGI = SampleSH(worldNormal); lightingInput.normalizedScreenSpaceUV = float2(0, 0); lightingInput.shadowMask = unity_ProbesOcclusion;
SurfaceData surfaceData; surfaceData.albedo = albedo; surfaceData.metallic = _Metallic; surfaceData.specular = 0; surfaceData.smoothness = 1.0 - _Roughness; surfaceData.normalTS = normalTS; surfaceData.emission = 0; surfaceData.occlusion = 1.0; surfaceData.alpha = 1.0; surfaceData.clearCoatMask = 0; surfaceData.clearCoatSmoothness = 0;
return UniversalFragmentPBR(lightingInput, surfaceData); } ENDHLSL }
// ShadowCaster Pass(标准,无特殊处理) UsePass "Universal Render Pipeline/Lit/ShadowCaster" } }
|