混合渲染
混合渲染(Hybrid Rendering)从字面意思就是非单一方法的渲染机制。这也就使得这个词,没有一个完全标准且唯一准确的定义。首先大家需要明白,渲染的最终目的是呈现画面,不论是图片,视频,还是实时交互的场景。
那为了这个最终的呈现结果,如果渲染过程中采用了很多种方案来混合实现,就可以说它是混合渲染。
我们从不同的角度,总结了一些混合渲染的形式。仍然不讨论具体的技术实现细节,只是为了方便大家理解概念。
基于管线的混合渲染,指的是一条渲染管线中,会用到不同的计算承载方式,最终来完成渲染工作。目前的计算承载方式包括:光栅化(Rasterization,包含Vertex Shader和Fragment Shader),计算着色器(Compute Shader),光线追踪着色器(Ray Tracing Shaders)。
渲染管线中,最基本的计算承载方式就是光栅化。原则上,光栅化是为了输出渲染内容的一整个渲染流程,同时也可以利用流程中的Vertex Shader和Fragment Shader进行一些计算的处理,但是光栅化过程中是发生在Render Pass中,其中有很多Fix Function,比如剔除,深度测试,颜色混合等,所以用光栅化来进行计算,其实是“不专一”的,效率会相对低下。
光栅化对于一些光线不是很复杂的场景仍然是可以胜任的。但是如果光线一旦复杂,它就没有办法很好地胜任复杂的光线算法了,因此渲染效果也就不尽人意。
目前WebGL只具备光栅化需要的Vertex Shader和Fragment Shader(Extension版本除外),计算能力有限且不够灵活,渲染效果也不会特别优秀。
WebGL为了实现比较好的渲染效果,都是通过预烘焙的方法,将效果附加到贴图本身,以静态的方式进行展示,从而失去了对复杂光线变换的实时应对能力。
为了解决光栅化的计算效率低下问题,现代图形API都提供了计算着色器,即Compute Shader。
WebGPU也应用了现代图形API的设计原则,同样支持Compute Shader。Compute Shader本质是一种通用计算的能力(GPGPU),完全运用在Compute Pass中的,是“专一”的计算单元,很类似于CUDA(不过CUDA可以通过英伟达的显卡做到硬件芯片级别的加速,因此计算性能更高)。
有了这种通用计算能力,就不再是光栅化中的“模拟”计算了,而是专业级的计算能力。比如我们用光栅化中的Fragment Shader模拟一些算法,只能限制在二维的平面坐标系中,而Computer Shader没有这种限制,也更加的灵活,速度更快。
光线追踪Ray Tracing是一项几十年前就有的技术,但是因为计算量太大,而无法实现实时渲染。因为RTX显卡的出现,让实时光线追踪这个概念再次得到了关注。
光线追踪是路径追踪的一种简单形式,但是这两个概念本质上都是一种数学算法。光线追踪着色器(Ray Tracing Shaders)就是特意为光线追踪这种数学算法而设计的,它由很多特殊着色器模块的组合而成。下图是RTX光线追踪的架构图:
既然光线追踪只是一种数学算法,那么任何语言和编程环境都可以对这个数学算法进行实现。
如果只看图形领域,我们可以用CUDA, Fragment Shader(OpenGL, WebGL),Computer Shader(WebGPU,Vulkan,Metal,DX11/DX12,OpenGL Extension),RXT(DX12/DXR, Vulkan)来实现光线追踪算法。
既然光线追踪算法用上面的方式都可以实现,为什么RXT会再次引爆这个概念呢?原因就是它可以实时地实现光线追踪算法。
RTX显卡针对光线追踪这一个非常重要且特殊的渲染算法,单独做了硬件级别的加速。通过硬件芯片可以直接运行上面提到的光线追踪过程中的各种着色器模块(可以理解成把CUDA的通用计算芯片重新设计,优化成更适合运行光线追踪算法的芯片),这样就可以在3D场景中实时的完成光线追踪的运算结果,渲染更加优质的3D画面。
目前苹果的M1芯片还暂时不支持对光线追踪算法的硬件加速,所以Metal还是通过类似于Compute Shader(Metal Performance Shaders)的方法来优化光线追踪算法。WebGPU也会在未来的版本中,加入对于RTX的支持,我们一起期待!
三种计算承载方式:光栅化,计算着色器和光线追踪着色器都已经介绍完了。它们之间并不是谁要代替谁,也没有一种完美的方法。
而对于不同的场景,运用不同的方法。所以,对于混合渲染的概念,相信大家也更加清晰了。只要混合使用了不同渲染方法的渲染管线,我都可以理解成是混合渲染的一种体现。
基于数据的混合渲染,指的就是对一个3D场景中的不同3D资源(模型,场景等)进行分类,相当于对3D资产数据进行拆分,把不同类别的3D数据放到不同的渲染节点进行渲染,最后通过网络通信技术,把数据合并到一个需要显示输出的节点上,进行最终的呈现。
一般提到这种基于数据的混合渲染,都会和上一期我们聊到的云渲染有些关联。因为这种数据拆分的形式可以让我们天然地想到,把一些复杂度高,计算要求大的任务放到并行计算能力更强的云端,利用渲染集群进行计算。
而我们的个人终端,只渲染计算量相对较小的任务。云端渲染的结果,最终不论是以视频或图片的形式传给客户端,还是只把复杂计算的结果返回给客户端,再由客户端进行最终的呈现,都会大大降低客户端的开销。
在5G通信技术的快速发展下,更加多样灵活的渲染架构,例如边,端,云协同渲染也得到了更多的尝试和验证。
这种渲染方式,可以充分利用终端及终端附近的边缘节点的计算能力,避免了全云端渲染可能会遇到的“卡顿”问题。
而且,也是一种“进可攻退可守”的架构设计,通过渲染任务的解耦设计,可以在全终端渲染和全云端渲染之间灵活切换和调配,进而适应更复杂的渲染需求。
基于管线的混合渲染
同济大学贾金元老师提出的协同混合渲染的网络架构
基于硬件的混合渲染
基于硬件的混合渲染,指的就是CPU和GPU可以同时参与渲染任务的一种混合渲染模式。这里我们参考V-ray的混合渲染模式。首先要说明的是,单纯的GPU渲染有两个问题:
1)很难进行Debug:GPU的程序如果出错基本都会返回一个kernel dump(就是内核挂掉了),不会有相应的报错信息提示。
2)无法充分利用CPU的性能:之前的渲染工作基本都是交给GPU来进行计算的,CPU把任务提交给GPU之后,CPU本身其实会处于一段时间的空闲状态,等于白白浪费了计算能力。
为了解决这两个问题,V-ray提出的混合渲染就是可以让CUDA同时运行在CPU和GPU上,这样可以充分利用CPU提交任务给GPU之后,本身的空闲时间,同样可以进行渲染的计算工作。
经过测试,V-ray的混合渲染比单纯的GPU渲染,完成时间平均缩短了约20%左右。这里需要强调下,这种CPU和GPU同时进行的混合渲染模式,在WebGL的标准下是无法实现的,因为它采用的是全局状态机模式,CPU必须要等待GPU的运行结果,才能继续做下一个任务,简单说就是同步机制。
而WebGPU采用了现代图形API的方法,完全遵循异步形式,这样才具备实现这种混合渲染的基础能力。
基于框架的混合渲染
基于框架的混合渲染,指的是渲染过程可以从之前的框架转移到另外一个全新的框架上实现。
2019年,Unity提出Data-Oriented Technology Stack(DOTS)技术,并通过Hybrid Renderer来实现。DOTS的核心就是ECS(Entities, Components, Systems)的架构设计,也标志着ECS框架在游戏引擎中的应用(关于ECS的细节和优劣势我们这里就不做讨论了)。
Unity的Hybrid Renderer带来的混合渲染,其实指的是可以让渲染过程从之前的OOP模式(Object-oriented Programming)转换到DOP模式(Data-oriented Programming),是把GameObjects转换成ECS中的 Entities。
最终的目的就是利用ECS的数据连续内存存储特征,提高缓存命中率,同时引入多核并行计算的优势,加快渲染过程。
讲到这里,我们把一些常见的混合渲染的形式都已经介绍完了。总结下就是,混合渲染没有一个固定的定义,只要把“渲染”混合使用,都可以叫混合渲染。
目前,我们已经介绍了离线渲染、实时渲染、云渲染、混合渲染。要强调的是,它们之间所用到的技术和场景,有很多都是相互交叠在一起的,并没有一个标准唯一的准则。
我们希望的是,大家如果在再次遇到这些概念,或者一些3D渲染引擎产品的时候,可以按照这些渲染分类,去快速的进行定位和分析,更好的帮助我们理解和学习,解决我们遇到的问题,这样就已经足够好啦!
来源:Orillusion