• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

百人以上的同屏战斗,GPU实现大规模动画角色渲染

武飞扬头像
大狗远的博客
帮助1

当遇到百人千人以至于万人同屏战斗时,渲染带给我们设备的压力是很大的,这也就是性能较差,机型过老的手机无法运行某些游戏的原因之一

对于这个问题,本文给出了一些解决方案,(为了让不懂技术的观众也能看懂本文,对此文中出现过的名词也做了相应解释)

首先关闭阴影,阴影开销是看不见的杀手,阴影会导致一个物体多次绘制,将需要绘制的物体重复提交给GPU,在阴影的作用下,Batches量大大提高,DrawCall量大大提高,什么是DrawCall?

在unity中,每次CPU准备数据并通知GPU的过程就称之为一个DrawCall。 具体过程就是:设置颜色-->绘图方式-->顶点坐标-->绘制-->结束,所以在绘制过程中,如果能在一次DrawCall完成所有绘制就会大大提高运行效率,进而达到优化的目的。

DrawCall为什么会影响游戏运行效率?

说道为什么会影响效率,就首先要了解一下他的工作原理:为了CPU和GPU可以进行并行工作,就需要一个命令缓冲区,就是由CPU向其中添加命令,然后又GPU从中读取命令,这样就实现了通过CPU准备数据,通知GPU进行渲染。

在每次调用DrawCall之前,CPU需要向GPU发送很多内容,主要是包括数据,渲染状态(就是设置对象需要的材质纹理等),命令等。CPU进行的操作具体就是:

准备渲染对象,然后将渲染对象从硬盘加载到内存,然后从内存加载到显存,进而方便GPU高速处理设置每个对象的渲染状态,也就是设置对象的材质、纹理、着色器等输出渲染图元,然后向GPU发送DrawCall命令,并将渲染图元传递给GPU

其次对Animation和Skinned Meshed Render 的开销进行优化

具体做法详见程序及思维导图,下面简略说明原理

这里我们来说一下Animation是什么,他做了哪些事情?

  1. 读取模型的顶点
  2. 读取动画文件,根据动画文件算出顶点在这一帧的位置

如何对Animation优化呢?

在计算机中有一经典优化方案,当CPU出现瓶颈时,就拿空间换时间,这个道理放在生活里也一样。

以帧动画为例,对于Animation计算每一帧位置的行为,我们需要预先将他计算出来。

  1. 生成动画,预先计算位置存放在一张贴图里
  2. 利用着色器Shader将贴图传递给GPU中的参数texture
  3. 顶点Shader决定模型形状时,利用着色器Shader从贴图中拿取坐标,转化成世界坐标,转化成透视投影

除了顶点动画,当动画复杂度有限的情况下,还可以利用UV来制作动画,根据不断更换UV范围达到序列帧动画效果的UV序列帧动画,将CPU的消耗转为GPU的消耗,使一部分计算更为高效,先定义帧动画的总帧数,图元排列的行数和列数,以及播放速度,在顶点着色时算好UV,计算过程是通过当前的时间和速度及总帧数,获得当前所在的帧数。

第二个方法是离线制作加速动画

方法一实质上是将CPU的消耗转移到GPU上,从而使动画性能得以优化。和方法一的相同点在于用空间换时间,例如一个时长为5秒的蒙皮网格动画,每秒30帧,总共需要150个画面,我们最多要准备150个模型依次在每帧中播放。但是用内存和硬盘的压力来换CPU的想法合不合理

举个例子,假设这个场景只有2-3个模型在播放该动画,为了这2-3个模型动画,就需要额外准备150个模型来播放该动画,本来只要一个模型 骨骼就可以办到的事,却要用150个模型来代替,加载150个模型也是需要时间得,更何况内存额外增到了150倍,这样看确实是不值得去做。那么再假设场景中同时播放该动画的模型数量非常多,如20个,这20个模型每帧都需要通过模型 骨骼的方式计算出一个模型的变化形状,而且用重复计算100次,这时如果是用150个模型来代替每帧持续的CPU消耗就值得了,具体步骤如下:

  1. 加载模型和动画
  2. 播放动画
  3. 定格在当前帧
  4. 将当前帧模型网格数据导出到文件
  5. 若不是最后一帧,则继续播放下一帧,跳到第三步,重复运行,否则结束进程

方法三利用GPU Instancing合批 动画组件MeshAnimator优化

动画组件MeshAnimator其原理是,将蒙皮动画烘焙成N份Mesh,播放动画就是替换MeshRenderer的Mesh。然后我们项目的情况是3种角色,4种动画,场景上会出现最大100 的角色,假设此时的DrawCall是100,我们控制一个角色播放一个动画时统一使用同一个Mesh播放序列,既保证了播放同一个动画的角色,其MeshRenderer里的Mesh都是一样的,这样DrawCall最大只有3*4 = 12个

这其实还是空间换时间的概念,而且MeshRenderer支持GPU Instancing,二者相结合

GPU Instancing其核心思想是,用一个 Draw Call 让 GPU 渲染一个物体有时候很浪费,不如在合适的时机,用一个 Draw Call 让 GPU 渲染一堆物体(100个,200个,甚至更多)

GPU Instancing 的工作原理是将具有相同 Mesh 和相同 Material 的多个 Object 的绘制放在同一个 Draw Call 中。GPU Instancing 在提高渲染建筑、树、草地等使用相同的材质和网格的对象的效率方面效果显著。虽然 GPU Instancing 只能把具有相同的 Mesh 和 Material 的对象放到同一个 Draw Call 中渲染,但是每个实例可以有不同的材质参数(例如 color,scale)。使用 GPU Instancing 可以显著提高渲染性能

具体来说使用 GPU Instancing,Unity 会将可见范围内的所有符合要求的 Object 的对象的属性(位置,uv等)放入到 GPU 中的缓冲区中,从中抽取一个对象作为实例送入渲染流程,这个对象包含了所有符合要求对象的公共信息(那些它们相同的部分),收到 Draw Call 之后,从显存中取出实例的部分共享信息与从GPU常量缓冲器中取出对应对象的相关信息一并传递到下一渲染阶段

对于渲染优化的内容分享到这里就结束了,算是笔者对于这部分的一个总结,其中内容部分参考自《Unity3D高级编程之进阶主程》

谢谢大家的观看

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /boutique/detail/tanhibekci
系列文章
更多 icon
同类精品
更多 icon
继续加载