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

Unity 性能优化 之 实战场景简化(LOD策略 | 遮挡剔除 | 光影剔除 | 渲染流程的精简与优化 | Terrain地形优化 | 主光源级联阴影优化)

Unity 之 性能优化实战

  • 场景总览
    • 远景、中景、近景定义
    • 远景简化
    • 模型简化插件
  • LOD策略
  • 遮挡剔除
  • 光影剔除
  • 渲染流程的精简与优化
  • Terrain地形优化
  • 主光源级联阴影优化

场景总览

通过编辑器下的线框模式,可以大致观察到场景三角形与顶点分布情况;

  • SRP渲染管线下,开启Rendering Debugger界面中的OverDraw项,可以观察到场景的OverDraw情况;
  • SRP渲染管线下,将Rendering Debugger界面中的Map Overlays项设置为Main Light Shadow Map,可以检查当前级联阴影可视视距,该视距设置不当将导致Shadow Caster数量过大;
  • SRP渲染管线下,将Rendering Debugger界面中Lighting Debug Mode项设置为Shadow Cascades项,并将Scene视角拉高,同样可以观察到级联阴影的级别范围。

远景、中景、近景定义

  • 远景(Background): 远景是游戏场景中最远的元素,通常用来增加场景的氛围和深度感。远景通常包括天空、远处的山脉、建筑物等,它们通常不可交互,并且在游戏中很少发生变化。

  • 中景(Middle Ground): 中景是游戏场景中介于远景和近景之间的元素。中景通常包括一些比较大的物体或者景观,如建筑、树木、岩石等。这些元素通常可以与玩家进行交互,例如可以作为掩体、跳跃点或者是游戏目标。

  • 近景(Foreground): 近景是游戏场景中最接近玩家的元素,通常位于玩家角色前方。近景通常包括一些较小的物体,如草丛、石头、障碍物等,它们可以通过与玩家交互来增加游戏的挑战性或者提供障碍。

其中中景和近景可能会随着玩家漫游的过程而发生相互转换。

远景简化

对于玩家无法到达的远景,相比于使用真实模型,使用天空盒能够带来较大的性能优化。

天空盒中需要使用到已配置Cube类型Texture的Cubemap材质球,这里提供两个将真实模型转为Cubemap材质球的两种方式:

  1. 在场景中Disable远景之外的所有模型;在场景中添加Reflection Probe,同时将其Type设置为Baked;将Reflection Probe的Static项设置为Reflection Probe Static;在Windows-Rendering-Lighting界面中关闭LightMappingSettings的Auto Generate项;在Reflection Probe的Cubemap Capture Settings中设置符合需求的Clipping Planes,并适当提高Resolution和配置HDR项;在Reflection Probe点击Bake即可烘焙出Cube类型的Texture;创建材质球,将Shader类型选为Skybox/CubeMap,并将烘焙的贴图挂载于此。

  2. 与上述方式的区别主要在于Cube类型Texture的生成。该方式通过Camera.RenderToCubemap将使用摄像机的位置、清除标记和裁剪面距离渲染到CubeTexture上,从而在编辑器中“烘焙”场景的静态CubeTexture或将实时反光渲染到CubeRenderTexture上。需要注意的是,某些图形硬件不支持该功能,一般情况下更推荐使用上述ReflectionProbes的方法。

模型简化插件

Unity Mesh Simplifier,通过该插件可以在编译器中自动生成指定分级的简化模型,并自动配置LOD Group,同时该工具配置Api以进行批量处理。

Amplify Imposters,对模型基于的不同使用类型进行Imporster的生成。

LOD策略

一般来说,LOD分级最好不要超过5级。其中0级使用原始模型,1级使用轻度简化模型,2级为重度简化模型,3级为Imposter,4级为剔除。

  • 对于近景、中景、远景均会出现的对象:
    将其LOD分为4级,0级对应近景使用,1级对应中景使用,2级对应远景使用,3级则为剔除;
  • 对于近景、中景会出现的对象:
    将其LOD分为3级,0级对应近景使用,1级对应中景使用,2级则为剔除;
  • 对于只在近景中会出现的对象:
    将其LOD分为2级,0级对应近景使用,1级则为剔除。

即使是用明确的分级策略,当放置环境不同、物体尺寸不同、物品功能性不同时,各级距离阈值也会有所不同。故需要根据项目实际情况进行LOD配置调整。

对于对象的低LOD级别模型,可以考虑关闭Cast Shadows等配置,以在远景等环境下关闭不必要的视觉效果。

在项目ProjectSettings-Quality中,可以对不同运行平台配置Lod BiasMaximum LOD Level,从而实现不同平台对LOD分级策略的差异。

遮挡剔除

Unity存在Occulusion Culling和Portal Culling两种遮挡剔除方法,本质均为在场景中预烘焙Occulusion数据,在Runtime中根据Camere视锥进行Culling。

  • Occulusion Culling:
    • 适配于可以遮挡、被遮挡的静态对象。
    • 在Window-Rendering-OcculusionCulling界面中,进行对象Static标签中的标记(Occluder\Occludee)、场景遮挡信息的烘焙,同时启动相机上的Occulusion Culling项。
  • Portal Culling:
    • 配置于对于门、窗等可开闭的门户类遮挡物。
    • 无需标记为Static,而是在对象上挂载Occusion Portal组件,并重新进行场景遮挡信息的烘焙。在Runtime中,通过代码逻辑,维护occulusion.open属性,以实现被遮挡对象的实时Culling。

光影剔除

  • 适当配置MeshRenderer的Cast Shadows和Receive Shadows项。例如对于Terrain,其产生的Shadow不可能被Camera观察到,则其不应该Cast Shadows。

  • 可以通过配置灯光Light组件上的CullingMask项,将光源的影响范围限制在指定Layer的对象上。

  • 在SRP管线下,可以使用Light Layer功能。CullingMask用于判定的Layer为Gameobject的Layer,而Light Layer使用的是一套单独的Layer,相对更灵活。需要注意是,自URP14起,该功能重新设计为Rendering Layer功能,其配置过程详见:Unity 官方说明文档。

  • 如果场景内存在实时灯光,则可以考虑通过代码逻辑维护实时灯光的开启、阴影状态。例如当玩家距离非常远时,此时灯光不应产生影子;例如当玩家在室内时,室内封闭空间的灯光可以直接关闭。

  • 在Render Pipeline Asset中,存在若干灯光渲染配置,可以尝试在尽量不破坏视觉效果的前提,调整相关参数。

    • 其中,Per Object Limit项定义了在渲染场景时,每个对象允许接收的光源数量的上限;Shadow Atlas Resolution项定义了渲染阴影时所使用的阴影图集的分辨率;Shadow Resolution Tiers项定义了在渲染阴影时根据距离所使用的不同级别的阴影分辨率;Cascade Count项定义了在渲染阴影时所使用的级联数量。
    • 例如,对于室外非主光源,可以将Per Object Limit项由默认的8调为4;
    • 例如,对于室内非主光源,可以将Shadow Atlas Resolution由默认的4096调为2048,可以将Shadow Resolution Tiers项由1024/2048/4096调为256/512/1048;
    • 例如,对于非主光源,可以将Cascade Count项由默认的4调为2,其中Split1和Last Border分别为37.5m/67.5m;
    • 这些参数数值调整,在性能优化/效果受损方面的平衡非常主观,务必根据实际项目进行评估。

渲染流程的精简与优化

  • Naitive Render Pass
    NaitiveRenderPass相对于传统RenderPass,由于其能够调度到现代图形Api设计出的更灵活的渲染管辖上下文切换渲染目标的方法,故可以在一遍渲染流程的开始与结束时指定贯穿始终的RenderTarget,这样可以在RenderSurface上做显示的Load和Store操作。同时单个NaitiveRenderPass允许运行多个子过程SubPass,这些SubPass可以在像素着色时可以读取到当前帧Pass中的像素信息。所以一些原先在传统RenderPass中需要多Pass才能完成操作,在NativeRenderPass中只需要一遍Pass就能完成,同时在基于Tile-Based Rendering渲染过程的平台上能够有更好的性能表现。

  • 该功能需要依赖图形Api接口,目前Vulken、Metal都有支持,但OpenGL、OpenGL ES无法支持。

  • 自定义Shader需要遵守Unity定义的上下文规则与限制,若不符合对应规范,则会造成相关渲染错误。Amplify Shader Editor生成的Shader无法支持NativeRenderPass。

  • 在延迟渲染管线中,如果目标平台的图形Api支持,则建议开启该选项。如此,可以将DeferrredPass在传统RenderPass模式下所需的两遍Pass,优化为NativeRenderPass模式下的一遍Pass。
    配置方式为,在Universal Renderer Data中启用“Native RendererPas”选项。
    详见官方文档

  • 渲染流程优化
    检查各渲染步骤中,是否存在并非功能需求的Pass,进行对应优化。

Terrain地形优化

Terrin To Mesh

  • Unity引擎中Terrain工具在移动端性能负担较大,尤其是TerrainShader,因此推荐对于地形需求使用基于网格的烘焙/预制体方案,而对于现有Terrain组件建议编写脚本或者使用插件进行Terrain转Mesh的操作。
  • 插件推荐使用Terrain To Mesh 2021。该工具支持将现有地形组件转为Mesh,同时进行地形分块,并支持生成简化的地形碰撞体,且TerrainShader支持纹理数组的传递。不过该工具使用的Splatmap Shader不支持SRP Batcher,这是由于其Shader内部材质属性并没有定义到ConstBuffer中。该插件相关配置参考如下:
    • Mesh中:使用Resolution模式;使地形大小设置Count,不应过大、也不宜过小,以便进行遮挡等剔除操作;勾选Generate Collider,并将Resolution设置为0.5;
    • Material中:使用Splatmap模式,并开启Texture 2D Array;Texture Resolution选用Default/512/512,Texture Format根据目标平台进行配置;
    • Objects中:可以选择性开启,如果可以的话,尽量不要选对植被等Objects进行处理,而是通过对各植被单独做Mesh配置实现,并通过SRP Batcher或GPU Instancing方案进行优化;
    • Save中:勾选Prefab Flags的Static,并选取Occluder Static/Occludee Static/Batching Static/Refelction Probe Static;可以选择性得勾选Tag,并作对应配置,以方便代码逻辑与地形交互。

由于插件中的Splatmap Shader不支持SRP Batcher,可以修改其绘制顺序,如滞后到Opaque的最末绘制。这样可以不打断其他支持SRP Batcher对象的绘制。

主光源级联阴影优化

主光源阴影LOD
虽然可以将主光源级联阴影层级数Cascade Count设置为只有2级,但是如果场景里受主光源影响的物体较多,且均需要为动态阴影时,性能负担依然较大。

因此采用LOD的思路,基于级联阴影层级的配置,对不同距离的阴影采用不同的阴影刷新频率。

在URP源码中,主光源级投影通过MainLightShadowCasterPass.cs脚本实现,可以复制该源码、重命名、并做对应实现,示例如下:

  • 重命名为MainLightShadowCasterCachePass.cs,同时修改UniversalRenderer.cs脚本中对原有MainLightShadowCasterPass对象的类型与命名,例如将对象重命名为m_MainLightShadowCasterCachePass;
  • 移除OnCameraCleanup方法中对m_MainLightShadowmapTexture的释放逻辑;
  • 增加Cleanup方法,实现对m_MainLightShadowmapTexture的释放逻辑,并在UniversalRenderer的Dipose方法中调用m_MainLightShadowCasterCachePass.Cleanup方法;
  • 修改Setup方法中对m_MainLightShadowmapTexture的创建逻辑,只有该Texture为空、或Texture大小发生改变时,才重新创建;
  • 在Setup方法中移除对Clear方法的调用;
  • 增加并维护一个m_FirsetFrame布尔变量,在以记录当前是否是第一帧;
  • 增加m_InterleavePattern整型数组,维护了帧序列绘制时对于不同层级阴影的绘制情况;
  • 增加一个m_InterballeaveIndex整型变量,记录当前绘制到第几帧,以便取模后结合上述数组中获得该帧需要绘制的阴影层级;
  • 移除Configure方法中的ConfigureClear逻辑;
  • 在RenderMainLightCascadeShadowmap方法中的基于m_ShadowCasterCascadesCount的循环里,增加一个根据【当前阴影层级cascadeIndex】、【当前帧序列m_InterballeaveIndex】、【不同层级阴影绘制情况m_InterleavePattern】的判定逻辑,只有满足条件时,才会进行对应实现;
  • 在Setup方法中同样存在一个m_ShadowCasterCascadesCount的循环,需要做上述判定处理;
  • 将上述循环中ShadowUtils.RenderShadowSlice的调用改为自行复制实现RenderShadowSlice方法;
  • 如果目标运行平台为metal图形Api架构,则需要将useNativeRenderPass变量设为false。
    Demo工程:https://github.com/wenhaoGit/MainLightShadowOptimization.git

本文整理自:Metaverse大衍神君《Unity性能优化》

http://www.dtcms.com/a/393717.html

相关文章:

  • [GXYCTF2019]禁止套娃1
  • 【论文阅读】-《Triangle Attack: A Query-efficient Decision-based Adversarial Attack》
  • 云微短剧小程序系统开发:赋能短剧生态,打造全链路数字化解决方案
  • 《从延迟300ms到80ms:GitHub Copilot X+Snyk重构手游跨服社交系统实录》
  • 力扣2132. 用邮票贴满网格图
  • Halcon学习--视觉深度学习
  • LeetCode:40.二叉树的直径
  • dplyr 是 R 语言中一个革命性的数据操作包,它的名字是 “data plier“ 的缩写,意为“数据折叠器“或“数据操作器“
  • 使用Node.js和PostgreSQL构建数据库应用
  • 设计模式(C++)详解—享元模式(1)
  • C++线程池学习 Day08
  • VALUER倾角传感器坐标系的选择
  • 解决 win+R 运行处以及文件资源管理器处无法使用 wt、wsl 命令打开终端
  • R语言 生物分析 CEL 文件是 **Affymetrix 基因芯片的原始扫描文件**,全称 **Cell Intensity File**。
  • Apache Spark Shuffle 文件丢失问题排查与解决方案实践指南
  • xtuoj 0x05-C 项链
  • STM32F429I-DISC1【读取板载运动传感器数据】
  • 【Kafka面试精讲 Day 21】Kafka Connect数据集成
  • 2025数据资产管理平台深度分析:技术特性、与选型逻辑
  • RabbitMQ Java 解决消息丢失、重复和积压问题
  • 深入解析 Spring AI 系列:解析请求参数处理
  • OpenLayers地图交互 -- 章节五:捕捉交互详解
  • 阿瓦隆1566HA-448T矿机深度解析:性能、效率与冷却技术
  • 平替confluence,推荐一款国产开源免费的知识管理工具 - sward
  • 【开源】基于STM32的智能垃圾桶
  • RuoYi-Cloud问题:访问https的网关地址,实际是访问http的文件服务
  • HttpClientFactory vs new HttpClient:.NET Core HTTP 客户端的正确打开方式
  • MySQL数据库(七)—— 基于主主复制与 Keepalived 非抢占模式的高可用方案
  • 如何提高Java并发编程的实战能力?
  • JavaWeb 课堂笔记 —— 17 SpringBootWeb案例 部门管理