-
渲染流程
-
首先接收用户提供的几何数据,并且将他们输入到一系列着色器阶段中进行处理,最后将数据转换到最终渲染的图像。顶点数据->顶点着色器->细分控制着色器->细分计算着色器->几何着色器->图元设置->剪切剔除->光栅化->片元着色器->最终渲染的图像。
-
不一定会用到所有的着色阶段,只有顶点着色器和片元着色器是必需的。一个复杂的引用程序可能包含许多个顶点着色器,但在同一时刻只能有一个顶点着色器起作用。
-
每一帧画面的渲染过程,大致如下
i. CPU检查场景中的每个对象来确定他是否需要渲染,并且将每个需要渲染的对象加入到DrawCall指令中,部分具有相同属性的对象可能会Batch到同一个DrawCall中。
ii. CPU会向GPU发送SetPassCall指令,在当前RenderState与下次不同时,SetPassCall会告知GPU在下次渲染Mesh时要使用哪种配置。
iii. GPU根据CPU的指令执行任务,执行顺序与指令发送顺序相同。
iv. DrawCall->GPU渲染Mesh,SetPassCall->GPU更新RenderState
-
-
GPU优化
- 填充率
i. 降低游戏分辨率
ii. 使用光照贴图并减少逐像素灯光的数量
iii. 减少FragmentShader中复杂或非必要的计算,不追求高精度的部分计算移至VertexShader中完成
iv. 减少粒子及透明物体的叠加或混合(降低OverDraw)
v. 减少后期效果的数量或优化其算法降低计算量。 - 显存带宽
i. 纹理的数量
ii. 纹理的尺寸
iii. 根据平台芯片选择对应的纹理压缩格式和修改项目设置中的TextureQuality。
iv. 会发生远近变化或缩放的物体需要使用Mipmap来减少带宽占用并提升表现效果,减轻摩尔纹或改善近距离分辨率不足的情况,其他情况下则可以关闭Mipmap来节省内存。
v. 关闭纹理的ReadWriteEnable,减少内存和带宽占用。 - 顶点数
i. 降低模型复杂度,可使用法线纹理提高表现效果。
ii. 调整模型导入属性,选择相应的压缩等级。
iii. 在项目设置中调整顶点数据的压缩内容。
iv. 使用LOD调整显示细节。
v. 使用OcclusionCulling,进行遮挡剔除。 - DrawCall
i. 静态批处理,会增加网格的资源量,占用内存及磁盘空间。
ii. 动态批处理,在游戏运行时进行Batching操作,需要注意的是,动态批处理的网格顶点属性要少于900个,所以在shader中使用到的顶点属性要尽可能的少,并且要避免使用多通道shader。
iii. 美术方面的预处理,根据设定的可视范围,调整合并材质及网格,能够使用Tiling的纹理尽可能采用Tilling的方式。
iv. 使用LOD调整显示细节。
v. 使用遮挡剔除,但部分情况下可能会造成额外开销。 - 减少反射,阴影,深度图的影响范围及调整相机的裁剪范围,会明显降低渲染开销。
- 填充率
-
CPU优化
- 移除脚本中的无效代码和空方法。
- 频繁使用的变量可以声明为全局变量。
- 减少游戏运行时获取组件的操作,应尽可能在全局变量中缓存。
- 能够在资源制作过程中序列化的,优先考虑通过序列化的方法获得组件。
- 客户端的可见组件,可以通过检测OnBecameVisible/OnBecameInvisible来确认是否在可见范围内,并且据此调整逻辑更新频率或内容。
- 频繁显示关闭的组件对象,可以通过移出屏幕的方式降低开销。
- 减少Object的实例化和销毁操作,尽可能使用对象池重复利用。
- 需要在Update中频繁查找的同一组件,尽可能的在初始化阶段缓存起来。
- 字符串拼接,最好使用StringBuilder。
- 减少高频的复杂计算,如实时性需求不高,可做分帧处理。
-
物理碰撞
- 调整Fixed Timestep,控制物理计算频率。
- 减少MeshCollider,优先使用BoxCollider,SphereCollider。
- 网络同步操作若需要使用物理组件,应打开IsKinematic,并采用相应的运动公式控制移动,检测方式为OnTrigger。
-
GC
- Mono运行时的托管堆,主要是类实例,字符串和数组。
- 触发方式
i. 堆内存不足时,自动调用GC
ii. 手动调用GC - 内存分配
i. 首先检查空闲内存是否足够。
ii. 如果不够,进行一次GC,回收内存。
iii. 如果仍然不够,会向操作系统申请内存,扩充现有堆内存。
iv. 已分配的内存不会交还给操作系统,只会回收到Mono的堆内存。 - 内存回收过程
i. 停止需要分配内存的线程。
ii. 遍历内存,找到无引用的内存,并标记。
iii. 回收被标记的内存到空闲内存。
iv. 继续启动被停止的线程。 - 内存泄漏
i. 引用丢失,导致无法通过任何途径访问到,但该对象仍有引用关系,无法被标记成垃圾。
ii. 大部分情况都是由于静态对象引用导致的,静态对象中不再使用的对象应将其设置为null,使其可以被GC标记并回收。 - 注意点
i. 字符串连接的处理,是在堆上分配的空间,结束后原字符串会成为垃圾,新字符串为新分配的空间。
ii. 尽可能不要使用foreach,优先使用for
iii. 使用对象池,重复使用对象,减少实例化销毁的操作。
iv. 尽量不要使用LINQ。
v. 优先使用局部变量。
vi. 需要频繁new的,优先使用结构体代替类。
相关文章
- 02-22游戏开发中的物理之使用KinematicBody2D
- 02-22cocos2dx游戏开发——捕鱼达人mini版学习笔记(一)——FishAchor的搭建
- 02-22OpenGL学习笔记一之实战篇五 2D游戏(Breakout)之渲染精灵
- 02-22Unity3D开发游戏世界天空盒
- 02-22HoloLens2开发笔记-使用UWP原生MediaCapture解决图像捕获与WebRTC视频流冲突问题
- 02-22Unity3D游戏开发笔记-2
- 02-22vue全家桶+Koa2开发笔记(7)--登陆注册功能
- 02-22window平台下使用cocos2dx引擎和vs2017,进行【别踩白块】游戏实战开发
- 02-22cocos2dx游戏开发——微信打飞机学习笔记(十一)——GameOverScene的搭建
- 02-22wemos D1 arduino物联网开发板应用笔记2-串口通讯