Unreal Engine Real-Time Rendering Class(三)

本文是Unreal Engine官方课程的学习笔记

Geometry Rendering [Part 1]

  • Frame 2 - Time 66ms - GPU:
      Prepass/Early Z Pass
      GPU获取到了需要渲染的对象列表,如果什么都不做直接进行渲染的话会造成大量的像素被重复绘制。考虑如下的场景:
    Unreal Engine Real-Time Rendering Class(三)_第1张图片
    先渲染橘红色的背景,接着渲染茶壶,被茶壶遮挡的属于橘红色背景渲染部分的像素都白白计算了,因为它们最终会被属于茶壶渲染的像素所覆盖。有的人会说,那如果先渲染茶壶呢?这也行不通,考虑如下的场景:
    Unreal Engine Real-Time Rendering Class(三)_第2张图片
    蓝色的栅栏既属于前景又属于后景,那么到底应该放到茶壶之前渲染还是茶壶之后渲染呢?
      出于以上的原因,会先以极其简单的方式渲染一遍所有的几何体,得到每个像素的深度信息。在之后的正常渲染流程中,如果当前几何体渲染的像素被认定为之后会被其他几何体渲染的像素所覆盖,就无需再次计算,直接可以丢弃
  • 几何体渲染
      Drawcalls
      几何体会根据绘制调用逐个渲染,一个绘制调用称为一个drawcall
      看下面的场景:
    Unreal Engine Real-Time Rendering Class(三)_第3张图片
    它实际上是这样渲染的:
    引擎计算后会首先渲染地面,被圆柱遮挡的像素不会进行渲染,因为引擎知道这些像素之后会被圆柱遮挡。可以看到最右边的圆柱被分为两步进行渲染,因为有两个不同的材质。
      渲染顺序:引擎会将不透明的网格模型根据它们使用的材质进行排序,这样就可以防止昂贵的改变硬件的渲染状态的操作。还是以上面的场景为例,引擎会连续的渲染最右边圆柱的下半部分(上图左2)、中间的圆柱(上图左3)以及左边的圆柱(上图左4),因为它们都属于同一个材质。
      在许多情况下,drawcall对性能的影响要比三角面大得多。拿拷贝文件做例子,拷贝1个1GB的文件大概只需要几分钟,而拷贝100万个1KB的文件却需要几个小时,尽管拷贝的总量仍旧是1GB。渲染也是一样的,每次渲染完成,渲染器都需要等待下一个渲染信息传递过来才能继续渲染,渲染之间的停顿正是影响性能的原因。来看个例子:下面有2个平面,橘红色平面由32768个三角面组成,只包含1个材质;彩色平面由32个三角面组成,却包含非常多的材质:
    Unreal Engine Real-Time Rendering Class(三)_第4张图片
    32768个三角面,1个材质
    Unreal Engine Real-Time Rendering Class(三)_第5张图片
    32个三角面,许许多多的材质
    将它们放入引擎中渲染,得到的结果如下:
    Unreal Engine Real-Time Rendering Class(三)_第6张图片
    8600万三角面,3000个drawcalls,33帧
    Unreal Engine Real-Time Rendering Class(三)_第7张图片
    10万个三角面,44000个drawcalls,4帧

Geometry Rendering [Part 2]

  • Drawcalls有一个最基本的损耗,因此把低三角面优化到超低三角面对性能可能不会产生任何影响
  • 降低Drawcalls可以使用更大的网格模型来替代许多小的网格模型,但也要注意会产生的副作用:
      1. 遮挡剔除变得更差,尽管要计算的对象少了,但大的对象很难被遮挡,因此需要绘制的三角面会有增加
      2. 光照贴图变得更糟糕,光照贴图的空间有限,以4k为例,4096对光照贴图来说已经是超大的分辨率,超大网格模型很容易就把光照贴图的空间用光了
      3. 碰撞检测变得更差,举个例子,如果有个球击中了柱子,引擎仅仅需要获取柱子的碰撞数据。如果柱子和整个房子合并成了大的网格模型,那么当球击中柱子的时候,引擎就需要获取整个房子的碰撞数据
      4. 内存的负担更重
  • 推荐的方案是既保留一些网格模型,同时也合并一些网格模型,合并网格模型应遵循以下原则:
      1. 使用次数多并且面数低的网格模型,这样可以降低很多draw calls,并且合并之后总的面数也不会很多
      2. 在同一区域的网格模型
      3. 共享同一个材质的网格模型
      4. 没有碰撞或者碰撞信息很简单的网格模型
      5. 小型的网格模型(无需担心光照贴图)或者只接受动态光照的网格模型,这样就不需要担心光照的问题
      6. 远距离的网格模型
  • 实例化渲染:实例化渲染会将相同的网格模型组织在一起,用一个draw call渲染完成。默认情况下,UE4中的网格模型会实例化并保存在内存中,但不会在渲染时实例化。在内存中实例化意味着即使你的场景中有10根柱子,内存中仍然只有一份柱子网格模型,但需要10个draw calls。
  • HLOD:常规的LOD通常会用低面数的模型来替换高面数的模型,但不会降低draw calls。HLOD会将对象编组,在启用时使用一整个网格模型来替换组内的对象,既减少面数,同时也降低draw calls

Geometry Rendering [Part 3]

  • 着色器系统用于处理大量的简单运算,这些运算通常是并行的
  • UE4支持世界坐标偏移的功能:
    Unreal Engine Real-Time Rendering Class(三)_第8张图片

    这是在顶点着色器中发生的,CPU并不知道这一切。我们可以用这个功能来做布料、水面的起伏、植被随风摆动的动画。使用这种方式的优势在于不再需要CPU来计算动画。如果你有一片森林,可能有几万棵草,是无法用CPU来计算那么大量的动画的

  • 由于CPU并不知道世界坐标偏移的功能,因此诸如物理或者碰撞检测之类的效果不会受到影响:
    Unreal Engine Real-Time Rendering Class(三)_第9张图片
    模型被偏移到上方,但是它的碰撞盒仍然在下方

    即使GPU在世界坐标偏移后回过头去告诉CPU,也无法起作用,因为CPU在流水线中是先行的。所以记住世界坐标偏移的功能只能用于视觉效果

  • 性能优化点:在远距离时禁用世界坐标偏移

本文固定链接: https://www.jianshu.com/p/ea8528eb36ad
转载请注明: EnigmaJJ 2018年12月29日 于 发表

你可能感兴趣的:(Unreal Engine Real-Time Rendering Class(三))