究竟,是人类控制科技,还是科技控制人类?
在科技高度发展的近未来,人类原有的社会生活被改变,社会制度崩坏、贫富差距悬殊。掌握技术与资本的科技型寡头企业收割财富与武力,绚烂的霓虹灯光之下却是拥挤混乱的底层世界。与此同时,科技的发展也带来了严重的环境问题,酸雨、沙尘暴、光污染已成日常……
《赛博朋克 Demo》
接下来,一起走进 Cocos 打造的「赛博朋克」世界,了解其背后强大的技术支持与实现。
本次技术分享的重点主要分为以下几个部分:
延迟渲染管线
光线剔除技术(Cluster Light Culling)
反射球(Cluster Reflection Probe)
优化方案
延迟渲染管线
「赛博朋克」是一种类科幻电影的风格,画面以充满科技感的洋红和蓝色为主,整体对比度高,着重突出光源之间的色彩对比。若要在游戏引擎中实现这样的风格画面,就需要搭配一个强大且高效的渲染管线。
前向渲染
前向渲染是大多数引擎使用的标准,前向渲染管线在绘制物体的时候会立即进行光照计算,在场景中,每渲染一个物体,都会考虑所有光源对它的影响,然后再渲染下一个物体,以此类推。传统的前向渲染思路是,先进行着色,再进行深度测试。其主要缺点就是光照计算跟场景复杂度和光源个数有很大关系。假设场景里有 n 个物体,m 个光源,且每个物体受所有光源的影响,那么复杂度就是 O(m*n)。由于最终看到的画面都是 2D 的,只能看到有限的像素数,理论上只要处理最终可以看到的像素就够了,多余的处理是浪费的。而延迟渲染就是为了解决这样的问题而诞生。
延迟渲染
延迟渲染管线大幅度地改变了渲染物体的方式,它能够在渲染上百甚至上千光源的同时还能够保持能让人接受的帧率。在延迟渲染管线里,物体会先被绘制到 G-Buffer 中,这样可以获得渲染到某个像素的最终物体的所有信息,在下一个渲染 pass 里面就可以根据 G-Buffer 里面的信息进行光照计算,这个步骤里就只需要进行一次光照计算。因此,如果场景里有 n 个物体,m 个光源,复杂度仅为 O(n+m)。因此,可以简单总结一下延迟渲染的优缺点:
优点:只渲染可见像素,计算复杂度低;对后处理支持良好;对使用大量光源的场景优势很明显。
缺点:读写 G-buffer 的内存带宽用量大;对透明物体的渲染存在问题;对多重采样抗锯齿(MSAA)的支持不友好。
Cocos Creator 3.3 采用的是华为贡献的延迟渲染管线,华为在硬件和驱动层面的积累非常深入,有很多手游的分析和优化经验。通过本次合作,我们在多光源计算方面得到了很大的效率提升。Cocos Creator 默认采用的是前向渲染,可以通过项目设置->项目数据->渲染管线处启用延迟渲染管线。
光线剔除技术
Cluster Light Culling
电子霓虹灯是「赛博朋克」的重要标志之一。本次 Demo 中同样出现了大量流光溢彩的霓虹灯,庞大复杂的光源也对光照计算提出了更高的要求。
如果说延迟渲染解决的是 100 盏灯以内的场景渲染,那么 Cluster Light Culling 就是解决成百上千的渲染。因为即使用了延迟渲染,每一帧画面还是需要去遍历所有的光源,然后从 G-Buffer 上取数据再处理。这个操作虽然已经减少了大量的复杂光照计算的计算量,但仍然会占用相当大的系统总带宽,如果想要在移动设备上运行,那简直难上加难。因此,我们需要剔除影响不到像素的光源、并按照距离选取离像素最近的几个光源来渲染。这个思路就有点类似于 Tiled 渲染的思路。
本次 Demo 里使用的光源基本都是静态的光源,也就是不会移动的,利用这个特点只需要在场景初始化的时候将整个世界在 3D 空间里面划分成 16 x 16 x 16 的格子。接着计算每个光源到格子的距离,将能影响到格子并且最近的 4 个(可以更多,越多越消耗性能)光源的信息放到格子中。在光照计算阶段就可以根据 G-Buffer 中世界坐标信息计算出当前像素所在的格子,从中获取到对应的需要计算的光源信息。
反射球
Cluster Reflection Probe
恶劣的天气也是「赛博朋克」的一大特点,用来描绘被科技重度破坏后的自然景象。「阴黑的雨天」是常见的一个环境设定,通常在这种情况下,人们生活空间的光源必须依靠人工照明,同时室外环境也是“湿漉漉”的,以此来渲染压抑的氛围。而这样的景象可以利用反射球来实现。
反射球的主要原理是通过计算周围环境对物体的影响来增加渲染的真实感,比如街上的水滩会倒映出旁边的墙体、房间里的镜子会反射出房间里的家具等。在技术上,一个常用的实现方法是通过 IBL (Image Based Lighting ) 实现,相当于用一个无限大的球面光源在照射场景。预先计算着色反射,然后将整个世界烘焙到一张环境贴图中,渲染镜面的时候根据视角和物体表面法线计算出反射方向,从环境贴图中读取反射方向的光照信息,整合到光照计算中。
出于性能的考虑,手机端上一般都只用一张天空盒作为环境贴图,或者一整个世界烘焙出一张环境贴图。这样实现虽然高效,但是环境中显示的反射就可能会比较容易穿帮,比如镜子里反射出来的物体可能是穿过好几堵墙外的物体。本次 Demo 为了强化真实感,我们尽可能在场景中不同的区域放置反射球,每个反射球只烘焙这一个区域中的环境信息。当世界中的反射球较多时又会出现上面多光源中碰到的问题,因此应尽可能只计算影响到当前像素的反射球信息。利用已有的 Cluster Light Culling 逻辑,很容易就可以扩展实现 Cluster Reflection Probe 的逻辑。
这里额外需要解决的问题是每次渲染中贴图的数量是有限的,如果分开存储每个反射球的环境贴图,数量是肯定不够的。一种方法是把多张 CubeMap 上传到 3D 贴图中,一张 CubeMap 就是 3D 贴图中的一个 z 分量,缺点是老设备不一定支持。另一种方法是把多张 CubeMap 合起来打到一张 CubeMap atlas 上(相当于把 3D 贴图展开成一张 2D 贴图),缺点是反射算法得自己写,并且很容易采样到不相关像素造成画面溢出。我们考虑的是优先使用 3D 贴图的方式,如果设备不支持则回退到 CubeMap atlas 的方案。
优化方案
渲染调试模式与遮挡剔除
在整个 Demo 的制作过程中,随着游戏表现力的增强,大量的计算开销对性能方面也会带来巨大的负担。为了能在手机上流畅的运行这个巨大的场景,我们尝试做了很多优化,其中一项便是加入了 overdraw 调试渲染模式。overdraw 的意思是游戏在运行过程中重复绘制同一个像素的现象。消灭 overdraw 主要就是为了解决 GPU 端像素填充率和计算量的瓶颈问题。overdraw 调试渲染模式的目的就是为了将游戏里可能存在的重复绘制像素问题转化成更直观的表现,从而知道哪些像素是被重复绘制的。
在上图中可以看到,越红的区域代表 overdraw 越严重。图中截取的当摄像机处于城市中央时候的调试信息,有很多建筑即使被其他建筑遮挡了依然会被渲染,这就浪费了很大一部分性能。因为在 Demo 场景中大部分物体都是静态的,因此决定采用预计算的遮挡剔除方法。在场景中按摄像机的活动范围划分出多个格子,在每个格子中预先计算出摄像机能够看到的所有物体并缓存 ID,最后在运行时我们只需要简单查表就能得出剔除后的结果,几乎没有性能消耗。预计算遮挡剔除计算流程如下:
划分摄像机运行范围
根据范围划分格子
在每个格子按规则发射射线检测
>>固定数量均匀发射
>>对每个物体的每个三角形发射
将检测结果存入格子数据
运行时简单查表得到剔除后的结果
环绕式场景延迟加载
我们可以看到在整个 Demo 场景里,游戏对象的数量是非常巨大的。通常,我们在做游戏的时候,都会有一个加载界面,如果初始化内容太久,就会增加玩家的等待时长,有可能在这段时间内玩家就已经流失了。因此,必须均衡加载时长,优先加载具有逻辑的节点,其余则放在后面慢慢加载。由于场景里大多数物体都是静态的,我们可以通过自定义序列化的数据的方式初始化,节省序列化时间。接着,采用环绕式的相机旋转方式,让大家以建造者的视角看到整个世界建造建的样子,避免等待时间。具体实现的流程如下:
划分逻辑节点与静态节点
对静态节点自定义序列化数据
按物体到世界中心的角度排序
加载时将摄像机旋转至已加载物体中最大角度
旋转一周则场景加载完成
以上就是关于本次《赛博朋克 Demo》的技术亮点分析,Demo 内容还会持续更新,力求打造更加丰富的「赛博空间」。
本次的《赛博朋克 Demo》基于 Cocos Creator 3.3 实现,相较初次发布的版本 Cocos Creator 3D v1.0,经历了近两年的打磨,Cocos Creator 的 3D 游戏开发体验攀上一个新的高峰,将帮助更多开发者创作出优秀的跨平台体验。9月4日,Cocos 引擎技术总监 Panda 还将在开发者沙龙「深圳站」上详解引擎在 2D 与 3D 方面的最新技术进展,赶快扫码报名吧↓
点击【阅读原文】查看 Cocos Creator 3.3 更新文档和下载地址,欢迎体验!
往期精彩