当前位置: 首页 > news >正文

【URP】Unity[视差贴图]模拟[风格化地形]实践

【从UnityURP开始探索游戏渲染】专栏-直达

陡峭视差贴图(Steep Parallax Mapping)实现原理

陡峭视差贴图通过‌分层深度比较‌和‌动态UV偏移‌技术增强岩石表面立体感.

视角自适应分层采样

  • 根据视线与表面法线的夹角动态分配采样层数(平视视角增加至12层,俯视视角减少至5层),解决标准视差贴图在平视角度下的失真问题

深度图梯度修正

  • 引入_LayerBias参数(推荐值0.2-0.4)调整UV偏移量计算公式,避免陡峭区域出现采样断裂:

$\Delta UV=\frac{ParallaxScale \cdot ViewDir_{xy}}{(ViewDir_z+LayerBias) \cdot LayerCount}$

风格化深度增强

  • 在最终插值阶段使用pow(weight,2)强化轮廓对比度,配合ramp贴图实现卡通化光影过渡效果

URP HLSL完整实现代码

关键特性说明

  • 动态层数优化‌:通过lerp(_MaxLayers, _MinLayers, saturate(dot(float3(0,0,1), viewDirTS)))实现平视视角自动增加采样精度

  • 抗失真处理‌:_LayerBias参数修正陡峭表面的UV偏移计算,避免采样断裂

  • 风格化增强‌:ramp贴图控制光影过渡,边缘光强化轮廓立体感

  • StylizedRockParallax.shader

    Shader "Universal Render Pipeline/StylizedRockParallax"
    {Properties{[Header(Base Textures)]_MainTex("Albedo (RGB)", 2D) = "white" {}_NormalMap("Normal Map", 2D) = "bump" {}_HeightMap("Height Map", 2D) = "white" {}_RampTex("Stylized Ramp", 2D) = "white" {}[Header(Parallax Settings)]_ParallaxScale("Depth Scale", Range(0, 0.15)) = 0.08_LayerBias("Layer Bias", Range(0.1, 0.5)) = 0.3_MinLayers("Min Layers", Int) = 5_MaxLayers("Max Layers", Int) = 12[Header(Stylized Lighting)]_RimPower("Rim Power", Range(1, 10)) = 3_ShadowTint("Shadow Tint", Color) = (0.3,0.3,0.4,1)}SubShader{Tags { "RenderType"="Opaque" "RenderPipeline"="UniversalPipeline" }HLSLINCLUDE#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(_HeightMap);  SAMPLER(sampler_HeightMap);TEXTURE2D(_RampTex);    SAMPLER(sampler_RampTex);float _ParallaxScale;float _LayerBias;int _MinLayers, _MaxLayers;float _RimPower;float4 _ShadowTint;// 陡峭视差映射核心算法float2 SteepParallaxMapping(float3 viewDirTS, float2 uv){// 动态层数计算(平视视角增加层数)int numLayers = (int)lerp(_MaxLayers, _MinLayers, saturate(dot(float3(0,0,1), viewDirTS)));float layerHeight = 1.0 / numLayers;float2 deltaUV = _ParallaxScale * viewDirTS.xy / (viewDirTS.z + _LayerBias) / numLayers;// 光线步进初始化float currentLayerHeight = 0;float2 currentUV = uv;float currentDepth = 1 - SAMPLE_TEXTURE2D(_HeightMap, sampler_HeightMap, currentUV).r;// 分层深度检测[loop]for (int i = 0; i < _MaxLayers; ++i) {if (currentLayerHeight >= currentDepth) break;currentUV -= deltaUV;currentDepth = 1 - SAMPLE_TEXTURE2D(_HeightMap, sampler_HeightMap, currentUV).r;currentLayerHeight += layerHeight;}// 风格化插值修正float2 prevUV = currentUV + deltaUV;float prevDepth = currentDepth - layerHeight;float weight = pow((currentLayerHeight - currentDepth) / (prevDepth - currentDepth + 0.001), 2);return lerp(currentUV, prevUV, saturate(weight * 1.5));}// 风格化光照计算half3 StylizedShading(float3 normalWS, float3 viewDirWS, float NdotL){float rim = pow(1 - saturate(dot(normalWS, viewDirWS)), _RimPower);float2 rampUV = float2(NdotL * 0.5 + 0.5, 0.5);half3 rampColor = SAMPLE_TEXTURE2D(_RampTex, sampler_RampTex, rampUV).rgb;return lerp(rampColor * _ShadowTint.rgb, rampColor, saturate(NdotL + rim));}ENDHLSLPass{HLSLPROGRAM#pragma vertex vert#pragma fragment fragstruct 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;float3 normalWS : TEXCOORD2;float3 viewDirWS : TEXCOORD3;float4 shadowCoord : TEXCOORD4;};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.normalWS = normInput.normalWS;OUT.viewDirWS = viewDirWS;OUT.shadowCoord = GetShadowCoord(posInput);OUT.uv = IN.uv;return OUT;}half4 frag(Varyings IN) : SV_Target{// 计算陡峭视差UVfloat2 parallaxUV = SteepParallaxMapping(normalize(IN.viewDirTS), IN.uv);// 采样纹理half4 albedo = SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, parallaxUV);half3 normalTS = UnpackNormal(SAMPLE_TEXTURE2D(_NormalMap, sampler_NormalMap, parallaxUV));// 转换法线到世界空间float3x3 TBN = float3x3(normalize(cross(IN.normalWS, IN.viewDirWS)),normalize(IN.normalWS),normalize(IN.viewDirWS));float3 normalWS = mul(TBN, normalTS);// 光照计算Light mainLight = GetMainLight(IN.shadowCoord);float NdotL = saturate(dot(normalWS, mainLight.direction));half3 lighting = StylizedShading(normalWS, normalize(IN.viewDirWS), NdotL);return half4(albedo.rgb * lighting * mainLight.color, 1);}ENDHLSL}}
    }
    

材质配置

参数组合 风格化效果
_ParallaxScale=0.05 + _RimPower=5 轻度凹凸+柔和边缘光
_ParallaxScale=0.1 + _LayerBias=0.4 强烈凹凸+抗失真处理
_ShadowTint=(0.4,0.2,0.6) 紫色调阴影增强风格化表现

【从UnityURP开始探索游戏渲染】专栏-直达
(欢迎点赞留言探讨,更多人加入进来能更加完善这个探索的过程,🙏)

http://www.hskmm.com/?act=detail&tid=38485

相关文章:

  • CI230x WiFi SDK 的TRAE的理解
  • Codeforces Round 1061 (Div. 2)
  • [ms-dos] copy the whole content of a floppy disk a: to c:\tbasic
  • XXL-TOOL v2.3.0 发布 | Java工具类库
  • 前端三剑客——CSS样式
  • first game (2)
  • listary pro
  • Luogu P3862 数圈 题解 [ 蓝 ] [ 递推 ] [ 打表 ]
  • 于课堂与球场间,见成长的底层逻辑
  • 10.24日学习笔记
  • 寻找反射型 XSS 漏洞:完整指南
  • CUDA在windows下的安装及配置
  • 【ArcMap】计算选中线的长度
  • Day3综合案例2:vue简介
  • 在乌鲁木齐办的第一届 新疆tho-东方大巴扎 的一些个人在10月2号和3号的现场观察纪录和乌鲁木齐6月份香蕉喵漫展的一些事
  • NumPy 入门示例系列01
  • 智能识别的力量:卫生许可证OCR技术的应用与价值
  • 一个关于sin的极限
  • 高级语言程序设计作业2
  • 以 “教练” 之姿引航,以 “实践” 之径求知
  • 2025.10.24
  • java:logform
  • 小作业 13(2023 年北京高考圆锥曲线)
  • DeepSeek-OCR 本地部署实践(适合新手、windows环境)
  • 10月24日日记
  • 2025.10.24总结 - A
  • 事务的隔离级别 - Higurashi
  • 2025年AI优化:AI优化公司技术实力哪家好
  • 总账系统核心设计 - 智慧园区
  • 每日反思(2025_10_24)