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 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266
| Shader "Custom/URP/StandardPBRExtended" { Properties { // 基础 PBR 属性 _BaseColor ("Base Color", Color) = (1,1,1,1) _BaseMap ("Base Albedo", 2D) = "white" {} _Metallic ("Metallic", Range(0,1)) = 0.0 _Smoothness ("Smoothness", Range(0,1)) = 0.5
// 法线贴图 _BumpMap ("Normal Map", 2D) = "bump" {} _BumpScale ("Normal Strength",Range(0,3)) = 1.0
// 第二层法线(宏观起伏) _BumpMap2 ("Normal Map 2", 2D) = "bump" {} _BumpScale2 ("Normal Strength 2", Range(0,1)) = 0.5 _BumpTiling2 ("Normal Map 2 Tiling", Range(0.1, 5)) = 0.3
// 高度图(视差贴图) _HeightMap ("Height Map", 2D) = "black" {} _ParallaxScale ("Parallax Depth", Range(0.001, 0.08)) = 0.02 _ParallaxSteps ("Parallax Steps", Range(4, 32)) = 16 // 陡峭视差步数
// 遮蔽/自发光 _OcclusionMap ("Occlusion Map", 2D) = "white" {} _OcclusionStrength ("Occlusion Strength", Range(0,1)) = 1.0 [HDR] _EmissionColor ("Emission", Color) = (0,0,0,1) _EmissionMap ("Emission Map", 2D) = "black" {} }
SubShader { Tags { "RenderType" = "Opaque" "RenderPipeline" = "UniversalPipeline" "Queue" = "Geometry" }
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 _ _ADDITIONAL_LIGHTS #pragma multi_compile _ _SHADOWS_SOFT #pragma multi_compile_fog
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl"
TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap); TEXTURE2D(_BumpMap); SAMPLER(sampler_BumpMap); TEXTURE2D(_BumpMap2); SAMPLER(sampler_BumpMap2); TEXTURE2D(_HeightMap); SAMPLER(sampler_HeightMap); TEXTURE2D(_OcclusionMap);SAMPLER(sampler_OcclusionMap); TEXTURE2D(_EmissionMap); SAMPLER(sampler_EmissionMap);
CBUFFER_START(UnityPerMaterial) float4 _BaseMap_ST; float4 _BumpMap_ST; float4 _BumpMap2_ST; float4 _HeightMap_ST; float4 _OcclusionMap_ST; float4 _EmissionMap_ST; float4 _BaseColor; float4 _EmissionColor; float _Metallic; float _Smoothness; float _BumpScale; float _BumpScale2; float _BumpTiling2; float _ParallaxScale; float _ParallaxSteps; float _OcclusionStrength; CBUFFER_END
struct Attributes { float4 positionOS : POSITION; float3 normalOS : NORMAL; float4 tangentOS : TANGENT; float2 uv : TEXCOORD0; float2 uv2 : TEXCOORD1; // 第二 UV(Lightmap UV) UNITY_VERTEX_INPUT_INSTANCE_ID };
struct Varyings { float4 positionHCS : SV_POSITION; float2 uv : TEXCOORD0; float2 lightmapUV : TEXCOORD1; float3 positionWS : TEXCOORD2; float3 normalWS : TEXCOORD3; float3 tangentWS : TEXCOORD4; float3 bitangentWS : TEXCOORD5; float3 viewDirTS : TEXCOORD6; // 切线空间视线方向(视差贴图使用) float4 shadowCoord : TEXCOORD7; float fogFactor : TEXCOORD8; UNITY_VERTEX_OUTPUT_STEREO };
// ======== 视差贴图(Parallax Occlusion Mapping)========
// 简单视差(Parallax Mapping) float2 parallaxSimple(float2 uv, float3 viewDirTS, float scale) { // 用高度图采样计算偏移量 float height = SAMPLE_TEXTURE2D_LOD(_HeightMap, sampler_HeightMap, uv, 0).r; // 偏移量 = 高度 × 视线切线分量(越斜视越大) float2 offset = viewDirTS.xy / viewDirTS.z * (height * scale); return uv - offset; // 减法:高区域 UV 向视线方向偏移 }
// 陡峭视差(Steep Parallax Mapping) // 多步采样,处理大深度时的锯齿问题 float2 parallaxSteep(float2 uv, float3 viewDirTS, float scale, int steps) { float stepSize = 1.0 / float(steps); float2 uvStep = viewDirTS.xy / abs(viewDirTS.z) * scale * stepSize;
float currentHeight = 1.0; // 从顶部开始向下步进 float2 currentUV = uv; float sampledHeight = SAMPLE_TEXTURE2D_LOD(_HeightMap, sampler_HeightMap, currentUV, 0).r;
[loop] for (int i = 0; i < steps; i++) { if (sampledHeight >= currentHeight) break; currentHeight -= stepSize; currentUV -= uvStep; // 每步向视线方向偏移 sampledHeight = SAMPLE_TEXTURE2D_LOD(_HeightMap, sampler_HeightMap, currentUV, 0).r; }
// 线性插值(在最后两步之间插值,消除锯齿) float2 prevUV = currentUV + uvStep; float prevHeight = SAMPLE_TEXTURE2D_LOD(_HeightMap, sampler_HeightMap, prevUV, 0).r; float prevDiff = prevHeight - (currentHeight + stepSize); float currDiff = sampledHeight - currentHeight; float blend = currDiff / (currDiff - prevDiff); return lerp(currentUV, prevUV, blend); }
Varyings vert(Attributes IN) { Varyings OUT; UNITY_SETUP_INSTANCE_ID(IN); UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
VertexPositionInputs posInputs = GetVertexPositionInputs(IN.positionOS.xyz); VertexNormalInputs normalInputs = GetVertexNormalInputs(IN.normalOS, IN.tangentOS);
OUT.positionHCS = posInputs.positionCS; OUT.positionWS = posInputs.positionWS; OUT.normalWS = normalInputs.normalWS; OUT.tangentWS = normalInputs.tangentWS; OUT.bitangentWS = normalInputs.bitangentWS; OUT.uv = TRANSFORM_TEX(IN.uv, _BaseMap); OUT.shadowCoord = GetShadowCoord(posInputs); OUT.fogFactor = ComputeFogFactor(posInputs.positionCS.z);
// 计算切线空间视线方向(视差贴图在顶点着色器中预计算更高效) float3 viewDirWS = GetCameraPositionWS() - posInputs.positionWS; // 构建 TBN 逆矩阵(正交矩阵的逆 = 转置) float3x3 TBN = float3x3(normalInputs.tangentWS, normalInputs.bitangentWS, normalInputs.normalWS); // 世界空间视线 → 切线空间(mul(v, M) 等价于 transpose(M) * v) OUT.viewDirTS = mul(TBN, viewDirWS); // 注意:这里 TBN 行主序,等价于切线空间变换
OUTPUT_LIGHTMAP_UV(IN.uv2, unity_LightmapST, OUT.lightmapUV);
return OUT; }
half4 frag(Varyings IN) : SV_Target { float3 viewDirTS = normalize(IN.viewDirTS);
// ===== 1. 视差贴图 UV 偏移 ===== float2 uv = IN.uv; #ifdef _PARALLAX_MAP // 使用陡峭视差(更大 _ParallaxScale 时推荐) uv = parallaxSteep(uv, viewDirTS, _ParallaxScale, (int)_ParallaxSteps); #else // 简单视差(低性能消耗) uv = parallaxSimple(uv, viewDirTS, _ParallaxScale); #endif
// ===== 2. 基础颜色 ===== half4 albedo = SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, uv) * _BaseColor;
// ===== 3. 法线(双层叠加)===== // 第一层法线(主要细节) float4 normalPacked1 = SAMPLE_TEXTURE2D(_BumpMap, sampler_BumpMap, uv); float3 normalTS1 = UnpackNormalScale(normalPacked1, _BumpScale);
// 第二层法线(宏观起伏,使用不同缩放) float2 uv2 = IN.uv * _BumpTiling2; float4 normalPacked2 = SAMPLE_TEXTURE2D(_BumpMap2, sampler_BumpMap2, uv2); float3 normalTS2 = UnpackNormalScale(normalPacked2, _BumpScale2);
// RNM 法线混合 float3 t = normalTS1 + float3(0, 0, 1); float3 u = normalTS2 * float3(-1, -1, 1); float3 blendedNormalTS = normalize(t * dot(t, u) / t.z - u);
// 切线空间 → 世界空间 float3x3 TBN = float3x3( normalize(IN.tangentWS), normalize(IN.bitangentWS), normalize(IN.normalWS) ); float3 normalWS = TransformTangentToWorld(blendedNormalTS, TBN);
// ===== 4. PBR 材质属性 ===== float metallic = _Metallic; float smoothness = _Smoothness; float occlusion = lerp(1.0, SAMPLE_TEXTURE2D(_OcclusionMap, sampler_OcclusionMap, uv).g, _OcclusionStrength); half3 emission = SAMPLE_TEXTURE2D(_EmissionMap, sampler_EmissionMap, uv).rgb * _EmissionColor.rgb;
// ===== 5. URP 标准 PBR 光照 ===== SurfaceData surfaceData; surfaceData.albedo = albedo.rgb; surfaceData.alpha = albedo.a; surfaceData.metallic = metallic; surfaceData.smoothness = smoothness; surfaceData.normalTS = blendedNormalTS; // 保存切线空间法线(URP 内部处理) surfaceData.occlusion = occlusion; surfaceData.emission = emission; surfaceData.specular = 0; surfaceData.clearCoatMask = 0; surfaceData.clearCoatSmoothness = 0;
InputData inputData; inputData.positionWS = IN.positionWS; inputData.normalWS = normalize(normalWS); inputData.viewDirectionWS = normalize(GetCameraPositionWS() - IN.positionWS); inputData.shadowCoord = IN.shadowCoord; inputData.fogCoord = IN.fogFactor; inputData.vertexLighting = 0; inputData.bakedGI = SAMPLE_GI(IN.lightmapUV, SampleSH(inputData.normalWS), inputData.normalWS); inputData.normalizedScreenSpaceUV = GetNormalizedScreenSpaceUV(IN.positionHCS); inputData.shadowMask = SAMPLE_SHADOWMASK(IN.lightmapUV);
// URP 内置 PBR 光照(封装了主光源 + 额外光源 + GI + 阴影) half4 color = UniversalFragmentPBR(inputData, surfaceData);
// 雾效 color.rgb = MixFog(color.rgb, IN.fogFactor); return color; } ENDHLSL }
// 阴影投射 Pass(使用 URP 内置) UsePass "Universal Render Pipeline/Lit/ShadowCaster" // 深度 Pass UsePass "Universal Render Pipeline/Lit/DepthOnly" // 法线深度 Pass(用于 SSAO) UsePass "Universal Render Pipeline/Lit/DepthNormals" } }
|