Unity性能优化-渲染模块(1)-CPU侧(1)-优化方向

Unity 中渲染方面的优化大致可以划分为以下几块核心内容:

  1. CPU 优化 (减少 Draw Calls 和 CPU 瓶颈)

  2. GPU 优化 (减少像素着色和 GPU 瓶颈)

  3. 内存和显存优化 (Resource Management)

  4. 光照优化 (Lighting & Global Illumination)

       这四个方面是相互关联的。一个方面的优化可能会影响到另一个方面。在实际项目中,往往需要综合考虑,并根据 Profiler 数据确定瓶颈所在,然后有针对性地进行优化。我将从这四部分讨论渲染模块的优化。

本期我们先来了解CPU侧的优化。

也许大家之前了解过性能优化,可能听说过一些重要的性能检测指标,比如DrawCall与SetPassCall,Batch与Batching这两对都是不同的概念,我们需要明确区分。

那么这里叠个甲,以下内容含个人经验总结,如有偏差,期待大佬指正。

一.两对相关概念区分

1.DrawCall与SetPassCall

        首先明确一次SetPassCall的性能开销远大于一次DrawCall:
因为它涉及 大量 CPU 与 GPU 状态同步、Shader 切换、资源绑定 等昂贵操作,
Draw Call 只是发出一次“用当前状态绘制”的命令,相对廉价。

        因为在CPU和GPU的时间线上SetPassCall总是先于DrawCall发生,所以这里先写SetPassCall。

(1)SetPassCall

1.概念定义

【表示GPU 渲染状态的切换。次数通常对应渲染过程中实际激活的Pass数量】

        SetPassCall是CPU端的函数调用,用于准备和切换GPU的渲染状态。在CPU上执行状态切换命令的准备和提交,GPU随后执行这些状态切换的实际硬件操作。

2.引起SetPassCall的操作

1.切换 Shader 程序:

(1)最常见且开销最大的改变之一。从使用一个 Shader 切换到另一个 Shader(即使它们逻辑相似,但编译后的程序不同)。
(2)不同 Shader 变体:即使是同一个 Shader 文件,如果由于 Shader Keywords 或 multi_compile导致编译出了不同的变体,切换这些变体也可能被视为 Shader 程序改变,从而触发 SetPassCall。

2.切换 Shader 的Pass:

        在一个SubShader内部,从渲染一个Pass切换到另一个Pass。每个Pass都可以定义自己独立的渲染状态(如混合模式、深度测试、剔除模式等),因此这种切换几乎总是会导致 SetPass Call。

3.切换材质:

(1)引用了不同的材质资产: 即使两个材质看起来使用了相同的 Shader,但如果它们是不同的材质球实例,并且它们所存储的参数有所不同,就可能导致状态改变。

(2)不合理使用MaterialPropertyBlock 虽然 MaterialPropertyBlock 可以减少 Draw Call 数量,但如果每个物体的MaterialPropertyBlock都不同,导致 Draw Call 无法合批。

不合理用法:多个物体使用不同的MPB

 foreach (var cube in cubes){var renderer = cube.GetComponent<Renderer>();var mpb = new MaterialPropertyBlock();// 每个物体颜色不同,都会生成不同的MPB数据mpb.SetColor("_Color", Random.ColorHSV());  renderer.SetPropertyBlock(mpb);}

合理用法:统一MPB数据

    var mpb = new MaterialPropertyBlock();mpb.SetColor("_Color", color);  // 所有物体共享同一个颜色参数foreach (var cube in cubes){var renderer = cube.GetComponent<Renderer>();// 共享同一个 MPB 数据,SRPBatcher 可合批renderer.SetPropertyBlock(mpb);}

4.纹理绑定改变 :

        绑定了新的纹理(包括颜色贴图、法线贴图、光照贴图、阴影贴图等)。虽然许多现代 API 和 Unity 的 SRP Batcher 会尝试优化纹理切换,但从一个完全不同的纹理集切换到另一个仍然是渲染状态的改变。

5.渲染状态设置改变:

(1)混合模式 (Blend Mode): 从不透明到半透明,或从一种混合模式切换到另一种。这也是透明物体无法合批的主要原因之一。

(2)深度测试 (Depth Test):ZTest模式的改变。

(3)深度写入 (Depth Write):ZWrite on变为ZWrite off。透明物体通常关闭深度写入。

(4)剔除模式 (Cull Mode):CullBack(背面剔除)变为CullFront(正面剔除)或CullOff(双面渲染)。

(5)模板操作 (Stencil Operation): 模板缓冲区的读写操作和比较函数的改变。

(6)Alpha 测试 (Alpha Test/Clip): 是否启用 Alpha 测试,以及测试阈值的改变。

(6)写入掩码 (ColorMask/ZWriteMask): 控制哪些颜色通道或深度缓冲区可以被写入。

6.渲染目标改变:将渲染结果从主屏幕缓冲区切换到渲染纹理 (Render Texture),或者从一个渲染纹理切换到另一个。这通常发生在渲染管线的不同阶段,例如:先渲染到深度图,再渲染到主屏幕缓冲区;或者渲染到反射纹理,再将反射纹理作为输入渲染到主屏幕。

7.清除操作 (Clear Buffer): 对帧缓冲区或深度缓冲区进行清除操作。

8.渲染队列改变:Unity 通过RenderQueue对物体进行排序。从一个渲染队列切换到另一个会强制 GPU 完成当前队列中的所有操作,并为下一个队列重新配置状态。

(2)DrawCall

1.概念定义

【DrawCall是CPU端调用的渲染命令,CPU准备并提交绘制数据和状态给GPU。GPU负责执行这些绘制命令,包括顶点处理、图元装配、光栅化及像素着色等整个渲染流程。】

        DrawCall是CPU向GPU提交绘制指令的基本单位,每次调用对应一个渲染请求。需要注意的是DrawCall的基本定义其实只是绘制指令,一次DrawCall可以理解为一次图形API调用一次绘制函数(如OpenGL里的DrawElement,DrawArray)。GPU随后负责把顶点连接成三角形、进行光栅化、执行像素着色等所有后续工作。

        记得我当时学习的时候有一种疑惑,既然DrawCall本质上只是一句渲染(通信)指令,在性能优化的问题中应该是显得微不足道的(当然也不绝对,大量Drawcall也会产生一定的通信压力),可是网络上却有大量的关于DrawCall优化的资料,后来我渐渐理解了,这其中存在语境的不同。在更广泛的语境中,尤其是在讨论性能优化时:Draw Call 也常被用来代指由这条指令所引发的从 CPU 数据准备到 GPU 最终渲染完成的整个流程。

2.引起DrawCall的操作

每绘制一个网格对象,通常就是一个 Draw Call。

即使材质相同,只要有一个物体需要被绘制,就至少产生一个 Draw Call。

主要优化手段是Batching批处理。

(3)二者对CPU的性能影响

主要影响GPU侧的性能。

DrawCall

(1)每个Draw Call都需要CPU准备数据,包括顶点缓冲,索引缓冲,渲染状态等。

(2)CPU负责组织和提交渲染命令,Draw Call越多,CPU命令缓冲区构建压力越大。

(3)过多Draw Call导致CPU渲染线程被占用过多时间,降低帧率。

SetPassCall

CPU上准备渲染状态的开销通常比GPU上改变渲染状态的开销大得多。

(1)SetPassCall触发CPU端复杂的状态管理和验证逻辑。

(2)本质上是CPU发出的切换指令,会打断当前渲染流程,增加同步和缓存刷新开销

2.Batch与Batching

(1)Batch

1.概念定义

        指 最终提交给 GPU 的一组合批渲染数据。一个 Batch 通常代表一次Draw Call。

2.(Game窗口)State面板

        在 Unity 的 Profiler 或 Game 界面(Stats 面板)中,"Batches" 数量通常等同于实际的 Draw Call 数量。

(2)Batching(合批)

1.概念定义

        Batching可以理解为是多个物体被逻辑合并为一个(少量) Batch(一个 Draw Call)的过程。

        Batching是对DrawCall的一种优化技术,指 Unity将多个原本会产生独立 Draw Call 的渲染任务,通过某种优化手段合并成一个或少数几个 Draw Call(也可说Batch),统一提交给 GPU 进行渲染的结果。其目的是为了减少 CPU 向 GPU 发送 Draw Call 的次数,从而提高渲染效率。

2.Unity中的Batching手段

        在Unity中,Batching大致包括四种手段:(1)Static Batching(静态合批),(2)Dynamic Batching(动态合批),(3)GPU Instancing,(4)SRP Batcher(SRP专用)。

二.优化方向

这里仅给出大致的优化方面,后面我会分篇详细介绍并总结以下优化方式。

1.DrawCall优化方向

1. 合批(Batching)

(1)Static Batching(静态合批):适用于不移动的物体,比如地形、墙体等。Unity 会在构建时合并它们的网格,减少运行时的 Draw Call。但它会占用更多内存,因为每个合并后的网格都需要单独保存。

(2)Dynamic Batching(动态合批):适用于顶点数较少、使用相同材质的动态物体,如小道具、粒子等。它会在 CPU 上每帧打包多个物体成一次绘制提交,但会增加 CPU 负担。

(3)GPU Instancing:适用于大量重复的,可以共用同一个 Mesh 和 Shader的对象。可以通过每个实例传入不同参数(如颜色、位移等)来表现差异,CPU 开销低,现代 GPU 支持良好。

(4)SRP Batcher(SRP专用):如果你使用 URP 或 HDRP,务必开启 SRP Batcher。它将材质属性统一打包在大块常量缓冲区里,极大减少 CPU 的重复提交成本。

2. 减少物体数量 / 合并 Mesh

        多个小物体会分别产生 Draw Call。如果这些物体在逻辑上不需要分离(如一整面墙、一个复杂模型),可以在建模时或运行时合并成一个 Mesh,从而一次性绘制。

要注意的是:合并后可能会丧失剔除(Culling)的能力,导致某些看不到的物体仍然被绘制。

3. 优化 UI 绘制

        Unity 的 UI 系统(UGUI)在 Canvas 更新时会重建 Mesh,这会造成大量 Draw Call。

通过将 UI 分层(多个 Canvas),设置 CanvasGroup、使用Canvas.overSorting()等方式,可以减少 Canvas 的重建频率,从而控制 UI 引起的 Draw Call。

4.其他(打包图集)

        打包图集是 “减少材质切换”的手段,本身不直接减少 Draw Call,而是通过减少材质数量,间接支持和促进Batching来降低 Draw Call。

2.SetPassCall优化方向

1. 减少材质数量、统一 Shader

        如果你有多个对象使用了相似的 Shader,但却分别用了不同的材质(即使只是颜色不同),Unity 也会认为它们是不同的 Shader 状态,从而触发新的 SetPass Call。

        使用共享材质,并通过MaterialPropertyBlock来修改不同对象的颜色或参数,就可以避免这个问题而不会打断合批。

2. 合并纹理贴图(打包图集)

        如果你场景中很多对象只是贴图不同,但本质材质逻辑一样,可以将多个纹理打成一张图集(Atlas),然后通过不同的 UV 区域来显示它们。

这样可以使用同一个材质和 Shader,就不会增加额外 SetPass Call。

3. 减少Shader中Pass 数量

        一个 Shader 可能包含多个 Pass,比如用于正面渲染、阴影渲染、深度写入等。每个 Pass 都可能导致新的 SetPass Call。

        如果不需要某些 Pass(如阴影,DepthOnly),建议删掉或通过构建设置剔除(Shader stripping)。特别是在使用 Forward 渲染时,多个灯光可能导致同一个对象被绘制多次(每个光源一个 Pass)。

注意:URP项目中强烈建议主Pass渲染。

4. 确保 Shader 支持 SRP Batcher(如果使用 URP/HDRP)

        要在URP项目中支持 SRP Batcher,需要注意两点:

(1)全局开启:在项目的渲染管线资产配置中开启SRPBatcher。

(2)Shader内编写:Shader 的属性声明必须符合 Unity 的标准结构(如统一定义在 CBuffer 中)。

SRP Batcher 的原理是会把多个对象的材质数据(如各种参数)统一打包到一个大块的 GPU 常量缓冲区(CBuffer)里,并且这些参数必须布局完全一致,这样 GPU 才能批量读取,避免 CPU 多次提交状态切换。如果你的 Shader 参数不是统一定义在 CBuffer 中,而是零散声明的,比如用不同的 uniform 变量或者其他方式,SRP Batcher 就不能正确识别和利用它们。

符合的写法(统一定义在 CBuffer 中)

CBUFFER_START(UnityPerMaterial)float4 _Color;float _Glossiness;float _Metallic;
CBUFFER_END

不符合的写法(零散声明)

float4 _Color;
float _Glossiness;
float _Metallic;

在 Frame Debugger 中,你可以看到哪些物体的材质成功参与了 SRP Batcher,哪些没有。

这里仅给出大致的优化方面,后面我会分篇详细介绍并总结以上优化方式。

本篇完

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/86695.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/86695.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

AI矢量图与视频无痕修复:用Illustrator与After Effects解锁创作新维度

最近因一个项目&#xff0c;有机会深度体验了奥地利Blueskyy艺术学院授权的Adobe教育版全家桶&#xff0c;过程中发现了不少令人惊喜的“黑科技”&#xff0c;很想和大家分享这份发掘宝藏的喜悦。一句话总结这次体验&#xff1a;慷慨且稳定。比如&#xff0c;它每周提供高达150…

Maven Javadoc 插件使用详解

Maven Javadoc 插件使用详解 maven-javadoc-plugin 是 Maven 项目中用于生成 Java API 文档的标准插件&#xff0c;它封装了 JDK 的 javadoc 工具&#xff0c;提供了更便捷的配置和集成方式。 一、基本使用 1. 快速生成 Javadoc 在项目根目录执行以下命令&#xff1a; bas…

Apache Kafka 面试应答指南

Apache Kafka 核心知识详解与面试应答指南 一、Apache Kafka 概述 Apache Kafka 作为一款分布式流处理框架,在实时构建流处理应用领域发挥着关键作用。其最广为人知的核心功能,便是作为企业级消息引擎被众多企业采用。 二、消费者组 (一)定义与原理 消费者组是 Kafka 独…

在NVIDIA Jetson和RTX上运行Google DeepMind的Gemma 3N:多模态AI的边缘计算革命

在NVIDIA Jetson和RTX上运行Google DeepMind的Gemma 3N&#xff1a;多模态AI的边缘计算革命 文章目录 在NVIDIA Jetson和RTX上运行Google DeepMind的Gemma 3N&#xff1a;多模态AI的边缘计算革命引言&#xff1a;多模态AI进入边缘计算时代文章结构概览 第一章&#xff1a;Gemma…

iOS打包流程中的安全处理实践:集成IPA混淆保护的自动化方案

随着iOS应用上线节奏的加快&#xff0c;如何在持续集成&#xff08;CI&#xff09;或交付流程中嵌入安全处理手段&#xff0c;成为开发团队构建自动化发布链路时不可忽视的一环。特别是在App已经完成构建打包&#xff0c;准备分发前这一阶段&#xff0c;对IPA进行结构层面的加固…

FFmpeg进行简单的视频编辑与代码写法实例

使用 FFmpeg 进行简单的视频编辑非常强大。它是一个命令行工具&#xff0c;虽然一开始可能看起来有点复杂&#xff0c;但掌握了基本命令后会非常有用。 以下是一些常见的简单视频编辑操作及其 FFmpeg 命令&#xff1a; 1. 剪切视频 如果你想从一个视频中剪切出一段&#xff0…

如何使用免费软件写论文?六个免费论文生成软件使用指南

在学术写作中&#xff0c;利用AI技术和免费的写作工具可以极大地提高效率&#xff0c;尤其对于需要处理大量文献、结构化写作的论文来说&#xff0c;使用合适的软件能节省时间&#xff0c;提升论文质量。这里为您推荐六个免费的论文生成软件&#xff0c;并提供使用指南&#xf…

大数据系统架构实践(二):Hadoop集群部署

大数据系统架构实践&#xff08;二&#xff09;&#xff1a;Hadoop集群部署 文章目录 大数据系统架构实践&#xff08;二&#xff09;&#xff1a;Hadoop集群部署一、Hadoop简介二、部署前准备三、部署Hadoop集群1. 下载并解压安装包2. 配置hadoop-env.sh3. 配置core-site.xml4…

42道Maven高频题整理(附答案背诵版)

1.简述什么是Maven&#xff1f; Maven是一个项目管理和构建自动化工具&#xff0c;主要服务于Java项目。使用Maven&#xff0c;开发者可以方便地管理项目的构建、文档生成、报告、依赖、SCM&#xff08;软件配置管理&#xff09;、发布和分发等过程。 Maven的核心概念是基于项…

【数字后端】- 如何进行时钟树综合?

首先&#xff0c;要明确的是&#xff0c;时钟树综合只有命令去操作这一种方式 CTS的步骤 1、时钟树综合前的准备工作-设置时钟树cell&#xff08;每个项目必做&#xff09; 最简单的项目要设置生长时钟树时可用的clock buffer和clock inverter cell list&#xff0c;如下 此…

OpenCV CUDA模块设备层-----像素值进行逐通道的最大值比较函数max()

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 是 OpenCV 的 CUDA 模块&#xff08;cv::cudev&#xff09; 中的一个 设备端内联函数&#xff08;device function&#xff09;&#xff0c;用于…

SCSAI万物对象模型和五维市场交易平台原型

一个完整的工业软件对象模型平台&#xff0c;基于SCSAI对象模型和五维市场理论。该平台包含对象管理、五维市场交易和大模型集成功能。 工业软件对象模型平台功能说明 这个平台实现了基于Aras Innovator对象模型和五维市场理论的工业软件解决方案&#xff0c;主要功能包括&…

昇腾のPrefix Cache

Prefix Cache特性介绍 Prefix Cache 即前缀缓存&#xff0c;是一种用于优化大语言模型&#xff08;LLM&#xff09;推理性能的技术&#xff0c;主要应用于多轮对话、系统提示等具有大量共同前缀的场景。 原理 LLM 推理计算主要包括 Prefill 阶段&#xff08;Prompt 计算&…

12-C#的list数据使用

C#的list数据使用 1.实例化 List<double> lst1 new List<double>();2.数据清除 lst1 .Clear();3.数据清除

SQL数据迁移利器:INSERT INTO SELECT语句详解

引言 在数据库操作中&#xff0c;我们经常需要将一个表中的数据迁移或复制到另一个表中。这时候&#xff0c;INSERT INTO SELECT语句就成为了一个极其有用的工具。今天我们就来深入探讨这个强大的SQL语句。 基本语法 INSERT INTO 目标表(字段1, 字段2, ...) SELECT 字段1, 字…

elementUI轮播图组件el-carousel适配移动端大小(图片加载好后根据大小适配)

获取img实例&#xff0c;动态设置el-carousel高度 <template><div class"content main"><el-carousel arrow"always" :height"bannerHeight px"><el-carousel-item v-for"(item, index) in banners" :key"…

AI歌手Yuri出道:GenAI,透露着新的AI产业机遇?

名人说&#xff1a;博观而约取&#xff0c;厚积而薄发。——苏轼《稼说送张琥》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、AI歌手Yuri横空出世1. 爆红的原生MV《SURREAL》2. 背后的创作团队 二、AI歌手背…

常见的自动化测试工具,好学吗?

自动化测试是把以人为驱动的测试行为转化为机器执行的一种过程。它通常涉及预设测试用例&#xff0c;并通过自动化工具或脚本来执行这些用例&#xff0c;最后比较实际结果与期望结果来评估软件的正确性。 常见的自动化测试工具包括Selenium、Appium、JMeter、LoadRunner、Post…

JavaEE初阶第四期:解锁多线程,从 “单车道” 到 “高速公路” 的编程升级(二)

专栏&#xff1a;JavaEE初阶起飞计划 个人主页&#xff1a;手握风云 目录 一、Thread类及常用方法 2.1. Thread的常见构造方法 2.2. Thread的常见属性 2.3. 启动一个线程 2.4. 中断一个线程 2.5. 等待一个线程 2.6. 休眠当前线程 一、Thread类及常用方法 2.1. Thread的…

elk+filebeat收集springboot项目日志

目录 步骤 1: 安装和配置Elasticsearch 步骤 2: 安装和配置Logstash&#xff08;可选&#xff09; 步骤 3: 安装和配置Filebeat 步骤 4: 安装和配置Kibana 要使用ELK&#xff08;Elasticsearch, Logstash, Kibana&#xff09;堆栈和Filebeat来收集Spring Boot项目的日志&am…