Unity Shader 细节贴图技术在不增加显存开销的前提下,有效提升近距离纹理细节的渲染质量

张开发
2026/5/22 13:07:45 15 分钟阅读
Unity Shader 细节贴图技术在不增加显存开销的前提下,有效提升近距离纹理细节的渲染质量
问题背景近距离纹理的质量挑战在 Unity URP 项目中当摄像机靠近物体表面时纹理会因采样率不足而出现模糊、像素化、重复感等问题。传统的解决方案是使用更高分辨率的纹理但这会带来显著的显存开销。为什么会出现这个问题Mipmap 切换当纹理在屏幕上投影变小时GPU 使用较小的 Mipmap 级别当靠近时使用较大的 Mipmap但这可能导致切换边界可见Tiling 重复平铺纹理在小距离下重复感明显暴露了纹理的平铺周期采样率不足近距离时每个像素覆盖的纹理面积变小但纹理分辨率固定⚠️ 传统解决方案的代价使用 4K 纹理替代 2K 纹理显存增加4 倍约 32MB vs 8MB带宽和采样开销也显著增加。对于移动设备这往往是不可接受的。解决方案细节贴图技术概览细节贴图技术的核心思想是使用高频、小尺度的细节纹理与主纹理混合在不增加主纹理分辨率的情况下丰富近距离细节。主要技术方案四种核心技术技术原理显存开销适用场景细节法线贴图叠加高频法线扰动极低表面微凹凸细节平铺独立 UV 采样低砖墙、路面等Triplanar 映射三轴向投影融合中大型地形、岩石细节遮罩控制混合区域低复杂材质✓ 核心优势细节纹理可以使用较小的分辨率256x256 或 512x512因为它是高频细节不需要存储大尺度的颜色变化。这使得总显存开销接近单张主纹理但细节表现却能接近高分辨率纹理。技术一细节法线贴图 (Detail Normal Map)细节法线贴图通过叠加一张高频法线纹理来扰动主法线为表面添加微小的凹凸细节。这种技术特别适合表现材质的微观粗糙度。数学原理在切线空间下细节法线与主法线通过向量相加或 Re-Orientation 方式合并// 方法一简单向量相加适用于强度较低的情况 half3 BlendNormals(half3 n1, half3 n2) { return normalize(n1 n2 * 0.5); } // 方法二Re-OrientationUnity 官方推荐更物理正确 half3 BlendNormalsReOriented(half3 n1, half3 n2) { half3 t half3(n1.xy half2(1, 1), n1.z * 1.128); half3 u half3(n2.xy * half2(1, 1), 1); half3 r t * dot(t, u) / t.z - u; return normalize(r); } 实现要点细节法线使用更高的 Tiling 值通常是主纹理的 4-8 倍细节法线强度通过纹理 Alpha 或单独的强度参数控制建议使用Re-Orientation方法避免法线偏差累积技术二细节平铺 (Detail Tiling / Secondary UV)细节平铺通过使用独立的 UV 坐标采样细节纹理这些 UV 通常使用更高的 Tiling 值使得细节纹理以更密集的方式重复从而在近距离时提供更丰富的视觉细节。// 声明细节纹理属性 TEXTURE2D(_DetailAlbedoMap); TEXTURE2D(_DetailNormalMap); SAMPLER(sampler_DetailNormalMap); // 细节纹理的 Tiling通常远大于 1 UNITY_INSTANCING_BUFFER_START(Props) UNITY_DEFINE_INSTANCED_PROP(float, _DetailTiling) // 例如4.0 UNITY_DEFINE_INSTANCED_PROP(float, _DetailNormalStrength) // 例如0.5 UNITY_INSTANCING_BUFFER_END(Props) half4 SampleDetailNormal(half2 uv, half3 normalTS) { // 获取实例化的细节 Tiling 值 float tiling UNITY_ACCESS_INSTANCED_PROP(Props, _DetailTiling); float strength UNITY_ACCESS_INSTANCED_PROP(Props, _DetailNormalStrength); // 使用高 Tiling 值采样细节法线 half2 detailUV uv * tiling; half4 detailNormalTex SAMPLE_TEXTURE2D(_DetailNormalMap, sampler_DetailNormalMap, detailUV); // 解码法线并应用强度 half3 detailNormalTS UnpackNormal(detailNormalTex); detailNormalTS.xy * strength; // 混合主法线和细节法线 half3 blendedNormal BlendNormalsReOriented(normalTS, detailNormalTS); return half4(blendedNormal, 1.0); }Shader Graph 实现在 Shader Graph 中实现细节平铺非常直观创建第二个Sample Texture 2D节点连接细节纹理在采样前使用Multiply节点将 UV 乘以较高的 Tiling 值如 4.0使用Normal Reorientation节点合并法线技术三Triplanar 映射Triplanar 映射是一种基于世界坐标的纹理投影技术它从三个相互垂直的方向对纹理进行投影然后根据法线方向进行加权混合。这种方法特别适合大型无缝表面如地形、岩石。half4 SampleTriplanar(TEXTURE2D_PARAM(tex, sam), float3 worldPos, float3 normal, float sharpness) { // 计算三个轴向的权重基于法线方向 half3 weights abs(normal); weights pow(weights, half(sharpness)); // sharpness 控制过渡锐利度 weights weights / (weights.x weights.y weights.z); // 归一化 // 三个轴向的投影坐标使用世界坐标进行采样 half2 uvX half2(worldPos.z, worldPos.y); // YZ 平面投影 half2 uvY half2(worldPos.x, worldPos.z); // XZ 平面投影 half2 uvZ half2(worldPos.x, worldPos.y); // XY 平面投影 // 采样三个方向的纹理 half4 sampleX SAMPLE_TEXTURE2D(tex, sam, uvX); half4 sampleY SAMPLE_TEXTURE2D(tex, sam, uvY); half4 sampleZ SAMPLE_TEXTURE2D(tex, sam, uvZ); // 加权混合三个方向的采样结果 return sampleX * weights.x sampleY * weights.y sampleZ * weights.z; } Triplanar 的优势无需 UV完全基于世界坐标模型不需要展开 UV无缝衔接三个方向投影自然过渡无接缝问题适合大型表面地形、岩石、建筑外墙等无需担心 UV 拉伸Mipmap 友好投影基于世界坐标Mipmap 计算更准确技术四细节遮罩控制 (Detail Mask)细节遮罩用于精确控制细节纹理在表面的分布区域。通过一张灰度图我们可以让细节纹理只在需要的区域出现如裂缝、缝隙、磨损区域避免在不必要的地方产生干扰。// 采样细节遮罩通常是主纹理的 R 通道或 A 通道 half SampleDetailMask(float2 uv) { half4 maskTex SAMPLE_TEXTURE2D(_DetailMask, sampler_DetailMask, uv); return maskTex.r; // 或使用 .a 根据你的遮罩格式 } // 使用遮罩混合细节纹理 half4 ApplyDetailWithMask(float2 mainUV, float2 detailUV) { // 采样主纹理 half4 mainColor SAMPLE_TEXTURE2D(_MainTex, sampler_MainTex, mainUV); // 采样细节纹理 half4 detailColor SAMPLE_TEXTURE2D(_DetailTex, sampler_DetailTex, detailUV); // 采样遮罩使用主 UV因为遮罩通常与主纹理 Tiling 一致 half mask SampleDetailMask(mainUV); // 使用 Lerp 根据遮罩值混合 // 遮罩值越接近 1细节纹理越明显 return lerp(mainColor, detailColor, mask * _DetailStrength); }常见的遮罩存储方式主纹理的 Alpha 通道单独的灰度图 (RGB)RGBA遮罩图分别控制不同细节层高度图辅助计算坡度遮罩完整实现代码下面是一个整合了所有细节贴图技术的完整 Shader 实现。这个 Shader 支持主纹理、细节法线、细节 albedo 和细节遮罩。// // 文件: DetailLitShader.hlsl // 描述: 整合细节贴图技术的 Lit Shader // // --- 属性声明 --- TEXTURE2D(_MainTex); SAMPLER(sampler_MainTex); TEXTURE2D(_MainNormalMap); SAMPLER(sampler_MainNormalMap); TEXTURE2D(_DetailNormalMap); SAMPLER(sampler_DetailNormalMap); TEXTURE2D(_DetailMask); SAMPLER(sampler_DetailMask); UNITY_INSTANCING_BUFFER_START(Props) UNITY_DEFINE_INSTANCED_PROP(float, _DetailNormalTiling) UNITY_DEFINE_INSTANCED_PROP(float, _DetailNormalStrength) UNITY_DEFINE_INSTANCED_PROP(float, _DetailMaskTiling) UNITY_DEFINE_INSTANCED_PROP(float, _UseTriplanar) UNITY_INSTANCING_BUFFER_END(Props) // --- 法线混合函数 --- half3 BlendNormalsReOriented(half3 n1, half3 n2) { half3 t half3(n1.xy half2(1, 1), n1.z * 1.128); half3 u half3(n2.xy * half2(1, 1), 1); half3 r t * dot(t, u) / t.z - u; return normalize(r); } // --- Triplanar 采样函数 --- half4 SampleTriplanarNormal(half3 worldPos, half3 normal, float tiling) { half3 weights abs(normal); weights weights / (weights.x weights.y weights.z); half2 uvX half2(worldPos.z, worldPos.y) * tiling; half2 uvY half2(worldPos.x, worldPos.z) * tiling; half2 uvZ half2(worldPos.x, worldPos.y) * tiling; half4 nx SAMPLE_TEXTURE2D(_DetailNormalMap, sampler_DetailNormalMap, uvX); half4 ny SAMPLE_TEXTURE2D(_DetailNormalMap, sampler_DetailNormalMap, uvY); half4 nz SAMPLE_TEXTURE2D(_DetailNormalMap, sampler_DetailNormalMap, uvZ); half3 result half3(0); result UnpackNormal(nx) * weights.x; result UnpackNormal(ny) * weights.y; result UnpackNormal(nz) * weights.z; return half4(normalize(result), 1); } // --- 主采样函数 --- half4 SampleDetailSurface(float2 uv, float3 worldPos, half3 normalTS) { // 获取实例化参数 float detailTiling UNITY_ACCESS_INSTANCED_PROP(Props, _DetailNormalTiling); float detailStr UNITY_ACCESS_INSTANCED_PROP(Props, _DetailNormalStrength); float useTriplanar UNITY_ACCESS_INSTANCED_PROP(Props, _UseTriplanar); // 1. 采样细节遮罩 float mask SAMPLE_TEXTURE2D(_DetailMask, sampler_DetailMask, uv) * detailStr; // 2. 根据模式选择细节法线采样方式 half4 detailNormalTS; if (useTriplanar 0.5) { // Triplanar 模式基于世界坐标采样 half3 worldNormal half3(0, 1, 0); // 假设输入为切线空间法线 detailNormalTS SampleTriplanarNormal(worldPos, worldNormal, detailTiling); } else { // 标准模式使用 UV 采样 half2 detailUV uv * detailTiling; detailNormalTS SAMPLE_TEXTURE2D(_DetailNormalMap, sampler_DetailNormalMap, detailUV); } // 3. 应用遮罩强度 detailNormalTS.xy * mask; // 4. 混合主法线和细节法线 half3 blendedNormal BlendNormalsReOriented(normalTS, detailNormalTS); return half4(blendedNormal, 1.0); }性能对比与优化建议方案对比方案主纹理细节纹理总显存近距离质量实现复杂度传统 4K4K (32MB)无32MB优秀简单2K 细节2K (8MB)512 (0.5MB)8.5MB良好中等1K 细节1K (2MB)256 (0.125MB)2.1MB中等中等2K Triplanar2K (8MB)无8MB良好中等优化建议最佳实践细节纹理分辨率使用 256x256 或 512x512足够存储高频细节即可Tiling 值主纹理的 4-16 倍根据场景比例调整Mipmap务必为细节纹理生成 Mipmap并使用 Mipmap 级别偏移来隐藏过渡法线强度细节法线强度建议 0.3-0.7过高会导致表面过于崎岖遮罩压缩将遮罩存储在已有纹理的通道中避免额外纹理批处理使用 GPU Instancing 减少 Draw Call⚠️ 注意事项细节纹理在远距离会因 Mipmap 而逐渐消失这是预期行为如果主纹理已经很大如 4K叠加细节纹理的收益会降低对于移动设备需要测试性能影响确保额外的采样不会成为瓶颈总结细节贴图技术是在有限显存预算下提升近距离纹理质量的有效手段。通过合理组合本文介绍的四种技术方案你可以在几乎不增加显存开销的情况下显著提升材质的视觉细节表现。✓ 关键收获细节贴图技术利用高频小尺度纹理补充主纹理的细节缺失四种技术可以组合使用发挥各自优势合理设置 Tiling 值和强度避免过度细节务必生成 Mipmap优化远距离渲染在目标平台进行性能测试确保帧率达标

更多文章