找回密码
 立即注册
首页 业界区 业界 【URP】Unity[视差贴图]原理剖析实践

【URP】Unity[视差贴图]原理剖析实践

崆蛾寺 2025-10-22 10:25:00
【从UnityURP开始探索游戏渲染】专栏-直达
Unity URP 视差贴图介绍与分类

视差贴图(Parallax Mapping)是一种通过动态偏移纹理坐标来模拟表面凹凸效果的渲染技术,主要用于增强低多边形模型的细节表现。在Unity URP(Universal Render Pipeline)中,它通过高度图(Height Map)和视角方向计算UV偏移,实现更真实的深度感,而无需增加模型顶点数量‌。
‌视差贴图的核心分类‌

‌标准视差贴图(Parallax Mapping)


  • 原理‌:基于单次高度采样计算UV偏移,性能消耗低但效果有限,适合移动端或性能敏感场景‌。
  • 实现‌:通过高度图的灰度值(黑色为低点,白色为高点)和视角方向,在切线空间内偏移UV坐标,模拟遮挡效果‌。
  • 示例‌:URP中通过ParallaxOffset1Step函数实现单步偏移计算‌。

    • 关键参数

      • _HeightMap:存储高度信息的纹理(R通道)
      • _Parallax:控制凹凸强度的缩放系数(建议0.02-0.05)

    • 切线空间转换

      • 使用URP内置函数GetVertexNormalInputs构建TBN矩阵,将视角方向转换到切线空间

    • 性能优化

      • 单步偏移计算(ParallaxOffset)相比多步光线步进(如POM)性能更高,适合移动端

    • ParallaxLit.shader
      1. Shader "Universal Render Pipeline/ParallaxLit"
      2. {
      3.     Properties
      4.     {
      5.         _MainTex("Albedo", 2D) = "white" {}
      6.         _NormalMap("Normal Map", 2D) = "bump" {}
      7.         _HeightMap("Height Map", 2D) = "white" {}
      8.         _Parallax("Height Scale", Range(0, 0.1)) = 0.02
      9.     }
      10.     SubShader
      11.     {
      12.         Tags { "RenderPipeline"="UniversalPipeline" }
      13.         HLSLINCLUDE
      14.         #include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
      15.         TEXTURE2D(_MainTex);    SAMPLER(sampler_MainTex);
      16.         TEXTURE2D(_NormalMap);  SAMPLER(sampler_NormalMap);
      17.         TEXTURE2D(_HeightMap);  SAMPLER(sampler_HeightMap);
      18.         float _Parallax;
      19.         float2 ParallaxOffset(float3 viewDirTS, float height)
      20.         {
      21.             height = height * _Parallax - _Parallax * 0.5;
      22.             return height * (viewDirTS.xy / (viewDirTS.z + 0.42));
      23.         }
      24.         ENDHLSL
      25.         Pass
      26.         {
      27.             HLSLPROGRAM
      28.             #pragma vertex vert
      29.             #pragma fragment frag
      30.             struct Attributes
      31.             {
      32.                 float4 positionOS : POSITION;
      33.                 float2 uv : TEXCOORD0;
      34.                 float3 normalOS : NORMAL;
      35.                 float4 tangentOS : TANGENT;
      36.             };
      37.             struct Varyings
      38.             {
      39.                 float4 positionCS : SV_POSITION;
      40.                 float2 uv : TEXCOORD0;
      41.                 float3 viewDirTS : TEXCOORD1;
      42.             };
      43.             Varyings vert(Attributes IN)
      44.             {
      45.                 Varyings OUT;
      46.                 VertexPositionInputs posInput = GetVertexPositionInputs(IN.positionOS.xyz);
      47.                 OUT.positionCS = posInput.positionCS;
      48.                 // 计算切线空间视角方向
      49.                 VertexNormalInputs normInput = GetVertexNormalInputs(IN.normalOS, IN.tangentOS);
      50.                 float3 viewDirWS = GetWorldSpaceViewDir(posInput.positionWS);
      51.                 OUT.viewDirTS = TransformWorldToTangent(viewDirWS, normInput.tangentWS, normInput.bitangentWS, normInput.normalWS);
      52.                 OUT.uv = IN.uv;
      53.                 return OUT;
      54.             }
      55.             half4 frag(Varyings IN) : SV_Target
      56.             {
      57.                 // 采样高度图并计算UV偏移
      58.                 float height = SAMPLE_TEXTURE2D(_HeightMap, sampler_HeightMap, IN.uv).r;
      59.                 float2 offset = ParallaxOffset(normalize(IN.viewDirTS), height);
      60.                 // 应用偏移后采样纹理
      61.                 float2 parallaxUV = IN.uv + offset;
      62.                 half4 albedo = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, parallaxUV);
      63.                 half3 normalTS = UnpackNormal(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, parallaxUV));
      64.                 return half4(albedo.rgb, 1);
      65.             }
      66.             ENDHLSL
      67.         }
      68.     }
      69. }
      复制代码

‌陡峭视差贴图(Steep Parallax Mapping)


  • 特点‌:针对陡峭地形优化,通过多次采样(如二分法)减少失真,适合高落差表面(如岩石、冰缝)‌。
  • 实现‌:在URP中结合光线步进(Raymarching)算法,逐层检测高度图以确定最终UV偏移‌。
‌视差遮挡贴图(Parallax Occlusion Mapping, POM)


  • 优势‌:在标准视差基础上增加遮挡计算,通过多次采样模拟更精确的深度感,但性能开销较高‌。
  • 应用‌:常用于风格化材质(如风化岩石、冰面裂缝),需配合高度图和法线贴图使用‌。
‌技术实现细节‌

核心原理


  • 高度图采样

    • 使用灰度图(通常存储在法线贴图的Alpha通道)表示表面深度,黑色(0)为最低点,白色(1)为最高点。

  • 切线空间转换

    • 将视角方向从世界空间转换到切线空间(通过TBN矩阵),确保偏移方向与模型表面法线对齐。

  • UV偏移计算

    • 根据高度值和视角方向动态调整UV坐标,核心公式为‌ $offset=\frac{height \cdot viewDir_{xy}}{viewDir_z}$
    • 其中viewDir需归一化,且需避免除零(通常添加小偏移量如viewDir.z + 0.42)

URP中的Shader实现


  • 核心函数:ParallaxOffset1Step(单步偏移)或自定义光线步进算法‌。
  • 示例代码(HLSL):
    1. hlsl
    2. float2 ParallaxOffset(half3 viewDirTS, half height, half scale) {
    3.     return height * (viewDirTS.xy / viewDirTS.z) * scale;
    4. }
    复制代码
性能优化


  • 使用_Parallax参数控制强度,避免过度偏移导致穿帮‌。
  • 移动端建议采用标准视差贴图,PC端可尝试POM‌。
‌与其他贴图技术的对比‌

技术原理差异性能开销适用场景优势局限性法线贴图仅改变光照计算低通用细节增强性能最优平视视角易穿帮视差贴图动态UV偏移模拟深度中风格化材质、地形真实遮挡效果陡峭边缘可能失真置换贴图实际修改顶点位置高高精度模型(如地形)几何级精度需要曲面细分支持‌总结‌

视差贴图在URP中通过动态UV偏移和高度图采样,有效平衡了性能与视觉效果。根据需求选择标准、陡峭或POM变种,可适配不同场景的细节要求‌
<blockquote>
【从UnityURP开始探索游戏渲染】专栏-直达
(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!

相关推荐

3 天前

举报

前排留名,哈哈哈
您需要登录后才可以回帖 登录 | 立即注册