【URP】Unity[陡峭視差貼圖]原理剖析實踐
【從UnityURP開始探索游戲渲染】專欄-直達
陡峭視差貼圖(Steep Parallax Mapping)介紹
陡峭視差貼圖是標準視差貼圖的進階技術,通過?分層采樣高度圖?解決陡峭表面(如巖石、冰縫)的UV偏移失真問題。其核心原理是將視線方向在切線空間內分解為多層,逐層檢測高度差以確定最終采樣點,相比單次偏移計算能更精確地模擬遮擋關系。
核心優勢
- ?陡峭表面適應性?:通過光線步進(Raymarching)避免標準視差貼圖在接近平行視角時的拉伸失真
- ?動態分層采樣?:根據視角與法線夾角動態調整采樣層數(通常5-15層),平衡性能與精度
- ?遮擋效果增強?:精確計算視線與高度圖的交點,模擬更真實的深度遮擋
Unity URP 實現示例與原理詳解
原理說明
-
?分層采樣機制?
- 根據視角與表面法線的夾角動態分配5-15層采樣(
numLayers),視角越平行層數越多 - 每層高度差為
layerHeight,通過循環逐層比較當前高度與采樣深度
- 根據視角與表面法線的夾角動態分配5-15層采樣(
-
?光線步進優化?
- 使用
deltaUV控制每步UV偏移量,避免標準視差貼圖的單次偏移過大問題 - 通過
currentLayerHeight >= currentDepth判斷終止條件,找到精確交點
- 使用
-
?切線空間計算?
- 通過URP內置函數
TransformWorldToTangent轉換視角方向,確保偏移方向正確 - 高度圖采樣值取反(
1 - SAMPLE_TEXTURE2D)以匹配Unity的紋理坐標系
- 通過URP內置函數
-
SteepParallax.shader
Shader "Universal Render Pipeline/SteepParallax" { Properties { _MainTex("Albedo", 2D) = "white" {} _NormalMap("Normal Map", 2D) = "bump" {} _HeightMap("Height Map", 2D) = "white" {} _ParallaxScale("Height Scale", Range(0, 0.1)) = 0.05 } SubShader { Tags { "RenderPipeline"="UniversalPipeline" } HLSLINCLUDE #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl" TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); TEXTURE2D(_NormalMap); SAMPLER(sampler_NormalMap); TEXTURE2D(_HeightMap); SAMPLER(sampler_HeightMap); float _ParallaxScale; // 陡峭視差映射核心函數 float2 SteepParallaxMapping(float3 viewDirTS, float2 uv) { // 動態計算采樣層數(視角越平行層數越多) float minLayers = 5; float maxLayers = 15; float numLayers = lerp(maxLayers, minLayers, abs(dot(float3(0,0,1), viewDirTS))); // 每層高度步長 float layerHeight = 1.0 / numLayers; float currentLayerHeight = 0; // UV偏移步長 float2 deltaUV = _ParallaxScale * viewDirTS.xy / viewDirTS.z / numLayers; float2 currentUV = uv; // 初始高度采樣 float currentDepth = 1 - SAMPLE_TEXTURE2D(_HeightMap, sampler_HeightMap, currentUV).r; // 光線步進循環 [loop] for (int i = 0; i < 15; ++i) { if (currentLayerHeight >= currentDepth) break; currentUV -= deltaUV; currentDepth = 1 - SAMPLE_TEXTURE2D(_HeightMap, sampler_HeightMap, currentUV).r; currentLayerHeight += layerHeight; } return currentUV; } ENDHLSL Pass { HLSLPROGRAM #pragma vertex vert #pragma fragment frag struct Attributes { float4 positionOS : POSITION; float2 uv : TEXCOORD0; float3 normalOS : NORMAL; float4 tangentOS : TANGENT; }; struct Varyings { float4 positionCS : SV_POSITION; float2 uv : TEXCOORD0; float3 viewDirTS : TEXCOORD1; }; Varyings vert(Attributes IN) { Varyings OUT; VertexPositionInputs posInput = GetVertexPositionInputs(IN.positionOS.xyz); OUT.positionCS = posInput.positionCS; // 轉換視角方向到切線空間 VertexNormalInputs normInput = GetVertexNormalInputs(IN.normalOS, IN.tangentOS); float3 viewDirWS = GetWorldSpaceViewDir(posInput.positionWS); OUT.viewDirTS = TransformWorldToTangent(viewDirWS, normInput.tangentWS, normInput.bitangentWS, normInput.normalWS); OUT.uv = IN.uv; return OUT; } half4 frag(Varyings IN) : SV_Target { // 計算陡峭視差UV偏移 float2 parallaxUV = SteepParallaxMapping(normalize(IN.viewDirTS), IN.uv); // 采樣最終紋理 half4 albedo = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, parallaxUV); half3 normalTS = UnpackNormal(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, parallaxUV)); return half4(albedo.rgb, 1); } ENDHLSL } } }
性能與效果對比
| 維度 | 標準視差貼圖 | 陡峭視差貼圖 |
|---|---|---|
| ?采樣次數? | 單次采樣 | 5-15次分層采樣 |
| ?陡峭表面表現? | 易失真 | 精準遮擋 |
| ?適用平臺? | 移動端 | PC/主機 |
| ?推薦參數? | _ParallaxScale=0.02 |
_ParallaxScale=0.05 |
實際應用中,建議在URP材質中同時使用法線貼圖和陡峭視差貼圖,并控制_ParallaxScale不超過0.1以避免性能瓶頸
【從UnityURP開始探索游戲渲染】專欄-直達
(歡迎點贊留言探討,更多人加入進來能更加完善這個探索的過程,??)

《Unity URP陡峭視差貼圖技術解析》介紹了進階的Steep Parallax Mapping技術,通過分層采樣高度圖解決標準視差貼圖在陡峭表面(如巖石、冰縫)的UV偏移失真問題。該技術采用5-15層動態采樣,利用光線步進算法精確計算視線與高度圖的交點,顯著提升遮擋效果和陡峭表面適應性。文章詳細講解了Unity URP實現方案,包括切線空間轉換、動態分層采樣機制和Shader代碼實現,并對比了標準與陡峭視差貼圖在采樣次數、表現效果和適用平臺上的差異。建議在PC/主機平臺結合法線貼圖使用,控制高度縮放參數
浙公網安備 33010602011771號