十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

从《明日方舟:终末地》看懂游戏纹理精细渲染的技术细节

从《明日方舟:终末地》看懂游戏纹理精细渲染的技术细节 最近游戏圈里有一段很热门的实机画面来自 UP 主籽岷上传的《明日方舟终末地》试玩演示。弹幕里有一条评论特别有意思“岷叔依旧爱嗨丝一潜图连纹理都画出来了”很多人看到这句话就划过去了觉得无非是玩家在夸画面“精致”“细节多”。但站在技术角度这句玩笑话其实戳中了一个非常硬核的问题为什么有些游戏近看就糊而有些游戏的画面经得起玩家贴脸截图“连纹理都画出来了”这句话翻译成图形学语言就是角色身上的材质贴图分辨率足够高、UV 密度足够合理、采样过滤没有糊成一片并且光照反馈真实到让玩家一眼能认出“这是什么布料”。这篇文章我想借《明日方舟终末地》这个话题把“游戏画面为什么看起来精细”这件事拆开讲清楚。不讲玄学只讲渲染管线和材质贴图里那些真正起作用的环节。读完你会知道玩家嘴里一句“纹理清晰”背后到底堆了多少技术细节如果自己做 Unity 或 Unreal 项目又该如何复现这种“经得起细看”的画面。1. 一句“纹理都画出来了”扇在了谁的耳光上先说一个很常见的误区很多非图形方向的开发者觉得游戏画面好不好看取决于美术画得好不好。这个判断只对了一半。美术确实决定了贴图里“画了什么”但贴图能不能在屏幕上呈现出“画了什么”是渲染管线的功劳。换句话说一张 4K 分辨率的精美布料贴图如果材质球的粗糙度设置错误或者纹理过滤方式不对最终效果可能还不如一张 512 的低清贴图。《终末地》能让人产生“连纹理都画出来了”的感叹说明它在以下四件事上都没掉链子贴图分辨率与 UV 密度角色身上的布料纹理足够清晰没有拉伸模糊。材质反馈真实不同布料对光的吸收和反射不同黑丝、皮衣、棉服不会互相串质感。光照与阴影配合纹理在暗环境下不会直接糊掉光照能保留材质细节。远近渲染连续玩家拉近镜头时画面不会突然“露馅”。这四件事任何一件做不好玩家都不会发出“纹理都画出来了”这种感叹。所以这句话表面上是在夸美术实际上是在夸整个渲染链路。从技术学习角度这就是一个绝佳的拆解样本。因为《终末地》使用的是 Unity 引擎它走的是风格化渲染路线没有追求 3A 写实大作那种“极致拟真”而是用更克制的技术组合把画面做得干净、精细、有辨识度。这种路线对中小型团队反而更有参考价值。换个角度说如果我们自己做一个 Unity 项目希望角色靠近镜头时也有这种“纹理可数”的效果该从哪里下手接下来的内容就是回答这个问题。2. 《明日方舟终末地》一款值得做技术拆解的游戏在深入渲染细节之前先明确我们讨论的对象。《明日方舟终末地》Arknights: Endfield是鹰角网络开发的 3D 即时策略 RPG是《明日方舟》IP 的续作。和原作 2D 塔防不同这一代采用了全 3D 角色和场景支持大世界探索战斗系统也从“塔防策略”转向了“即时指挥 策略配合”。从公开的实机演示看角色可以自由移动、切换攻击目标、释放技能场景中有大量可交互的工业设施和野外地形。从画面风格来看《终末地》走的是“风格化写实”路线角色比例接近真人但五官和发型保留明显二次元审美场景追求真实光照但在材质上用较简洁的 PBR 参数避免写实游戏常见的脏、旧、乱。这种风格路线的技术难点在于它既要让二次元玩家觉得“好看”又要让画面具有足够的信息密度不能像传统二次元网游那样“一片光滑”。因此材质细节、纹理密度、光照层次都必须做到位否则画面会显得空、薄、假。从 Unity 技术视角看《终末地》的渲染思路大致可以拆成四层层级内容解决的问题几何层模型精度、UV 展开、法线贴图角色轮廓和曲面细节是否准确材质层PBR 参数、贴图组、着色器不同材质是否有正确的质感光照层直接光、间接光、AO、阴影画面是否有体积感和层次感后处理层抗锯齿、泛光、颜色分级最终画面是否干净、统一后文会逐个展开重点落在材质层和光照层因为这正是“连纹理都画出来了”这句话的真正源头。3. 纹理细节的基础PBR 材质与贴图体系3.1 PBR 到底在说什么PBRPhysically Based Rendering基于物理的渲染是现代商业引擎默认的材质方案它的核心思想是用一组通用的物理参数描述材质然后在任何光照环境下都能得到一致的结果。在 Unity 的标准着色器里一个 PBR 材质通常由五个核心贴图控制贴图英文名含义直观效果反照率贴图Albedo / BaseMap材质固有色决定“这块布是什么颜色”法线贴图Normal Map表面凹凸信息决定“布纹、缝线、褶皱是否明显”粗糙度贴图Roughness / Smoothness表面光滑程度决定“是哑光棉还是反光皮革”金属度贴图Metallic是否是金属决定“是否有金属反射”环境光遮蔽贴图AO缝隙的阴影让布纹和结构更有层次很多新手第一次接触 PBR容易把注意力全部放在反照率贴图上觉得“贴图画得精细 纹理清晰”。但实际上法线贴图和粗糙度贴图对“看起来真不真”的影响往往比反照率贴图更大。以黑丝材质为例黑丝本身的固有色接近黑色反照率贴图几乎是一张黑图。如果只靠反照率玩家根本看不清纹理。真正让黑丝“看起来是织物”的是法线贴图里细密的网格凹凸信息以及粗糙度贴图里纱线交织产生的微弱高光变化。再加上半透明渲染织物下的皮肤肤色能透出来这才有了“嗨丝”的质感。3.2 为什么很多游戏“近看就糊”贴图画得再精细如果 UV 密度不合理靠近镜头时依然会糊。这里需要理解两个概念UV 密度指模型表面每单位面积分配的贴图像素数量。同样一张 2048 的贴图如果角色的脸只占 20% 的 UV 面积那脸部的有效分辨率就很高如果身体大面积占用 UDIM脸的精度就低。纹素密度Texel Density在场景搭建中通常用“每米多少像素”来衡量。比如角色近距离看需要 1024 px/m远景建筑可能只需要 128 px/m。当模型近看时如果贴图分辨率不够相机会把贴图放大这时就会出现马赛克或模糊。引擎通常会通过 mipmap 来避免这种情况但 mipmap 远看是优化近看并不能凭空增加细节。所以一个模型能承受多大程度的“贴脸看”在建模和 UV 阶段就已经决定了。材质和着色器只能在这个基础上做优化无法逆转。4. 服装材质渲染从“嗨丝”聊到织物着色“嗨丝”是一个网络谐音称呼游戏里通常指角色穿着的黑色丝袜。弹幕调侃的“岷叔依旧爱嗨丝”翻译成技术话题就是半透明织物材质在游戏引擎里到底怎么渲染才能既保留细密纹理又不显廉价4.1 织物材质的三个难点第一织物的表面是凹凸不平的纱线之间有微观缝隙直接拍一张照片贴上去光线一变就会显得假。正确做法是用法线贴图模拟纱线交织的微观凹凸再用粗糙度变化模拟不同部位的磨损和张力。第二织物往往有半透明区域尤其是丝袜、纱裙、镂空部位。半透明材质要参与渲染排序如果不做特殊处理容易出现穿模、遮挡顺序错误、深度冲突。第三织物和皮肤是“贴合”的靠近皮肤的区域会有次表面散射效果尤其是暗色织物下的皮肤阳光照射时会有一种柔和的透红感。完全模拟这种效果需要次表面散射SSS移动端很难全屏运行所以常见做法是用一张透光贴图Backlight / Transmission Map来模拟。4.2 一个织物材质 Shader 的最小示例在 Unity 的 URP 管线里可以写一个简单的 Shader 来控制织物材质的核心参数把不同贴图通道的作用暴露给美术。下面是一个基于 ShaderLab 的简化示例。Shader Custom/FabricPBR { Properties { _BaseMap (Albedo, 2D) white {} _NormalMap (Normal, 2D) bump {} _RoughnessMap (Roughness, 2D) white {} _AO (AO, 2D) white {} _Metallic (Metallic, Range(0,1)) 0.0 _Transparency (Transparency, Range(0,1)) 0.0 _TransmissionColor (Transmission Color, Color) (1, 0.2, 0.1, 1) } SubShader { Tags { RenderTypeTransparent QueueTransparent } Blend SrcAlpha OneMinusSrcAlpha ZWrite Off Pass { HLSLPROGRAM #pragma vertex vert #pragma fragment frag #include Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl #include Packages/com.unity.render-pipelines.universal/ShaderLibrary/Lighting.hlsl struct Attributes { float4 positionOS : POSITION; float2 uv : TEXCOORD0; float3 normalOS : NORMAL; }; struct Varyings { float4 positionHCS : SV_POSITION; float2 uv : TEXCOORD0; float3 normalWS : TEXCOORD1; float3 positionWS : TEXCOORD2; }; TEXTURE2D(_BaseMap); SAMPLER(sampler_BaseMap); TEXTURE2D(_NormalMap); SAMPLER(sampler_NormalMap); TEXTURE2D(_RoughnessMap); SAMPLER(sampler_RoughnessMap); TEXTURE2D(_AO); SAMPLER(sampler_AO); CBUFFER_START(UnityPerMaterial) float4 _BaseMap_ST; float _Metallic; float _Transparency; float4 _TransmissionColor; CBUFFER_END Varyings vert(Attributes input) { Varyings output; output.positionHCS TransformObjectToHClip(input.positionOS.xyz); output.positionWS TransformObjectToWorld(input.positionOS.xyz); output.normalWS TransformObjectToWorldNormal(input.normalOS); output.uv TRANSFORM_TEX(input.uv, _BaseMap); return output; } half4 frag(Varyings input) : SV_Target { float3 albedo SAMPLE_TEXTURE2D(_BaseMap, sampler_BaseMap, input.uv).rgb; float roughness SAMPLE_TEXTURE2D(_RoughnessMap, sampler_RoughnessMap, input.uv).r; float ao SAMPLE_TEXTURE2D(_AO, sampler_AO, input.uv).r; Light mainLight GetMainLight(); float3 normalWS normalize(input.normalWS); float NdotL saturate(dot(normalWS, mainLight.direction)); float3 color albedo * mainLight.color * (NdotL * ao 0.15); // 模拟织物透光 float transmission (1.0 - NdotL) * _Transparency; color _TransmissionColor.rgb * transmission; return half4(color, _Transparency); } ENDHLSL } } }这段代码的核心是最后两行当光线从背面穿过织物时用_TransmissionColor叠加一层透光色再通过_Transparency控制整体透明度。这样美术只需要调一个透明度和一个透光颜色就能做出“暗色织物下皮肤透出微光”的感觉。实际项目中建议在这个基础上继续叠加 Shadow Caster Pass并处理深度写入问题。尤其在移动端大量半透明物体会导致 Overdraw 激增需要严格控制半透明材质的面积和数量。4.3 不同“黑丝”是同一张贴图吗答案是否定的。黑丝、皮裤、漆皮靴在游戏美术里是三套完全不同的材质参数只是在颜色上都是黑色。皮裤需要极高的 Smoothness光滑度和较强的反射法线贴图强调紧绷的褶皱黑丝则需要半透明混合、细密网格法线、粗糙度偏高漆皮靴需要金属度接近 0但光滑度和反射率都很高。如果美术只用一张黑色反照率贴图走天下渲染出来的结果就是“塑料感”。这也是很多低质量二次元游戏常见的问题角色都像穿了同一件黑色雨衣。所以看到“连纹理都画出来了”这句话时真正值得关注的信息是这套角色材质系统把不同织物的参数区分开了让玩家靠视觉就能识别出材质。这种认知识别的能力在图形学里叫 Material Recognition是衡量渲染质量的重要指标。5. 潜行玩法为什么更考验画面技术“一潜图连纹理都画出来了”如果理解成“一张潜行截图”那就更有意思了。潜行玩法本身恰好是对渲染系统压力最大的场景之一。原因很简单潜行意味着角色经常处于阴影中、遮挡中、边缘位置。而纹理细节在低照度下的可见性恰恰是画面技术最难保证的部分。5.1 暗环境下纹理为什么容易“消失”人在昏暗环境下辨认可视物靠的是微弱的光线变化和明暗边界。如果游戏渲染时没有正确处理间接光照和环境遮蔽暗部的纹理就会直接糊成一片黑别说纹理连轮廓都看不清。而《终末地》的潜行画面能做到“暗处也有纹理”说明它的光照系统至少做了三件事环境光不是纯黑而是有方向的间接光保证了暗部的基础亮度。环境光遮蔽AO的强度经过调校不会让缝隙死黑也不会让暗部一片平。后处理阶段对暗部做了颜色分级Color Grading提升了暗部层次而不是简单压黑。5.2 体积光在潜行氛围中的作用潜行场景通常需要体积光来营造氛围——从窗口射入的光柱、门缝透出的光线、尘埃飘在光束里的效果。这些光会让画面“看见空气”也会让潜行路线在视觉上更清晰。Unity 中可以在需要的地方手动添加体积光闪烁效果也可以直接用 Post-processing 的体积光插件。下面是一个可以在 URP 中使用的后处理体积光脚本示例。using UnityEngine; using UnityEngine.Rendering; using UnityEngine.Rendering.Universal; public class VolumetricLightController : MonoBehaviour { public Material volumetricLightMaterial; public Light directionalLight; [Range(0f, 4f)] public float density 1.2f; void OnRenderImage(RenderTexture source, RenderTexture destination) { if (volumetricLightMaterial null || directionalLight null) { Graphics.Blit(source, destination); return; } volumetricLightMaterial.SetVector(_LightDir, -directionalLight.transform.forward); volumetricLightMaterial.SetFloat(_Density, density); Graphics.Blit(source, destination, volumetricLightMaterial); } }这只是示意代码实际接入 URP 时需要在自己的 Renderer Feature 里调用 Blit不能直接挂OnRenderImage。但思路是一致的把方向光的方向和浓度参数传给材质在后处理阶段叠加体积光效果。值得提醒的是体积光是特效里非常昂贵的开销。移动端不建议全屏幕、全场景开启更合理的做法是在特定潜行关卡用局部 Trigger 控制密度玩家进入区域后动态提高体积光强度平时保持关闭或低强度。潜行画面真正让人“看得清纹理”的是暗部细节的保留而不是把画面调亮。调亮画面会破坏氛围保留暗部细节才能既紧张又清晰。6. 大场景的纹理加载不糊、不跳、不穿帮如果说角色材质的精细度决定了“近看美不美”那么大场景的纹理加载就决定了“远看稳不稳”。开放地图里玩家会快速跑动、切换视角如果纹理流送Texture Streaming做得不好就会出现两个经典问题场景突然从低清变成高清弹出或者远景贴图一直模糊糊死。6.1 为什么不能一张贴图走天下一个大型野外场景可能有上万个物件不可能每个物件都使用 2048 甚至 4096 的贴图。那样显存会瞬间爆掉。正确做法是根据物体与相机的距离动态切换不同精度的贴图这就是 mipmap 和 LOD 的用途。在 Unity 里导入纹理时一定要正确开启 Mipmap 选项。这个选项在 Inspector 面板的Advanced区域里勾选Generate Mip Maps后引擎会生成一系列由细致到模糊的降采样贴图远距离采样时自动选择低精度 Mip 层减少显存占用和带宽消耗。如果关闭 Mipmap远距离物体在缩放时会出现严重的闪烁和水波纹现象。6.2 Unity Texture Streaming 配置示例新版本的 Unity2021.2内置了 Texture Streaming 功能。开启后引擎可以根据相机距离动态加载合适精度的纹理而不是一开始就加载最高精度。在Project Settings Quality Textures里做如下配置using UnityEngine; public class TextureStreamingConfig : MonoBehaviour { void Start() { if (TextureStreaming.enabled false) { // 开启纹理流送 TextureStreaming.enabled true; // 限制最大纹理预算单位MB TextureStreaming.memoryBudget 1024; // 每帧最多加载的纹理数量 TextureStreaming.maxPendingFrames 4; } } }这段代码会在游戏启动时开启纹理流送并把显存预算限制在 1GB 左右同时控制每帧加载的纹理数量避免瞬时卡顿。在实际项目中还需要为纹理设置正确的压缩格式。Android 平台建议优先选择 ASTCiOS 平台使用 ASTC 或 ETC2这是移动端纹理压缩的主流方案。选错压缩格式或者不压缩会带来明显的显存压力。6.3 LOD 与纹理流送配合LODLevel of Detail和纹理流送是两套系统但必须配合使用。LOD 控制的是模型面数纹理流送控制的是贴图精度。如果一个模型切换了低精度面数但贴图依然是 4096传输带宽就会被白白浪费。更合理的做法是LOD 0近距离使用完整模型 高质量贴图LOD 1中距离使用简化模型 中等精度贴图LOD 2远距离使用极简模型 低精度贴图。Unity 的LODGroup组件可以设置各层级的切换距离。美术在建模时就应该规划好层级而不是在项目后期才补。7. 普通开发者可以从《终末地》画面上学到什么开篇说过这篇文章不只是夸《终末地》更想聊“如何让画面经得起细看”。从可操作性出发我建议从四个方向入手。7.1 先定渲染风格再定贴图规范很多团队在项目启动时只定玩法画面风格很模糊导致美术做了一批高精度贴图后期性能不达标又整体压缩最后效果两头不到岸。正确的顺序是先明确画面是写实、二次元还是风格化再确定使用的渲染管线是 URP 还是 HDRP最后根据管线能力制定贴图分辨率、压缩格式和 LOD 层级。贴图规范不是美术单方面的事而是渲染管线和美术风格共同得出的结果。7.2 纹理精度按“最近观察距离”设计一个角色会被玩家贴脸看那么在角色脸上就应该使用更高的纹素密度一个装饰瓶只会被扫一眼就没必要塞进 4096 贴图。实际项目中可以用一个简单公式估算合适的贴图分辨率 ≈ 屏幕高度像素 × 观察期望占比。这个思路同样适用于场景物件。玩家在潜行玩法中会长时间躲在物体后面、贴着墙移动那么潜行区域的墙体、管道、地面材质就需要比普通区域更高的贴图精度。这也是《终末地》“潜行截图纹理清晰”的原因之一制作者在关键玩法区域提高了贴图规格。7.3 把材质参数暴露给美术而不是写死在 Shader 里新手写 Shader 时喜欢把各种数值直接写死在代码里美术看到的是一个不能调整的“黑盒”只能反复提需求。更成熟的团队会定义一整套材质面板把颜色、粗糙度、金属度、透明度、透光颜色、AO 强度全部暴露出来再配合材质球预设让美术可以在编辑器里快速调整并实时看到效果。从协作效率来看材质参数化比纠结某一张贴图画得好不好更要紧。因为它能极大减少沟通成本让美术在引擎里完成迭代而不是每次改完贴图还要等程序改代码。7.4 性能预算要先定再优化而不是最后“救火”画面精细度和性能几乎永远是对立的。不做预算的后果是项目后期发现手机跑不动只能一刀切降低贴图精度、关闭后处理结果画面塌方前面的精细工作全部白费。比较合理的做法是在项目初期就确定目标机型为 Draw Call、显存、填充率、Overdraw 分别设置预算。例如角色材质允许 3 层贴图采样、玩家可见场景同时存在最多 30 个高质量材质球、半透明材质的屏幕占比不超过 20%。这样在执行“精细纹理”时始终知道用什么代价去换取效果。8. 常见问题与排查方法关于纹理清晰度和画面精细感大家在 Unity 项目里问得最多的就是下面几类问题。直接整理成排查表格。问题现象可能原因排查方式解决方案贴图近距离模糊、像蒙了一层雾纹理分辨率不足或 mipmap 过滤导致近看用了低精度层在纹理 Inspector 中检查分辨率和 Mip Bias 设置提高纹理分辨率调整 Mip Bias 让近看时偏向更清晰层纹理闪烁、有摩尔纹远处纹理没有正确生成 mipmap观察运行时纹理面板确认 mipmap 层数在导入设置中勾选 Generate Mip Maps开启 Aniso Level暗处一片黑纹理完全看不清环境光过暗AO 过强后处理压暗过度关闭 AO 和后处理逐项排查在暗部增加均匀的环境光强度调低 AO 强度使用颜色分级提升暗部层次半透明织物渲染穿模、排序错误没有设置正确的 Render Queue 和 ZWrite观察透明物体之间的遮挡顺序设置透明渲染队列关闭 ZWrite 时注意排序复杂情况考虑使用深度写入 Pass角色胸口或袖口出现明显拉伸花纹UV 展开不合理纹素密度不均匀在建模软件中检查 UV 岛是否均匀重展 UV均匀分配面积重要区域单独分配高密度 UV 岛场景加载时贴图忽清忽糊纹理流送预算不足或加载速度跟不上查看 Texture Streaming 控制台日志和内存统计提高内存预算减少单帧加载的纹理数量优化压缩格式球面或圆柱表面高光呈现条状断层法线贴图精度不足查看法线贴图细节和压缩格式改用无损或更高精度的法线压缩格式检查法线贴图是否被过度压缩这些问题的共性在于“纹理清晰”并不是贴图分辨率这一个变量决定的。多数糊、假、脏的问题是贴图、UV、材质、光照、后处理多个环节组合失误的结果。排查时要学会控制变量逐层定位而不是一上来就重画贴图。9. 总结与后续学习方向回到文章开头的那个弹幕“连纹理都画出来了。”这句话看似是玩家对画面细节的欣赏实际上是对一整套渲染技术的肯定。它背后是 PBR 材质系统的正确使用、UV 密度与贴图分辨率的匹配、光照和阴影对暗部细节的保留、半透明织物材质的透光处理以及大场景纹理流送的稳定表现。如果你现在正在做一个 Unity 项目并且希望角色在近距离观察下也有足够的材质细节我的建议是按这个顺序推进。第一步检查项目是否使用了 URP 或 HDRP 这类可编程渲染管线。内置管线在材质扩展性和后处理能力上都有明显瓶颈。第二步建立贴图规范和纹素密度标准。先确保美术在产出贴图时有统一的分辨率、压缩格式和 UV 密度预期而不是靠个人感觉。第三步从最简单的 PBR 材质开始逐个理解反照率、法线、粗糙度、金属度、AO 这五个贴图的作用。不要急着写复杂的 Shader先用引擎内置的 Lit/Standard 材质把基础质感调对。第四步用 GPU Profiler 观察真实设备的渲染耗时。重点看半透明区域的开销、纹理采样的带宽、以及材质数量对 Draw Call 的影响。第五步等基础链路稳定后再尝试自定义 Shader、体积光、透光材质、纹理流送等进阶功能。后续值得深入学习的方向包括URP 的 Renderer Feature 机制、ShaderGraph 的节点化材质编辑、GPU Instancing 对场景渲染的优化、以及 PBR 背后的 BRDF 理论。理解了这些再回看《终末地》的画面时你看到的就不只是“好看”而是一整套成熟的技术决策。如果这篇文章对你有帮助建议收藏备用。遇到画面“糊、假、脏”的问题时按第 8 节的排查表逐项检查大概率能找到原因。也欢迎在评论区分享你的材质踩坑经历碰到具体问题可以一起讨论。
返回列表