目录
对象池
减少Draw Calls
批处理
合并网格
贴图集
LOD
基本原理
应用
优点
挑战
LightMap
基本概念
如何工作
优点
缺点
使用对象池:频繁地创建和销毁对象会导致性能下降和内存碎片化。对象池可以预先创建一些对象,然后在需要时从池中取出,不再使用时再放回池中。
Draw Call是指CPU向GPU发送绘制命令的次数。减少Draw Call可以通过批处理,合并网格,使用贴图集等方法实现。
批处理(Batching)是在游戏开发和3D图形渲染中常用的一种性能优化技术,尤其在使用像Unity这样的游戏引擎时。它的核心目的是减少CPU向GPU发送的绘制指令(即Draw Calls)的数量,从而提升渲染效率。以下是详细的批处理概念和使用方法:
批处理的基本概念
Draw Call:Draw Call是CPU告诉GPU:“请绘制这个对象”的命令。每个Draw Call都涉及状态设置、顶点数据传输等操作,这些都会消耗时间和资源。
批处理:批处理的思想是将多个渲染操作组合成一个较大的批次(Batch),以减少Draw Calls的总数。这通常涉及将使用相同材质和纹理的多个对象渲染为一个大的绘制操作。
Unity中的批处理类型
在Unity中,主要有两种类型的批处理:
在Unity中,静态批处理(Static Batching)、动态批处理(Dynamic Batching)和GPU Instancing都是用于优化渲染性能的技术,特别是在减少Draw Calls方面。这三种技术虽然目的相似,但各自的工作原理和使用场景有所不同。以下是它们的主要区别:
在使用这些技术时,开发者需要根据具体的游戏场景和需求来选择最合适的方法,有时甚至需要结合使用多种技术来获得最佳的性能优化效果。
实现批处理的技巧和最佳实践
共享材质:确保尽可能多的对象使用相同的材质。这是批处理能否成功的关键因素。
使用图集:将多个小纹理打包到一个大的纹理图集中,这样不同的对象即使使用不同的纹理,也仍然可以合批。
减少材质属性的变化:例如,避免频繁更改材质的颜色或其他属性。
优化网格:对于动态批处理,保持网格简单(低顶点数)是重要的。
标记静态对象:在Unity编辑器中,确保场景中不会移动的对象被标记为“静态”。
合理使用LOD和遮挡剔除:这些技术可以减少渲染的对象数量,间接减少Draw Calls。
性能监控:使用Unity的Profiler工具监控Draw Calls和其他性能指标,以评估批处理的效果。
面临的问题
合并多个网格为一个大网格是一种在3D图形和游戏开发中常用的优化技术。网格(Mesh)是由顶点、边和面组成的3D对象的结构,在3D渲染中非常基础。合并网格意味着将多个单独的3D模型(每个都有自己的网格)结合成一个单一的、更大的网格。这个过程的具体含义和优点如下:
含义
优点
缺点
应用场景
在3D图形和游戏开发中,“使用贴图集(Texture Atlas)”是一种常用的优化技术。贴图集是将多个不同的纹理图像合并到一个单一的、更大的纹理图中的做法。以下是关于贴图集的详细解释:
贴图集的基本概念
如何减少Draw Calls
根据物体与摄像机的距离,动态调整物体的细节级别,从而减少渲染负担。
LOD(Level of Detail)技术是一种在3D图形渲染中常用的优化手段,旨在提高渲染效率,同时尽量保持视觉质量。LOD的基本原理是根据对象与观察点的距离,动态地调整对象的复杂度。这里是LOD技术的一些关键点:
Lightmap(光照贴图)是一种在3D图形和游戏开发中常用的技术,用于提高场景的光照效果的同时优化性能。在这种技术中,光照信息被预先计算并存储在一张或多张纹理中,这些纹理随后被应用到场景中的对象上。以下是关于Lightmap的更详细的解释:
使用 GPU Instancing:使用 GPU 实例化技术可以将多个相同的物体实例化,减少 Draw Call。可以通过创建 MaterialPropertyBlock 对象并调用 MaterialPropertyBlock.SetVectorArray 方法来实现 GPU Instancing。
资源异步加载
优化脚本
避免在Update函数中进行大量的计算或者频繁的内存分配,尽量减少使用Find系列函数,避免频繁的GC。
在Unity中,Find系列函数(如FindObjectOfType,Find,FindChild等)是非常消耗性能的操作,因为它们需要遍历整个场景或者对象的所有子对象。如果在Update或者频繁调用的函数中使用Find系列函数,会大大降低游戏的性能。
更好的做法是在Start或Awake函数中使用Find系列函数,将找到的对象保存在一个变量中,然后在需要的地方直接使用这个变量。这样就只需要在游戏开始时执行一次Find操作,而不是每帧都执行。
另外,如果可能的话,尽量使用public变量或者单例模式来引用需要的对象,这样可以完全避免使用Find系列函数。
使用Profiler工具:Profiler可以帮助你找到性能瓶颈,从而进行针对性的优化。
优化物理:减少物理模拟的复杂度,比如使用简化的碰撞体,减少不必要的物理计算
遮挡剔除
Occlusion Culling:隐藏摄像机看不见的物体,减少渲染负担。
使用Shader优化:使用更简单的Shader,或者针对特定平台优化Shader。
优化UI:避免频繁更新UI,尽量使用Canvas Group和Layout Group。
在3D图形和游戏开发中,材质(Material)和纹理(Texture)是两个基本且关键的概念,它们在创建视觉效果时扮演着不同的角色。理解它们之间的区别对于正确地使用它们来创建丰富、逼真的3D场景是非常重要的。
定义:材质是一个用来定义对象表面外观的属性集合。它不仅包括颜色和纹理,还包括光照如何与对象表面交互的信息,例如光泽度、透明度、反射性等。
作用:材质决定了物体看起来是金属的、木制的、塑料的还是布料的等等。它是物体表面视觉特征的综合表现。
属性:材质包含多种属性,如漫反射颜色、镜面高光、法线贴图、反射率、透明度等。这些属性可以通过调整材质中的参数来改变。
渲染管线:在渲染管线中,材质决定了对象如何响应光照和环境,影响着对象的最终视觉效果。
使用方式:在游戏引擎如Unity中,材质通常通过材质编辑器创建和修改,可以应用到一个或多个3D模型上。
定义:纹理是一种图像,用于给3D模型的表面添加细节。它是一个2D图像文件,可以通过UV映射将其贴在3D模型的表面。
作用:纹理直接决定了物体表面的具体外观,如颜色、图案等。纹理可以非常详细地描绘表面特征,比如砖墙的纹理、木纹或皮肤纹理等。
类型:纹理有多种类型,包括漫反射贴图(决定物体颜色)、法线贴图(模拟表面凹凸)、镜面高光贴图(定义高光区域)等。
UV映射:为了将2D纹理应用到3D模型上,需要进行UV映射,这是一个将3D表面坐标转换为2D纹理坐标的过程。
使用方式:纹理被创建为图像文件,然后在材质中被引用。通过将纹理应用到材质上,可以赋予材质具体的视觉外观。
纹理(Texture)通常被视为材质(Material)的一部分,在3D图形和游戏开发中,它们共同工作以定义对象的表面外观。
合并网格:将多个网格合并成一个网格,可以减少 Draw Call。可以使用 Unity 中的 Mesh.CombineMeshes 方法来实现网格的合并。
合并材质:将多个使用相同材质的物体合并成一个物体,可以减少 Draw Call。可以使用 Unity 中的 MaterialPropertyBlock 来实现材质的共享。
使用静态批处理:将多个静态物体合并为一个批次进行渲染,可以减少 Draw Call。可以在 Unity 中开启静态批处理来实现。
使用动态批处理:将多个动态物体合并为一个批次进行渲染,可以减少 Draw Call。可以在 Unity 中开启动态批处理来实现。
使用 GPU Instancing:使用 GPU 实例化技术可以将多个相同的物体实例化,减少 Draw Call。可以通过创建 MaterialPropertyBlock 对象并调用 MaterialPropertyBlock.SetVectorArray 方法来实现 GPU Instancing。
使用 Atlas 贴图:将多个小贴图合并成一个大贴图,可以减少 Draw Call。可以使用 Unity 中的 SpritePacker 工具来实现贴图的合并。
减少动态物体的数量:动态物体需要每帧重新绘制,因此数量过多会导致 Draw Call 增加。可以通过使用静态物体、使用 LOD 等方式来减少动态物体的数量。
减少透明物体的数量:透明物体需要额外的渲染步骤,因此数量过多会导致 Draw Call 增加。可以通过使用不透明物体、使用 Alpha Test 等方式来减少透明物体的数量。
使用 Occlusion Culling:根据摄像机视锥体内的可见 UI 元素,减少需要渲染的 UI 元素数量,从而提高渲染性能。
当UI实例化时,需要将Prefeb实例化到场景中,期间会有网格的合并、组件初始化、渲染初始化、图片加载、界面逻辑初始化等,会消耗大量的CPU,可能导致我们在打开某个界面时频繁出现卡顿现象。上面我们介绍了拆分UI法,此方法适合大冗余、益拆分的界面,对于容量小、难拆分的UI即使再拆分后可能仍会消耗大量CPU,这种情况可以使用UI预加载的方法,在游戏开始前/进入某个场景之前预先加载部分UI,使得实例化和初始化平摊到等待的时间线上。
最简单直接的方法就是在游戏开始前加载UI资源但不实例化,这样做只是提前把资源加载到内存中,在显示UI时CPU只需要实例化和初始化。