关于Unity四种合批技术详解
文章目录
- 一.静态合批(StaticBatching)
- 1.启用静态合批
- 2.举例说明
- 3.静态合批的限制
- 4.静态合批的优点缺点
- 5.动态指定物品合批
- 二.动态合批(Dynamic Batching)
- 1.启用动态合批
- 2.合批规则
- 3.举例说明
- 4.使用限制
- 三.GPU Instancing
- 1.启用GPU Instancing
- 2.启用限制
- 3.举例说明
- 四.SRP Batcher
- 1.兼容性
- 2.工作原理
- 3.开启SRP Batcher
- 4.例子
- 五.总结
- 1.优先级
- 2.四种合批的区别
- 3.合批失败信息汇总
Unity中Batching大致可以分为StaticBatching(静态合批),DynamicBatching(动态合批),SRPBatching与GPUInstancing四大类,
这里记录一下这几种拿批的细节
一.静态合批(StaticBatching)
静态合批是Unity的一种优化技术, 本质是将相同材质
并且始终不动
的的Mesh合并
成为一个大Mesh
然后由CPU合并
为一个批次发送给GPU处理,从而减少DrawCall带来的消耗.
1.启用静态合批
可以通过 Project Settings > Player > Other Settings > Static Batching 开启动态合批
选中在场景中物体后在Inspector面板中勾选Static
Unity会将场景中所有的Mesh合并成一个Mesh,但总顶点数不超过2的16次幂
2.举例说明
当前场景中创建4个圆柱体时场景中的DrawCall是5.
我们勾选场景中的静态选项时
可以现发Draw减少到了2
将基中两个改为材质B,会发现DrawCall增加到3
3.静态合批的限制
单次合批最多可以合并64000个顶点,所以需要静态合批的物体需要有网格且处于激活状态.网格读写需要是开启的.
然后Unity会在各个MeshFilter组件中收集Mesh将其合并.
我们可以通过打开Windows > Analysis > Frame Debugger 查看静态合批详细内容
4.静态合批的优点缺点
1):优点
__可以优化DrawCall
__可能使用使用光照贴图
2):缺点
__因为有合并网格的操作所以性能开销会变大
__静态物品不得合批旋转等
5.动态指定物品合批
在满足以条件的情况下,可以使用以下API动态设置批处理
二.动态合批(Dynamic Batching)
与静态拿批不同,动态合批是的物体是可以运动的,但是需要符合Unity内部执行的步骤,我们需要其规则去开发.
1.启用动态合批
可以通过 Project Settings > Player > Other Settings > Dynamic Batching 开启动态合批
2.合批规则
1): 需要使用相关的材质
2): 支持不同Mesh网格之间的合批
3): 单个网个最多支持225个顶点,未来可能会调整.
3.举例说明
1): 例子如图我们创建了一球体使用材质A,以发现只用了了一个Batches:(场景默认用了1个)
2): 复制多个,下显示为7 合批失败.
3): 为什么呢,因为球体的点数是远超过225个顶点的
4): 当我们使用球体
在相同材质下不段创建时,会发现Batch将不断上升
5): 当我们将球体
Mesh换成圆柱体
(88个顶点)时发现,合批成功了
6): 当我们使用圆柱体
在相同材质下不段创建时,会发现Batch将没有变化
7): 当我们在上面动态创建的基础上再去修修改材质参数时,合批也将会被打断
8): 当我们使用的Shader中存在多个Pass时也会导致合批失败
9):当场景中只有一个灯光时可以成功合批
当场景中存在多个灯光如图(红色绿色)时,合批将会被打断
10).我们可以通过打开Windows > Analysis > Frame Debugger 查看合批详细内容
11): 在此可以查看合批失败的原因
4.使用限制
1): 拿批Mesh点数不超过225
2): 不同Mesh相同材质可以合批
3): 相同材质复制出来的材质实例不能合批(修改实例中材质参数会自动创建材质实例)
4): 照片贴图材质必须使用相同光照贴图位置
5): 采用具有多个Pass的Shader将无法合批
6): 合批成功的对像只受一个光照影响
7): 延迟渲染不支持动态合批操作
8): 收集合批信息将加大CPU负担
三.GPU Instancing
GPU Instancing也是Unity提供的一种优化方案,其本质是使用一个DrawCall渲染多个相同材质的网格对像.
从而减少CPU和GPU的开销.比较适合场景中大量重复的物体如树木和草地等.
1.启用GPU Instancing
选择对像后在Inspector
面板中勾选Enable GPU Instancing 即可以启用.
2.启用限制
1.会合并使用相同材质和Mesh的对象
2.材质需要支持GPU Instancing,例如默认标准材质就有
3.Tranform信息需要有所不同,(完全重合了渲染出来也没有意义)
4.未使用SRP Batcher,如有会优先使用SRP Batcher.(在URP渲染管线中是默认开启的)
5.粒子对像不能合批
6.使用MaterialPropertyBlocks的游戏不能合批
7.Shader必须是使用compatible的
3.举例说明
在场景中创建4个圆柱体使用标准材质
选择材质勾选Enable GPU Instancing 后再看,合批成功
可以通过打开Windows > Analysis > Frame Debugger 查看合批详细内容
四.SRP Batcher
SRP Batcher是Unity提供的一种渲染优化技术,它可以将多个网格合并成单个批次进行渲染,从而提高性能。
与其他合批不同,SRP Batcher将未改变属性的Mesh缓存起来,从而减少消耗
1.兼容性
1): 不支持内置渲染管线,支持通用(URP)
/高清(HDRP)
/自定义(SRP)
渲染管线
2): 不使用MaterialPropertyBlocks.
3): 着色器必须兼容SRP Batcher
2.工作原理
在标准的渲染流程下,CPU需要收集所有场景物体的参数,场景中的材质越多CPU提交给GPU的数据就越多.
而在SRP中流程下GPU拥有数据管理的"生命权",管理大量不同材质但Shader变动较小的的内容
让数据在GPU中持久存在,从而减少消耗.
3.开启SRP Batcher
在Package Manager中导入Universal RP(通用渲染管线)
创建通用渲染管线
然后按以下步骤添加通用渲染管线
4.例子
在场景中创建四个圆柱体
运行后会发现已被SRP Batch合并,因为SRP默认是开启的
关闭SRP Batch选项
则会分成4个Bathc进行渲染
五.总结
1.优先级
1): 静态合批会优先使用,如果还兼容SRP Batcher则会同时使用
2): 动态物体会优先使用SRP Batcher
3): 非静态且不支持SRP Batcher才会检查启启用GPU Instancing
4): 以上都不支持才会使用Dynamic Batching
即: Static Batching > SRP Batcher > GPU Instancing > Dynamic Batching
2.四种合批的区别
Static Batching | DynamicBatching | GPUInstancing | SRPBatching | |
---|---|---|---|---|
原理 | 离线合并网格 | 运行时合并网格 | 切换矩阵变换渲染相同物体 | 使用大块常量缓冲区避免切换上下文 |
目的 | 降低SetPass calls | 降低Drawcall | 降低Drawcall | 降低SetPass calls |
优点 | 限制少 | 自动 | 性能极好 | 相同Shader不同材质加速 |
缺点 | 加大包体,加大内容,要求同材质 | 加大CPU消耗,对顶点与材质有要求 | 要求相同物体 | 只能用于SRP |
要求相同Mesh | 否 | 否 | 是 | 否 |
要求相同材质 | 是 | 是 | 是 | 否 |
要求相同Shader | 是 | 是 | 是 | 是 |
要求Shader兼容 | 否 | 否 | 是 | 是 |
适用情形 | 静态场景 | 小物体,特效,UI动态 | 大量相同物体 | 较为广泛,特效和蒙皮网格除外 |
3.合批失败信息汇总
- “An object is affected by multiple forward lights.” 此物体受到多个前向灯光的影
- “Objects have different materials.” 此物体有不同的材质
- “An object is using a multi-pass shader.” 此物体使用了多pass着色器
- “An object has odd negative scaling.” 此物体Trasform的Scale使用了负数
- “Either objects have different \”Receive Shadows\“ settings, or some objects are within the shadow distance, while some other objects are not.” 此物体接收阴影的设置不同,或者物体有不同的的阴影距离设置
- “Objects are affected by different forward lights.” 此物体受到不同的前向灯光影响
- “Objects are on different lighting layers.” 物体在不同的Lighting Layer上
- “Objects have different \”Cast Shadows\“ settings.” 此物体有不同的投影体设置
- “Objects either have different shadow caster shaders, or have different shader properties / keywords that affect the output of the shadow caster pass.” 此物体有不同的投影着色器设置或者有不同的着色器属性或者关键字影响Shadow Caster Pass的输出
- “The shader explicitly disables batching with the \”DisableBatching\“ tag.” 着色器中显式设置了DisableBatching的标记
- “Objects have different MaterialPropertyBlock set.” 此物体有不同的MaterialPropertyBlock的属性集
- “Non-instanced properties set for instanced shader.” Instanced的着色器有非instanced属性集
- “Objects are lightmapped.” 物体使用了不同的LightMap或者虽然使用相同的LightMap但使用的UV不同
- “Objects are affected by different light probes.” 此物体受到不同的光照探针影响
- “Objects are shadowed by baked occlusions and have different occlusion factors.” 此物体烘焙了遮挡,并且设置了不同的遮挡因子
- “Objects are affected by different reflection probes.” 此物体受到不同的反射探针影响
- “Rendering different meshes or submeshes with GPU instancing.” 使用GPU实例化渲染不同的网格或子网格
- “Objects have different batching-static settings.” 此物体有不同的静态合批设置
- “Objects belong to different static batches.” 此物体归属不同的Static Batches
- "Dynamic Batching is turned off in the Player Settings or is disabled temporarily in the current context to avoid z-fighting.” 在Player Settings中关闭了动态合批,或者在当前的环境中为了避免深度冲突而临时关闭了合批
- “There are too many indices (more than 32k) in a dynamic batch.” 动态合批中有太多的索引(大于32k)
- “A mesh renderer has additional vertex streams. Dynamic batching doesn‘t support such mesh renderers.” Mesh Renderer具有其他顶点流。动态批处理不支持此类网格渲染器。
- “A submesh we are trying to dynamic-batch has more than 300 vertices.” 动态合批超过300个顶点
- “A submesh we are trying to dynamic-batch has more than 900 vertex attributes.” 动态合批超过900个顶点属性
- “This is the first draw call of a new shadow cascade.” 新阴影级联的第一次绘制调用
- “The material doesn‘t have GPU instancing enabled.” 材质未启用GPU Instancing功能
- “Objects are rendered using different rendering functions. This can happen if the type of renderer is different (eg Mesh/Skinned Mesh) or when using different settings within the same renderer, such as Sprite Masking.” 使用不同的渲染。如果渲染器的类型不同(例如网格/蒙皮网格),或者在同一渲染器中使用不同的设置(例如精灵遮罩),则可能会发生这种情况。
- “Objects have different batching keys. This is usually caused by using different vertex streams on Particle Systems, or by mixing Lines and Trails, or by mixing lit and unlit geometry.” 此对象具有不同的Batching Keys。 这通常是由于在粒子系统上使用不同的顶点流,或混合线和轨迹,或混合Lit和Unlit的几何体造成的。"
- “Mesh uses 32 bit index buffer.” Mesh使用了32位的索引缓冲
- “Submesh has non-zero base vertex.” 子网格对象有非0的基础顶点, submesh.BaseVertexLocation != 0
- “The previous instanced draw call has reached its maximum instance count.” 先前的InstanceDrawCall已经达到了Instance的最大数量
- “Motion Vector rendering doesn‘t support batching.” Motion Vector的渲染不支持Batching
- “When using late latching, children of an XR late latched GameObject do not use batching.” 使用late latching时,XR late latched GameObject的子级不能合批
- “Objects have different bounds and bounds instancing is disabled.” 对象具有不同的包裹体,那么包裹体实例化被禁用
- “SRP: Node have different shaders.” 节点具有不同的着色器
- “SRP: Node use multi-pass shader” 节点使用了多Pass着色器
- “SRP: Node use different shader keywords” 节点使用了不同的着色器关键字
- “SRP: End of the batch flush” Batch Flush结束
- “SRP: Node is not compatible with SRP batcher” 节点与SRP Batcher不兼容
- “SRP: Node material requires device state change” 节点材质需要改变渲染设备状态
- “SRP: First call from ScriptableRenderLoopJob” ScriptableRenderLoopJob第一次调用
- “SRP: This material has custom buffer override” 材质有自定义重写的Buffer
相关文章:
关于Unity四种合批技术详解
文章目录 一.静态合批(StaticBatching)1.启用静态合批2.举例说明3.静态合批的限制4.静态合批的优点缺点5.动态指定物品合批 二.动态合批(Dynamic Batching)1.启用动态合批2.合批规则3.举例说明4.使用限制 三.GPU Instancing1.启用GPU Instancing2.启用限制3.举例说明 四.SRP Ba…...
自定义注解+拦截器+redis限流
逻辑:写一个注解,自定义在多少秒内限制访问多少次。 自定义拦截器,对于加了注解的请求,在执行方法前。先检查有没有注解,如果有注解就将请求的ipurl拼接作为key。 查询redis中有没有该key,没有就存入&…...
Springcloud物流配送后台-计算机毕业设计源码69809
目 录 摘要 1 绪论 1.1 选题背景与意义 1.2国内外研究现状 1.3论文结构与章节安排 2 物流配送后台系统分析 2.1 可行性分析 2.1.1 技术可行性分析 2.1.2 经济可行性分析 2.1.3 操作可行性分析 2.2 系统流程分析 2.2.1数据增加流程 2.2.2 数据修改流程 2.2.3 数据…...
【Java面试篇】数据埋点监控页面pv的SDK接口实现
面试题如下: 题目要求你实现一个 Monitor.counter(String code, String dim) 接口,用于监控数据统计。 具体要求: 数据聚合: 你需要按照 code 和 dim 的组合进行数据聚合, code 代表监控项的唯一标识, dim 为自定义维度。上报频率: 每分钟上报一次聚合后的数据。数据保证…...
vue3直播视频流easy-player
vue3直播视频流easy-player <script src"/easyPlayer/EasyPlayer-element.min.js"></script> easyPlayer文件下载地址 https://download.csdn.net/download/weixin_42120669/89605739 <template><div class"container"><div …...
Python笔试面试题AI答之面向对象(3)
文章目录 12.Python中OOPS是什么?1. 类(Class)2. 对象(Object)3. 面向对象编程的主要特性4. 面向对象编程的优点 13.解释一下Python中的继承?继承的基本语法继承的特性继承的类型 14. 什么是封装࿱…...
vulnhub靶场serial-php渗透(蜥蜴细!)
目录 一、信息收集 1.探测主机存活(目标主机IP地址) 2.访问web服务 3.后台目录和端口扫描 4.解析bak.zip源码 二、漏洞利用 1.构造payload 2.通过bp的repeater模块 3.get shell 4.获取反弹shell 三、提升权限 1. 查看系统版本,内核…...
Qt Designer,仿作一个ui界面的练习(一):界面的基本布局
初学不要太复杂,先做一个结构简单的,大致规划一下功能分区,绘制草图: 最终的效果: 界面主要由顶边栏、侧边栏、内容区构成。顶边栏左边是logo,右边是时钟显示。侧边栏最上边是切换按钮,用以动画…...
《深入了解 Postman 接口测试工具》
在现代 Web 开发中,接口测试是确保系统稳定性和可靠性的关键环节。Postman 作为一款强大的接口测试工具,为开发者和测试人员提供了便捷、高效的测试体验。本文将深入详解 Postman 的各项功能和使用方法。 一、Postman 简介 Postman 是一款功能丰富的 A…...
java使用org.apache.commons:commons-compress解压 .7z压缩包
前言 java使用org.apache.commons:commons-compress解压 .7z压缩包 一、使用步骤 1.引入库 代码如下(示例):cpmpress需要用到xz依赖,不一起引入会报错。 <!-- https://mvnrepository.com/artifact/org.tukaani/xz --> …...
通过知识库系统实现卓越医疗保健
提供更好的患者治疗效果;提高医疗保健组织的效率和有效性。 利用 Baklib 的力量 Baklib 使患者、代理人和专业人员能够轻松采用知识库系统。 1.对于患者 通过自助在线知识库提供有关药品、测试、服务、康复等的信息,改善患者体验和健康结果。 2.对于…...
基于C语言从0开始手撸MQTT协议代码连接标准的MQTT服务器,完成数据上传和命令下发响应(华为云IOT服务器)
文章目录 一、前言二、搭建开发环境三、网络编程基础概念科普3.1 什么是网络编程3.2 TCP 和 UDP协议介绍3.3 TCP通信的实现过程 四、Windows下的网络编程相关API介绍4.1 常用的函数介绍4.2 函数参数介绍4.3 编写代码体验网络编程 五、访问华为云IOT服务器创建一个产品和设备5.2…...
程序员面试中的“八股文”:敲门砖还是绊脚石?
在现代技术行业中,“八股文”成为了程序员面试中的常见问题。“八股文”究竟能否在实际工作中发挥应有的作用,成了一个备受争议的话题。许多IT从业者都提出疑问:程序员面试到底考察的是什么?是工作能力、工作经验,还是…...
液位传感器- 从零开始认识各种传感器【二十四期】
液位传感器|从零开始认识各种传感器 1、什么是液位传感器 ? 液位传感器是一种用于检测和测量液体位置和高度的装置,广泛应用于工业、农业、环保和家庭等领域。液位传感器可以实时监测液体的水平,以实现自动化控制和安全防护。 2、液位传感器…...
【c++】爬虫到底违不违法?
很多小伙伴都想知道爬虫到底违法吗,今天博主就给大家科普一下 爬虫本身并不违法,但使用爬虫采集数据可能涉及违法风险,具体取决于采集行为是否侵犯了他人的合法权益,尤其是隐私权和个人信息权。以下是对爬虫是否违法的详细分析&am…...
Python基础知识笔记——特殊符号
1. #:注释符号。在它后面的内容直到行尾都会被 Python 解释器忽略,通常用于添加注释说明代码。 2. :赋值运算符。用于将右侧的值赋给左侧的变量。 3. :等于运算符。用于比较两个值是否相等。 4. !:不等于运算符。用…...
Thinkphp仿华为商城源码/红色风格电脑手机数码商城系统网站源码
Thinkphp仿华为商城,主要实现了商品首页展示、用户意见、商品分类列表、商品搜索、商品详细展示、购物车、订单生成、在线付款、以及个人中心完善个人资料、用户修改收货地址、余额查询、消费查询、订单管理、商品评价、热销商品和最近商品浏览; 后台是…...
超有用的数据恢复方法!你一定不要错过!
无论我们当下所使用的是何种设备,例如电脑、U 盘、硬盘、相机、行车记录仪,都难以避免出现误删文件的情况。那么,这些被误删的数据究竟应当通过何种方式找回? 今日,为大家分享若干极为实用的数据恢复方法,望…...
CDH清理磁盘空间完全攻略和完整实现自动化脚本(大数据清除日志)
在CDH集群中,自动清除日志的意义非常重大。尤其是在内网环境下,运维人员无法随时登录服务器进行操作,或者是因为放长假等原因不能每天进行运维工作。这时,如果日志不自动清理,就会面临日志空间满了的问题,这可能造成CDH各组件无法正常工作,离线数仓计算完全停止。 考虑…...
vulhub:Apache解析漏洞apache_parsing
在Apache1.x/2.x中Apache 解析文件的规则是从右到左开始判断解析,如果后缀名为不可识别文件解析,就再往左判断。如 1.php.xxxxx 漏洞原理 Apache HTTPD 支持一个文件拥有多个后缀,并为不同后缀执行不同的指令。比如如下配置文件 AddType te…...
Raspberry Pi Docker 运行 IRIS
在 Raspberry Pi 上成功安装 Docker 后可以安装 IRIS 数据库。 安装的命令为: docker run --name my-iris -d --publish 1972:1972 --publish 52773:52773 intersystems/irishealth-community:latest-em-linux-arm64v8 注意,我们这里暴露了 2 个端口&a…...
【SQL Server】默认端口与自定义端口
目录 第4章:默认端口与自定义端口 SQL Server 默认端口号 更改 SQL Server 端口号 使用自定义端口的好处 示例:更改 SQL Server 端口为 1434 示例代码:更新连接字符串 安全注意事项 第4章:默认端口与自定义端口 SQL Serve…...
【笔记】Android 驻网(网络注册)状态变化的代码实现
背景 基于 Android U/V 代码。 疑问:注册状态是仅看数据吗?通过hasRegistered 确认?从代码看是data 和voice combine的 。 目标:分析注册过程中,Modem返回的code值得含义,以及MD和AP code的映射关系。 功能说明 网络已注册(驻网成功)跟能上网是两码事,比如驻网了也…...
SAP执行董事会变动
以下是SAP发布的新闻: SAP正在进行重大管理层重组,以配合其持续的云转型战略。首席营收官Scott Russell和首席营销与解决方案官Julia White将卸任其职务。SAP首席执行官Christian Klein将暂时接管销售组织的职责。 Scott Russell在全球范围内帮助SAP客…...
css-grid布局之美
一,grid布局概述 网格布局(Grid)是最强大的 CSS 布局方案。 它将网页划分成一个个网格,可以任意组合不同的网格,做出各种各样的布局。以前,只能通过复杂的 CSS 框架达到的效果,现在浏览器内置…...
Python面试整理-异常处理
在Python中,异常处理是一种通过捕获和处理运行时错误来使程序更加健壮和稳定的机制。以下是有关Python异常处理的详细介绍: 异常处理基础 try-except 结构 基本的异常处理结构是try-except块。当代码块中的某些代码可能会引发异常时,可以使用try块将其包含起来,并使用excep…...
linux服务之DHCP(centos7.6)
DHCP服务 1. DHCP介绍 DHCP(Dynamic Host Configuration Protocol,动态主机配置协议),被应用在局域网环境中,主要作用是集中管理、分配IP地址,使网络环境中主机动态的获取IP地址、网关地址、DNS服务器地址等信息,并能…...
2024最新的软件测试面试八股文
🍅 点击文末小卡片 ,免费获取软件测试全套资料,资料在手,涨薪更快 前言 最近有很多粉丝问我,有什么方法能够快速提升自己,通过阿里、腾讯、字节跳动、京东等互联网大厂的面试,我觉得短时间提升…...
C++ STL transform_reduce 用法
一:功能 计算两个向量的内积,它是 std::inner_product 的泛化版本,支持lambda表达式自定义运算。 二:用法 #include <iostream> #include <vector> #include <numeric> #include <execution>int main()…...
MySQL5.7 排序
一、不分组排序 (1).排序-并列数据随机顺序 select col1, col2, rank : rank 1 as rank from (select A as col1,100 as col2union all select B as col1,130 as col2union all select C as col1,120 as col2union all select D as col1,120 as col2order by col2 desc ) a,…...
可以做商城网站的公司吗/下载百度2024最新版
line in接口是线路输入接口的意思,只要将音源通过音频线连接到标记LINE IN的输入接口,并且同时将输入切换开关切换至LINE IN,再缓慢提升音量至适中就可以欣赏音乐。本文操作环境:Windows7系统,Dell G3电脑。LINE IN就是…...
如何设计大气的网站/企业网站模板下载
1、什么是标准文档流 <!-- 什么是标准文档流宏观的将,我们的web页面和ps等设计软件有本质的区别web 网页的制作 是个“流” 从上而下 ,像 “织毛衣”而设计软件 ,想往哪里画东西 就去哪里画标准文档流下 有哪些微观现象?1.空…...
济南微信网站开发/外包网络推广公司怎么选
目录 1、环境准备 2、导入模板 2.1创建模板 3、zabbix客户端设置 4、代码 5、监控效果图 1、环境准备 1、centos7.5 2、zabbix 5.0.4 3、python 2.7 requests模块 4、shell脚本 2、导入模板 模板下载:https://download.csdn.net/download/Hu_wen/1954…...
烟台网站建设诚信臻动传媒/怎么去推广自己的网站
一、相关内存概念在这篇笔记开始之前,我们需要对以下概念有所了解。1.操作系统中的栈和堆注:这里所说的堆和栈与数据结构中的堆和栈不是一回事。我们先来看看一个由C/C/OBJC编译的程序占用内存分布的结构:C:C:OBJC编译的程序占用内存分布的结…...
wordpress内容页主题修改/百度站长平台链接
一、RabbitMQ简述与其docker安装 这里主要讲解实战整合rabbitMQ,了解RabbitMQ简述与其docker安装请点击:传送门 二、springboot整合rabbitMQ 1.新建springboot项目 2.pom:主要添加以下两个依赖 <dependency><groupId>org.springframework.bo…...
iis怎么做网站空间/海外推广渠道
PAGE某某工程实训报告五子棋游戏课程名称 C语言程序设计工程实训姓 名院(系)专业班级学 号指导教师某某大学教务处制PAGEPAGE 23目 录 TOC \o "1-3" \h \z \u1 需求分析 12 系统总框图和功能模块说明 12.1 系统总框图 12.2 功能模块说明 13 系统设计 23.1 主要结构体…...