首发于kiiye9697.cn 感兴趣支持一下喵

Warm Up:概念引入

图形学角度观察渲染

  • 不注重硬件层级的实现,主要专注于表现以及数学方法上的正确性/无偏性
  • 对于实时渲染的理解能够达到30FPS即可,对于交互要求达到10FPS即可
  • 可以通过离线渲染的Out-Of-Core Rendering来暴力实现一些真实感的渲染效果

游戏渲染上的挑战

  • Everything in one container:需要将大量的渲染算法都在引擎内通过一套管线容器实现,需要有灵活和编辑的机制
  • 游戏平台的性能有限性:需要在现代硬件系统中实现渲染流程,需要适应平台的硬件架构以获得优秀的性能表现(PC/PS5/Mobile等)
  • 帧率和分辨率的挑战:需要保证稳定的帧率以及实时级别的高分辨率渲染,保证无论画质精度如何,帧率都要保证稳定,且需要满足现在显示屏的分辨度不断提升挑战
  • CPU的利用率问题:在真正的引擎系统中,不能将全部的CPU全部吃掉——通过Profile来监控CPU端的性能占用;我们需要将network ai gameplay部分的cpu占用让出来,不能类似conventional cg一样将全部性能都压在上面

游戏引擎的渲染算法

引擎内的工程算法并非百分之百正确,且迭代速度和优化速度很快,更多不拘泥于理论上的逻辑而是更多考虑落地的逻辑,可行性大部分时间大于算法的绝对正确性。 (NPR Rendering、2D Rendering、皮肤与毛发渲染等没有在这里详细提及)

Part I:Basics of Game Rendering

Building Blocks Of Rendering

渲染管线和数据

详情见Games101相关的知识,此处以管线图作为简单记录

Computation

  • 传入顶点片元数据
  • 正交/透视投影+矩阵运算->光栅化离散为像素点
  • 着色计算(Shading):材质纹理映射、着色模型计算(对材质的纹理映射需要进行mipmap查询,线性插值以进行防走样)

GPU

SIMD与SIMT

  • SIMD(单指令多数据):通过一次计算指令同时完成四个数值的计算逻辑
  • SIMT(单指令多线程):在不同的核上将单个指令发送后,在多个核中完成完全相同的计算,在GPU上,我们应该尽可能多的设计算法以使用SIMT以加速渲染到逻辑

GPU Architecture (费米架构)

  • 基础概念:GPC(Graphics Processing Cluster)、SM(Streaming Multiprocessor)
  • 图形处理集群,内有大量Core(Nvidia内有CUDA核或者RT core以及Tenser处理)用于数学计算,有专门硬件处理复杂工作,类似数学运算(三角函数)、纹理采样、着色等问题。在进行并行化编程时,这个架构主要负责执行复杂度部分
  • SM:用于运行CUDA指令的逻辑部分,在GPU端处理CUDA核的逻辑运行部分

CPU和GPU之间的通信部分

  • 由于冯诺依曼架构的数据和运算分离的逻辑,我们在CPU GPU数据交换的时候存在数据共享的问题(数据的传输和共享速度很慢),我们的数据Back-Forth中,一般地绘制和同步逻辑是不同步的。在渲染机制设计原则当中,我们一般令数据是单向流动的,尽可能将数据由CPU端传入GPU,而不再从GPU中向回读取数据。

Cache Efficiency

Cache(缓存)是决定计算效率的关键步骤,在进行计算时,数据应该相对集中的存放以更好的适应Cache的利用(局部性原理)

如果进行一次计算时,所用数据均读入Cache内,被命名为Cache Hit(缓存命中),反之为Cache Miss,无法进行对应计算

GPU Bounds

常见的表现局限性存在于Memory Bounds、TMU(Texture Mapping Bounds)、BW(带宽,bandwidth)等;

HardWare Pipeline

RHI(Render Hardware Interface)渲染硬件层的调用语言,主要有Vulkan、OpenGL和DirectX12等主流语言

Renderable(可绘制/可渲染物体)

Mesh

属于可渲染组件,可以在一个Mesh上打包出不同的组件,赋予不同的材质,并赋予不同的贴图效果;简单的逻辑是记录顶点的位置、颜色以及对应法线,而类似OpenGL提供的规范着色器逻辑主要是将数据信息设计为Vertex以及Index类数据进行交互;

  • 逐顶点法向的重要性:为对硬表面处能够表现出法线的逻辑,必须单独定义每一个顶点的法线方向以保证硬表面的发现方向正确(插值只会出现平滑的表面)

Materials

定义物体对于受光后应该有的着色表现(不是物理效果的材质,而是用于表现光线的材质类型);常见的效果类型有Phong Shading、PBR Shading或者SubSurface(微表面)模型,在此不过多赘述。

Texture In Materials

材质中有一些材质的贴图用于记材质的信息,用于记录金属度、基础色、法线信息、AO等信息。

Variety of shader

着色器。同时属于源码,本身也是用于绘制的数据部分,需要传递数据和绘制逻辑用于实现,用于决定绘画风格和表现效果。

Coordinte System and Transformation

一套坐标逻辑,利用齐次坐标进行空间的变换,由MVP变换等变换基础将物体从Object Space转换到屏幕空间

Object With Many Materials

很多物体需要对不同的部件引入不同的着色模型,以保证渲染效果的正确。这里主要使用的逻辑是SubMesh,但是所有的顶点和片元数据是同一个Buffer传入,SubMesh用于选定那一部分网格使用什么Shader进行着色,在UE中的实现就类似这一逻辑。

Instance(实例化逻辑)

对于大量使用相同Shading逻辑和贴图、材质等的物体来说,每一个物体进行一次单独的DC显然是影响性能和功耗的处理方式;在节约空间中,我们一般利用Resource Pool优化数据的传输: Resource Pool 这样,我们传入了所有需要的资源和逻辑,在这一批传输中,我们在实例化物体的时候,只需将对应的索引传入,并行的调用纹理池中的内容就可以极大的优化绘制和调用的逻辑了。(一个简单的资源池逻辑) 实例化的时候的调用逻辑

Sort By Material

由于在GPU上,对数据的切换比较缓慢,因此我们将场景中的物体按照材质类型进行分类发送,这样的话合批处理后,这样会大大提升GPU的运算效率逻辑,这样将所有的SubMesh一起处理。在Unity中称之为GPU Instancing。

GPU Batch Rendering(批处理)

我们尽可能将绘制运算交付给gpu进行运算,因此我们绘制大量的相同物品对象时,我们将所有的相同Mesh打包后一起发送,由于渲染的Material逻辑是一致的,因此会提升渲染效率。

Visibility Culling

在实际的渲染中,我们不需要对全部世界中的WordObject进行绘制,在一般的游戏中,我们采用透视投影矩阵,故此我们只需要绘制在当前帧视锥体内的行为与对象

Object Culling

在渲染物体时,我们将物体的模型放置在一个包围盒(Bound)中,通过计算视锥体和包围盒的包含关系,来判断是否应该将当前物体加入渲染队列。 包围盒有很多种方法,基本上来说,越精细的包围盒,其剔除效果越好,不过对应会有更高的cost,因此选择合适的才是最好的 不同类型的包围盒概览

Hierarchical View Culling

包围的计算,主要由BVH等计算向下进行查询,比遍历的复杂度相对较低,但是很适合会移动物体的空间划分逻辑->对于静止物体和运动物体,我们考虑的角度不同,对于Moving Object,我们要同时考虑构建包围盒系统以及查询系统两个部分的开销,需要一个同时考虑重新构建和查询两种均有能保证良好速度的结构。(這裏的BVH算法逻辑非常类似光线追踪中用于相交判定的经典加速结构,可以进行相应的对比逻辑记忆。)

PVS逻辑(Potential Visibility Set)

将空间分为小的包围盒,在每个区域内设计好Portal,将每一个房间内,通过每一个门设计最多可见的其他房间(区块划分),这样需要渲染的部分就是当前和其他利用传送门可视的部分。这是一种高效的算法逻辑。

  • 不适用于室外的开放世界
  • 不适用于含镜面的复杂逻辑
  • 比较局限于线性的箱庭间的逻辑
  • 这种Zoom分块逻辑可以同时考虑将资源加载和其同时考虑——>可以卸载不可视部分的全部逻辑,包括所有区块的所有逻辑加载而不止局限于视锥体剔除的逻辑。
GPU Culling

力大砖飞!将全部包围盒扔进GPU端进行剔除,通过高平行性快速判断是否需要剔除。

Early-Z(延迟渲染)

将渲染管线中的深度测试环节提前到顶点着色之前,即先绘制当前场景的深度图(可视区能见到的最小深度),然后进行Alpha Test(模板测试),这样可以减少大量被遮挡物体的绘制效率问题。

这种管线对于半透明/透明物体并不友好。涉及这些物体时,我们需要单独的逻辑来解决(否则后续物体可能在这套管线下被提前剔除没有留下合适的影迹)

Texture Compression(纹理压缩)

在引擎的绘制系统中,我们不能将传统的图像压缩算法应用于引擎端的纹理资源优化,类似JPG\PNG类的图形压缩逻辑后我们查询随机坐标点颜色信息的复杂度显著提升,这不利于我们进行映射等逻辑,也难以制作lod等系统。

常见的压缩格式

  • BC7:pc端口常用,将4x4像素块内的颜色查询到对应的最大值、最小值,将其中其他的颜色利用其将其他颜色进行插值,这样我们根据纹理的cpu实时压缩、解压缩,有着优秀的效率性能:
  • DXTC,不严格的设计成方形的压缩算法,可以将其分区域解压缩获取颜色信息,效率高但是不能再运行时进行解压缩逻辑。 常见的颜色压缩逻辑

DCC For Modeling

  • conventional:在构建物体时,我们常见的建模工具有3dmax、maya和blender等。而详细的雕刻模型时多用Zbrush进行处理
  • Scanning Method:基于实体扫描处理的模型由于AI 3d重新建模的优化,因此扫描建模的精度优势使得其获取一席之地
  • PCG功能:类似Houdini、Unreal等正在进行的PCG探索,能从程序化逻辑中实现我们的模型功能,将其细节进行补充,是未来的发展趋势之一。 Different Model Different data like

绘制系统的更新

在当下更精细模型的处理逻辑下,我们的GPU有很搞笑的创建几何细节的逻辑,现在我们的几何逻辑将通过曲面细分算法进行曲面的优化,而不是认为的雕刻。由于曲面细分的算法逻辑区域一致化,因此我们就可以利用GPU优化整体的渲染管线逻辑。 Cluster-Based逻辑 基于曲面细分的渲染管线逻辑

  • 可以产生无数细节且可以进行动态的lod
  • 可以优化曲面,通过分面片的细分程度来优化mesh的动态LOD,高效的完成高精度网格优化。

Nanite的优化

工业引擎上,Nanite可以进行工业级别的像素级别细分网格,详细内容放在后面进行详细介绍。

Short Break

  • 深入了解GPU硬件设计才能更加优化渲染性能
  • GPU Driven是当前的热点方向