unity静态批处理原理理解

 unity静态批处理原理理解

1、静态批处理的时间点

1)在游戏导出的时候,在player setting中勾选static batching,这样在导出包的时候就进行批处理,导出来的包就会比较大

2 ) 在游戏场景中勾选场景物体的static选项,在加载该场景的时候,会进行一次静态批处理的合并,这样导出来的包不大,但是在加载的时候会使得内存变大。

2、静态批处理的基本原理

场景中有4个物体,ABCD,如果都勾选静态选项,在进行静态批处理的时候,引擎会判断这四个物体是否共用同一渲染材质。

如果共用同一渲染材质,则会将这四个物体视为可以批处理的对象,引擎会基于单个渲染对象的大小拷贝出3个,总共变为4个mesh,此时这4个mesh会存在一个index buffer中,此时会让资源占用的内存变大4倍。

3、为什么要用静态批处理?

在游戏的运行中,有时候CPU的瓶颈也会至关重要。如果CPU的运行速度较慢,则GPU会出现等待CPU的情况,此时游戏主要受到CPU的限制。

CPU在游戏中的主要分工,主要分为两个部分:设置渲染状态和调用DC。 其中设置渲染状态属于比较重要的分工,对于加载到游戏中的资源和对象等,CPU需要计算其顶点相关的矩阵,渲染所用的贴图,渲染所用到的材质和shader,渲染所用到的灯光等。

如果每个物体的材质和贴图等都不一样,此时CPU的主要工作就是设置这些物体的渲染状态(当然调用DC也会更多,但此时渲染状态的改变更消耗性能,也就是setPass),游戏的运行会比较缓慢。所以在常见的游戏中,对于大量的不需要改变位置的物体,都会采用静态批处理的方式来解决渲染状态的瓶颈。

采用批处理的方式,对于相同渲染材质的物体,会合并成一个更大的渲染对象mesh来进行渲染,这时候设置合并后的渲染对象的渲染状态,与设置合并前的多个渲染对象的渲染状态相比会大大减小次数。

此外对于大部分的渲染对象,主要的判断依据就是渲染状态和位置矩阵相关的参数。如果渲染状态一致,则基本可以视为同一个批处理的对象,然后对于位置矩阵进行单独的设置即可。其实在引擎的内部,对于需要渲染的对象也会进行一个渲染排序,会优先将渲染状态相同的排在一起进行设置,这样渲染状态的切换就不会过于频繁。

通过批处理的方式来降低渲染状态的切换次数,可以极大的优化CPU的渲染瓶颈,所以在很多时候会采用静态批处理的方式来优化CPU的瓶颈。

4、对于静态批处理后的物体,如何决定其可视?

对于静态批处理后的物体,比如ABCD,那么如何在实际的游戏中去具体的渲染ABCD中的那几个可见(位于相机的视锥体内)? 这需要解释一下批处理的合并方式:在unity5中,会构建一个更大的内存buffer空间,依次存放ABCD的数据。

在渲染A的时候,会调用DX的接口来取这份buffer中的指定起始点和长度的数据出来,传递到GPU中进行渲染。如果需要渲染AD两个对象,则会在前面的基础上,再将整体取出来(因为D存在末尾),然后传递到GPU中进行渲染。注意此时是整体传递A或者ABCD的数据,不会在CPU进行裁剪的工作。具体的A的哪部分可见,实在GPU的顶点裁剪过程中进行的。

此时相当于要进行两次渲染,渲染的次数增大了,这样当然会带来一定的性能损耗,但是相对于渲染状态的设置改变带来的性能损耗,是可以接受的。游戏中如果大量的物体都采用静态批处理,此时会出现很大的内存buffer,如果渲染头和尾部的物体,则会使得渲染数据过大(CPU传递给GPU),带来较大性能损耗,所以可以在游戏中对静态批处理对象进行一个分块的处理。将场景中的对象分成多个块,每个块的大小可以依据一个经验值来设置,此时就会出现多个静态批处理的操作,而不是统一的一个静态批处理操作。具体的分块操作取决于具体的项目的场景大小,可以多次测试得到一个经验值来进行设置。

用户喜欢...

Unity架构常用的几种方式

对于初学者来说,视频《Unity项目架构设计与开发管理》(),全是干货。简单的总结了一下,Unity的架构有如下几种常用的方式。 1、EmptyGO: 在Hierarchy上创建一个空的GameObject,然后挂上所有与...


Unity应用架构设计(13)——日志组件的实施

对于应用程序而言,日志是非常重要的功能,通过日志,我们可以跟踪应用程序的数据状态,记录Crash的日志可以帮助我们分析应用程序崩溃的原因,我们甚至可以通过日志来进行性能的监控...


Unity应用架构设计(10)——绕不开的协程和多线程(Part 2)

在上一回合谈到,客户端应用程序的所有操作都在主线程上进行,所以一些比较耗时的操作可以在异步线程上去进行,充分利用CPU的性能来达到程序的最佳性能。对于Unity而言,又提供了另外...


Unity应用架构设计(10)——绕不开的协程和多线程(Part 1)

在进入本章主题之前,我们必须要了解客户端应用程序都是单线程模型,即只有一个主线程(Main Thread),或者叫做UI线程,即所有的UI控件的创建和操作都是在主线程上完成的。而服务器端应...


Unity应用架构设计(9)——构建统一的 Repository

谈到 『Repository』 仓储模式,第一映像就是封装了对数据的访问和持久化。Repository 模式的理念核心是定义了一个规范,即接口『Interface』,在这个规范里面定义了访问以及持久化数据的行为...


Unity应用架构设计(8)——使用ServiceLocator实现对象的注入

对象的 『注入』 是企业级软件开发经常听到的术语。如果你是一个 Java 程序员,一定对注入有着深刻的映像。不管是SSH框架还是SSM框架,Spring 全家桶永远是绕不过去的弯。通过依赖注入,可...


Unity应用架构设计(7)——IoC工厂理念先行

一谈到 『IoC』,有经验的程序员马上会联想到控制反转,将创建对象的责任反转给工厂。IoC是依赖注入 『DI』 的核心,大名鼎鼎的Spring框架就是一个非常卓越的的控制反转、依赖注入框架。...


干货:Unity游戏开发图片纹理压缩方案

对纹理的处理是智能的:不论你放入的是PNG,PSD还是TGA,它们都会被自动转换成Unity自己的Texture2D格式。 在Texture2D的设置选项中,你可以针对不同的平台,设置不同的压缩格式,如IOS设置成...


Unity应用架构设计(6)——设计动态数据集合ObservableList

什么是 『动态数据集合』 ?简而言之,就是当集合添加、删除项目或者重置时,能提供一种通知机制,告诉UI动态更新界面。有经验的程序员脑海里迸出的第一个词就是 ObservableCollection。没...


Unity应用架构设计(5)——ViewModel之间如何共享数据

对于客户端应用程序而言,单页应用程序(Single Page Application)是最常见的表现形式。有经验的开发人员往往会把一个View分解多个SubView。那么,如何在多个SubView之间 『共享数据』 是一个很...


Unity应用架构设计(4)——设计可复用的SubView和SubViewModel(Part 1)

『可复用』这个词相信大家都熟悉,通过『可复用』的组件,可以大大提高软件开发效率。 值得注意的事,当我们设计一个可复用的面向对象组件时,需要保证其独立性,也就是我们熟知的...


Unity应用架构设计(3)——构建View和ViewModel的生命周期

对于一个View而言,本质上是一个MonoBehaviour。它本身就具备生命周期这个概念,比如,Awake,Start,Update,OnDestory等。这些是非常好的方法,可以让开发者在各个阶段去执行自定义的代码。但唯...


Unity应用架构设计(2)——使用中介者模式解耦ViewModel之间通信

当你开发一个客户端应用程序的时候,往往一个单页会包含很多子模块,在不同的平台下,这些子模块又被叫成子View(视图),或者子Component(组件)。越是复杂的页面,被切割出来的子模...


Unity游戏项目常见性能问题

Unity技术支持团队经常会对有需求的客户公司项目进行游戏项目性能审查与优化,在我们碰到过的各种项目相关的问题中也有很多比较共同的方面,这里我们罗列了一些常见的问题并进行了归...


[技术分享]Unity3D程序脚本反编译分析与加密

前言 对于使用 Unity3D 开发的程序,存在被反编译的风险,也面临着被 dump 内存的威胁,最终引起游戏或工程被抄袭甚至盗版。 下面简单介绍对Unity3D 脚本分析过程,同时提供了对其保护的参...


Unity 2017.2 编辑器与新功能详解

Unity 2017.2提供了全新的2D世界构建工具,支持新的XR平台,并且受益于Unity和Autodesk之间的独家合作,可以更快地在Maya / 3DS Max和Unity之间进行数据的导入和导出。 Unity 2017.2对强大的叙事工具T...