“编辑语:《星际穿越》游戏凭借高清的画质,出色的渲染能力与极致的性能表现,受到了很多开发者的关注。今天小编有幸邀请开发团队 gamemcu 做一次技术分享,希望对大家有所帮助!
Q1:请大佬介绍下这款游戏
《星际穿越》是一款次世代模拟飞行游戏,拥有高清画质和震撼的飞行体验。
在游戏中,你的掌心的玩具蜕变为星际战舰,透过电视开始一场惊险刺激的飞行旅行。
大家可以在下方链接进行体验:
“在线体验:https://gamemcu.com/fly
项目已开源,欢迎各位开发者自由下载,二次创作。
“开源地址:https://github.com/gamemcu/interstellar-next
注意,该项目基于 Cocos Creator 3.8.3,定制的引擎管线可能与新版本不兼容,请谨慎升级!
Q2:《星际穿越》有哪些技术亮点?
本项目主要使用了下面这些技术:
-
自定义高清渲染管线 -
重构PBR材质系统 -
高品质后期处理 -
多边形 GPU 粒子系统 -
高性能碰撞物理模拟 -
IK 模拟 -
音效系统设计 -
指数级高度雾
项目代码结构如下:
cinetation //镜头控制器,用于调试
components //自定义组件
controllers //游戏控制器,镜头、手、飞船等控制器
datas //游戏数据
managers //各类管理器
pipline-next //自定义高清管线 + 后期处理
statics //静态资源,贴图、模型
resources //动态资源,音频
Q3:有没有给其他开发者的技术分享?
我最想给大家分享的是项目的优化技巧。优化分了两块,包括渲染优化和互动优化。
渲染优化
1. 场景渲染

将模型和材质直接拖入引擎中,你会得到如上图所示的效果,虽然看起来不错,但离真实感还有一定距离。
主要问题出在间接光、曝光和反射上。经过优化后的效果如下:

优化工作包括:
-
自定义高清渲染管线(开启 float 输出,支持颜色值大于1) -
添加 FXAA(优化版,边缘更锐利)、Bloom(基于 Mipmap Blur)、Tonemap(拟合函数,性能更好) -
添加自定义 PBR 材质(去除了复杂光照计算,保留IBL并引入单次散射拟合,避免金属部分过暗) -
支持自定义烘焙光照贴图 -
扩展光照探针,支持自定义环境贴图(模拟环境反射)
2. 人手渲染

经过以上优化,手的光照效果已经比较真实。
最初,我尝试了 SSS(Subsurface Scattering,次表面散射),但后来发现直接烘焙光照效果就足够,在本项目中视觉差异并不大。

添加间接光(烘焙贴图),可以让手部渲染效果看起来更真实,同时,手指的捏合效果也可以通过动态调整间接光的强度来模拟光影变化。
至此,主场景的渲染优化工作完成!
互动优化
1. 动态手部动作模拟
静置的时候,让手动起来可以让画面更真实,可是该如何动呢?

项目采用了叠加多个 Perlin 噪声,生成更平滑的分型噪声(FBM),并给手的肩关节、肘关节、腕关节不同的噪声幅度,模拟人的的呼吸感和摆动(虽然也考虑过使用 K 动画,但复杂度较高,噪声方法更简便)
玩家可以通过控制手部的动作来进行交互,这里通过添加骨骼权重和动态控制关节旋转来实现。
此外,为了优化骨骼动画的编辑,项目中使用了 Cocos 的小技巧:
将 SkeletalAnimation
替换为 Animation
,这样就能通过 Cocos 的动画编辑器编辑骨骼动画,并且能动态调整抓取动画的速度,非常方便。
电视画面的渲染是通过UI相机实现的,简单的激光位移和旋转处理,就可以让画面看起来有3D感,这样无需重复渲染3D画面,可以节省下大量性能开销。
为了让老式电视更加真实,项目中加入了扫描线的特效和暗角。

后期效果中也加入了扫描线效果,可以在片段着色器中简单通过 sin 函数实现。
然而这样直接实现非常耗性能,于是我写了个拟合函数来优化:
0.9+1.03*mix(-y*y,y*(y-2.)+1.,y)替代
0.9+0.1*sin(y*500.0)性能提升非常大(超级干货,可以抄!)
性能提升非常大(超级干货,可以抄!)
2. 真实感尾焰
写实风格的尾焰渲染过程遇到了不少挑战,尝试过多种方案,比如贴图流动和视频播放,但要么效果不理想,要么性能开销太大。

最后,我们通过多层模型+顶点偏移+噪声+颜色混合实现了尾焰效果。
另外还加入了镜头光晕效果,随着镜头的旋转,光晕也会动态变化。具体实现可以参考flame.effect
。

3. 多边形GPU粒子系统
游戏内粒子的效果比较抓人眼球,相信很多人都想知道如何实现的,下面介绍下原理,具体请参考 initParticleMesh
函数的实现。

飞机收集电池的特效分成多段,由扫光+爆炸粒子+收集粒子组成。
扫光是通过 Fresnel 分段偏移实现的,爆炸粒子使用了常规的粒子系统。
收集粒子比较复杂,其实是个模型,具体原理和飞机的合成特效一样,只是 Shader 中做了不同处理。

粒子实现具体分为四步:
-
模型拆面,移除 indices,计算每个面的重心坐标,并写入贝塞尔曲线参数;
-
顶点着色器中,将顶点位置以重心坐标为参考,按照贝塞尔曲线进行偏移;
-
加入噪声让顶点位置在贝塞尔曲线上随机偏移,可产生拉伸效果;
-
在片段着色器中,根据粒子生命周期,将颜色、AO、反射做适当的处理。
“有没人对电池效果的实现好奇?这里电池由三部分组成,分别是外壳、外发光和里面的闪电。这里外壳和外发光其实只是一张朝向相机的图片,里面的闪电是个模型,极致优化!
4. 指数级高度雾(美颜 + 抗锯齿)

这是没有雾气的效果,为了让大家直观感受指数级高度雾的效果,我只能把这种丑陋的图片拿出来。

以上是指数雾的效果,改善了很多,画面变干净了,锯齿也少了,但是场景缺乏层次。


这是指数级高度雾的效果,画面不仅更干净,还更有层次感和氛围感。
5. 多种物理碰撞模拟

为了让游戏中的碰撞更加真实,我们针对不同碰撞物做了不同的碰撞处理,尾焰效果也会做不同程度的缩放。

6. 解决模型破面问题
由于第一次做跑酷游戏,在开发过程中,模型破面问题困扰了我一段时间。

后面经过调查发现,这并非引擎问题,而是 GPU 浮点数精度的问题。
解决方法如下:
-
将顶点着色器中的 "precision mediump float;" 改为 "precision highp float;",否则距离超过100m就会破面; -
当飞船移动超过100m时,复位到起始点,并且场景内所有物体相对飞船一起平移,这里要处理好特效的位置。
总结一下
由于篇幅关系,游戏内还有不少细节没有涉及,欢迎大家查阅源代码,挖掘更多有趣的技术实现。
“再贴一次开源地址:https://github.com/gamemcu/interstellar-next
本项目从管线到材质,再到各种 trick,通过打磨大量细节,最终呈现出了一个让人相对满意的画面和体验。
Q4:最后再介绍下团队吧
我们团队叫 gamemcu,专注于用户体验的探索与创新,希望今后能给大家带来更多优秀作品!
结束语
感谢 gamemcu 团队接受采访!希望本项目的代码和经验,能够帮助到更多开发者。