《恋与深空》首次深度技术分享:这可能是叠纸最「掏心掏肺」的一次
创始人
2025-10-24 22:50:24

真的是干。

整理/秋秋&依光流

10月24日下午,叠纸《恋与深空》团队在Unite Shanghai 2025上,带来了一系列关于游戏研发的干货分享。

说起《恋与深空》,很多人可能已经不陌生了。

其作为叠纸有史以来收入最高的游戏,上线一年半以来,在全球市场展现出惊人的爆发力——AppMagic预测,其累计营收已突破50亿元大关;前不久,它还作为唯一入选的中国游戏,获得了;在国内,。

可以说,无论是商业成绩还是行业影响力,《恋与深空》都能称得上一款创造历史的游戏。

那么,这款游戏究竟是如何凭借出色的内容品质与设计,持续吸引玩家沉浸其中的?

在本次Unite大会上,叠纸《恋与深空》的引擎负责人阮天龙、技术美术负责人秦平与资深物理算法工程师赵英杰,分别从影视级渲染管线搭建和物理效果开发等角度,分享了背后的技术实践与心得。

从葡萄君现场的感受来看,叠纸这轮分享比干货还「干」,并结合了大量实例。

第一场引擎负责人的演讲PPT几乎全是代码与示意图,葡萄君可以坦诚地说一句「完全没看懂」;后两场演讲虽用了大量动图演示,但其信息密度同样达到了万字级别——换句话说,今天可能是叠纸对开发者们最「掏心掏肺」的一次了。

具体演讲内容如下,为照顾阅读体验,内容有一定幅度的筛选和调整:

01

从光影到脸红流汗

大家好,先自我介绍一下,我叫秦平,2017年加入叠纸,此前有幸参与了《神秘海域4》《怪物猎人:世界》等项目,成为了叠纸首位TA,参与开发了《闪耀暖暖》《恋与深空》,现任《恋与深空》项目的TA负责人。

因为之前做过一些主机游戏,所以对高品质的游戏效果有一定的追求。今天想借这个机会,跟大家聊一聊《恋与深空》项目在追求角色效果表现上面的一些问题和解决思路。

我先总结一下对我们角色表现影响比较大的几点:

第一是分镜,项目的每一个具体表演和每一段约会,都采用了影视级导演分镜思维,来指导创作。一个好的分镜思维,是优秀作品不可缺少的部分。

第二,我们采用了大量真人动捕来提升角色动作表现;

第三,有了分镜和动作后,我们工具组的同事花了大半年的时间,打造的一套专业的剧情表演工具;

第四,我们采用了AI驱动的校对口型、表情同步的技术方案;

第五,也就是我们这次分享的主题:定制化的光照渲染方案。

首先,我这里讲的光照方案,不是大家熟悉的前向渲染、延迟渲染等管线技术,而是一个解决方案,比如角色应该受到哪些光照、怎么管理这些光照等。

说到这里,可能大家都会遇到一些上述问题。比如有人会抱怨游戏场景和角色分裂感很严重,或者一个静帧打光完成后,看着效果还可以,但镜头和角色动起来,效果就差了很多等等。

我将具体的光照问题分成四部分:

第一是光照需求的冲突。比如一个夜晚的场景,需要用冷色调渲染夜晚的氛围,但角色面部,则需要一个暖光来保持自然肤色——如果我们只用冷色调强调氛围,那就容易让角色不自然或失去立体感;

第二是协作问题。比如一个室内的场景已经设计好了,但放入角色后,发现角色表演的位置透不进来光,就去跟场景同学沟通开窗或者增加光源,但补光又可能导致动作与光源不匹配……这些反复沟通可能会浪费很多成本;

第三是工作量问题。如果游戏每张卡牌、每个剧情、每段表演都要从头单独制作的话,就会产生海量的工作;

最后是高品质的需求。我们希望游戏呈现的内容,每一帧都经得起大家反复观看,因此就需要灯光效果可以逐帧精修。

我们将上述问题拆解一下。

关于场景和角色,我们需要这两者的光照可以分开调整,尽量互不影响,同时支持逐帧调整光照参数和效果,以及支持模板的保存和编辑。

得到了这些需求后我们就可以推进解决方案。

我们知道光照是由直接光和间接光组成的,直接光是平行光、射灯和点光。一般情况下,我们只会有一盏平行光,我们习惯称之为主光。

我们的基本思路是:使用主光源正常照亮整个场景,但在处理角色时,我们只保留主光的方向信息,转而使用角色的PPV(Post Process Volume,后期处理体积)来覆盖主光原本的颜色和强度。

具体实现上,我们额外传递了一个专属于角色的主光颜色,确保角色获取到的是最符合其视觉需求的「角色色谱」。此外,还为角色单独添加了一盏不产生投影的平行光,专门用于勾勒角色的轮廓。

同时,我们还预留了两盏额外的灯光供角色使用,它们可以是任意的点光源或射灯组合。这些是正常的光源,能照亮其范围内的所有角色和场景物体。由于我们的系统规定在每个2米的格子里最多只能存在四盏这样的额外光,因此我们对其进行了划分:固定分配两盏给角色,另外两盏则留给场景使用。

对于间接光的处理,我们采用了Unity的LightProbe系统来构建光照探针。不过,我们将间接光信息存储到探针内部的逻辑是自主实现的,这使我们能够将场景环境和角色环境的间接光照分开两套,分别存储和使用。

至于环境光的高光部分,我们仍然使用了场景通用的反射指针来获取信息。但在一些特殊的角色材质上,我们支持了一些参数的覆盖输入。

接着,我们将所有影响角色光照的参数统一存储在一个对象 (ableobject)中,由灯光师调整完毕后,保存为一个可复用的模板。大家可以看到下方右侧这张图,这就是我们保存下来的一个资源包,我们称之为「角色工作模板」。

这个模板中集成了我刚刚提到的所有元素:两盏平行光、两盏额外灯光、从探针中保存的间接光信息,以及后期处理体积 (Post Process Volume)上可额外调整的参数——比如补光颜色和外光颜色等。

最后,我们通过一个管理器 (Manager),采用类似「栈」的结构来统一管理这些灯光模板。这种栈式的管理方式,与我们的实际使用需求密切相关。通常情况下,除了加载一个新的灯光方案之外,最频繁的操作就是需要快速切换回上一个使用的灯光效果。栈结构天然支持这种「返回上一步」的逻辑,因此能非常高效地满足这一特性。

到这里,这套角色光照方案就基本完成了。它成功实现了我们最初拆分的核心需求:角色光照与场景光照能够分开调整,并且支持实时、灵活地切换。

下面是角色在不同光照方案之间切换的实时表现。

我们将「切换灯光方案」这个操作,编辑器里定义为了一个事件。这种事件驱动的设计有个天然优势:因为它只在切换发生的那一刻修改参数,这就为后续的动画配帧留下了接口。

大家接下来看到的,就是在编辑器里进行动态配帧的实录。我们可以像处理角色动画一样,为光照变化「K帧」,精细调整每一刻的光影效果。可以看到,其中大量的参数都被设置了关键帧——不仅是后处理效果,包括灯光、阴影的细微调整,也全都录入了动画曲线。

不仅如此,这个配帧系统不只控制灯光,它更是我们整合所有表演元素的入口。无论是物理效果还是其他系统,都可以在这里配置进去。

而正如大家所知,光与影从来密不可分。介绍完「光」,接下来就重点谈谈我们的「阴影」。

我的同事之前提到了我们的阴影方案:三级CSM配合特写阴影。我将着重介绍后者——特写阴影。

它的原理很直观:我们可以在角色身上选定一根骨骼作为球心,并指定一个半径,从而构建一个包围球。我们的子系统中可以设置这个包围球的半径,并通过「父节点」参数来指定那根作为球心的骨骼。比如我们以选定的骨骼为球心,以0.85米为半径构建球体。

当场景中存在多个角色时,系统会用算法计算出能包裹所有个体包围球的一个更大总包围球,并基于这个总包围球来计算最终的Shadow Map (阴影贴图)

从上面可以清晰看到效果:原本完全处于室内阴影中的角色,在启用特写阴影后,面部被精准照亮了。这正是特写阴影的价值——确保角色在任何复杂光照环境下,面部等重要细节始终清晰可见。

以上演示主要是为了说明,我们的特写阴影系统提供了丰富的参数可供独立调整。比如,我可以推动「近裁切平面」参数,将房屋的墙壁排除在阴影计算之外,从而确保角色面部被准确照亮——我们的目标是通过灵活调整这些参数,为不同场景找到最优的配置,最终呈现出最好的视觉效果。

说完了整体的光影,我们接下来聚焦于角色本身的渲染细节,特别是皮肤质感与面部细节表现。

在皮肤渲染方面,我们提供了高低两套配置方案:高配方案采用基于屏幕空间的3S技术 (Subsurface Scattering)。由于3S本身需要模糊处理,我们适当降低了分辨率进行计算,这反而在保证效果的同时兼顾了性能;低配方案则使用了一套专门的工具,来实时拟合与生成近似的皮肤质感——这部分技术今天就不详细展开了。

接下来,我们重点介绍一些更细微的表现。

例如,我们实现了动态的脸红和流汗效果,它们能极大地增强角色的生动感和情绪表达。此外,我们还完善了大量面部细节。比如解决了张嘴、闭嘴时口腔内部的环境光遮蔽问题;实现了眼球高光的动态变化,以及睁眼、闭眼时双眼皮的自然褶皱效果,但由于时间有限,我们先聊聊角色脸红和流汗效果。

下面是我录制的一张卡牌的动画效果,为大家展示角色的脸红表现。当女主与男主进行互动时,动态改变面部肤色能极大地增强画面的生动感和真实感。

通常来说,脸红是一个渐变且区域强度不同的过程——比如大多数人会从耳根开始泛红,逐渐蔓延至脸颊,有时甚至会满脸通红。为了模拟这一过程,我们将脸红效果做成了一张可分通道控制的遮罩图,每个通道对应一个面部区域,可以独立调整颜色。

但如果全靠手动逐帧调整,工作量会非常庞大。因此,我们再次采用了模板化的思路:美术同学可以为不同的情境(如羞涩、运动后)预先制作好不同的脸红变化曲线并存为模板。在实际需要表现脸红时,我们只需调用对应的模板,就能高效地实现自然的脸红效果。

而当脸红到一定程度,比如在运动后满脸通红时,如果只有脸红而没有流汗,真实感依然会打折扣。所以,我们还配套开发了流汗效果。流汗效果主要由两部分构成:

  • 一是粒子表现:我们使用粒子系统来模拟汗珠飞溅的效果,用来描述一些甩汗的效果;

  • 二是材质变化:这部分又细分为两点:首先是通过降低皮肤粗糙度,来模拟出汗后皮肤湿润的反光感;其次是生成了凝聚的汗珠。

汗珠生成的思路,与我们2019年Unite上某次技术分享中介绍的「闪点」实现一脉相承,

具体来说,首先,我们将角色面部的UV空间划分为均匀的网格;然后,将每个网格的唯一ID作为输入,确保每个格子都会得到一个固定且唯一的随机数。

这样一来,我们就能根据这个处理后的随机值,来决定在哪个格子的范围内生成汗珠的初始凝聚点。这不仅保证了汗珠位置的可控性,也避免了不自然的均匀分布。

大家可以看到下面的这段简短的代码,就是这一逻辑的具体实现。右边视频所展示的、带有随机分布感的逼真流汗效果,正是基于这套机制实现的。

当然,如果汗滴只是简单地沿直线流下,会显得比较生硬。为此,我们额外加入了一个模拟汗珠流动轨迹的小算法,在上图右下角的位置,让汗水的流动路径更贴合面部轮廓,从而更加真实自然。

感谢大家的倾听,以上就是关于角色面部细节渲染的分享。

02

风吹衣角、发丝微颤……

这些细节全靠它

大家好,下面我为大家带来《恋与深空》物理效果开发的分享,首先做一下自我介绍,我叫赵英杰,2020年加入叠纸,参与过《闪耀暖暖》《恋与深空》项目,目前在《恋与深空》内主要担任资深物理算法工程师,主要负责物理和动画的相关内容开发。

这次分享主要分为四个部分:布料模拟的实现、实时表演的控制、基于Unity DOTS的开发,以及最后的检测模块。

首先是布料模拟的实现,这在《恋与深空》中其实占了相当大的部分,比如具体表演、战斗、互动、玩法当中,都大量使用了布料。

我们自主开发了一套基于骨骼的布料模拟系统,团队内部我们都叫它Stray Cloth。采用的模拟方法,是XPBD结合SubStep的方式。相比PBD,XPBD的优点是摆脱了迭代次数和时间步长的依赖,结合Substep可以显著提升收敛效果。

比较特殊的地方是我们采用骨骼作为基本的模拟粒子,比如每个粒子除了位置外还带有旋转信息。在具体的Substep当中,我们针对不同的性能压力,采用动态的时间,在1/200~1/300之间。并且对于场景中的运动对象,会进行插值,这样运动效果会增加稳定性。

事实上,运动插值虽然性能开销不是很高,但由于碰撞类型比较多,比如有各种碰撞体,分场静态粒子等等,所以实践起来还是非常麻烦的。

这里有一个疑问,为什么我们使用骨骼,而不使用代理网格、使用顶点的方式,去模拟布料?

因为《恋与深空》对于布料模拟表现的需求其实比较复杂, 很多时候需要动画、解算的共同介入,骨骼方案可以很好地在这两者之间过度,以及平衡。

然后受限于移动端性能,骨骼方案结合我们的配置,可以给美术很大自由调节的空间。在骨骼的基础上,我们实际上构建了类似于顶点模拟的约束方式。下面右边的图,就是我们新资产的效果,可以达到和Mesh模拟相对近似的效果。

在已有的骨骼布料模拟方案里,骨骼约束实现通常会采用基于Local和Global的形状约束方式,这种方式优点是简单快速,但也有非常明显的缺点,就是在作为布料模拟的时候,它的效果偏向于卡通,不太符合《恋与深空》追求的3D写实风格。

而且它的参数调整非常不直观,因为它有Local和Global两个参数,不利于美术调整,以及在不同场景下的效果匹配,特别是在大形变的情况下,效果表现就非常奇怪。

所以我们在骨骼约束方案上选择了基于Cosserat Rod的方式,它有几个优点:

效果上更贴近于《恋与深空》3D写实美术风格;而且在弯曲参数上也只有一个参数,给美术调整起来更加直观;并且三个轴的参数是分离开的,在模拟一些特殊场合,比如带有裙撑的裙子,就可以通过各项分离的弯曲参数来模拟出近似裙撑的效果。

这个方法其实在正常情况下更多用于头发、绳子的模拟,所以头发也和衣服一样,使用同一套约束方案,这样整个工程量就会简化不少。如下图右侧是我们《恋与深空》最新日卡的表现效果,总的来说,基于Cosserat Rod的骨骼约束是可以满足项目表现需求的。

布料与角色的连接,通过两种方式:第一种是静态骨骼,它直接受角色的骨骼动画影响,根据层级关系进行移动,这种方式比较简单,在一些偏向于刚性的连接部位表现良好。

但是对于一些骨骼交界处,比如有多个骨骼的存在,或者说存在一定的骨骼拉伸和收缩的较为复杂的位置,比如说手肘,肩部,腰部,表现上容易出现布料和角色的分离。

这个时候,我们提供第二种吸附的方式,和Maya里面的吸附方式类似,我们将静态粒子吸附到角色模型的某个三角形上,通过并行的Bake Mesh来获取每帧顶点的更新位置,使用离线计算的重心坐标来更新粒子的Transform。

对于三角形存在的退化问题这种特殊情况,我们使用三角形顶点的Spin蒙皮骨骼的变化进行加权平均,来分析静态粒子的Transform来解决三角形退化时的这些特殊情况。

在碰撞管理方案上,我们使用Dynamic BVH作为场景宽相位检测 (Broad Phase)的核心数据结构。每个角色被组织为一个独立的子树 (Subtree),而角色身上的各个碰撞体则作为该子树下的节点。通过角色ID、碰撞体可见性 (是否参与碰撞)以及部件类型 (如武器、服装、身体)这三类规则,我们实现了对不同角色、不同部件之间碰撞关系的精细化管理。

在碰撞解决流程上,我们并不在检测到潜在重叠后立即生成Contact Generation。而是先将这些检测到的重叠信息缓存起来,留到物理更新的Substep中去解决穿透问题。采用Substep的主要优点是:在大多数情况下,仅依靠离散碰撞检测,就能有效避免因物体快速移动而导致的穿透问题,从而无需引入计算代价更高的连续碰撞检测方案。

对于参数化的几何碰撞体,例如plane、capsule、box,就可以比较简单地解决它们和粒子以及Edge之间的碰撞。在肩部、胸部、背部等比较复杂的区域,参数化几何体其实难以表达角色的模型形态,表现上容易发生穿透,所以在这些部位大量的使用Mesh Collider。

但是Mesh Collider作为不规则的凹凸,甚至有些时候它都不是封闭的,只是一个面,想要表达精准的碰撞效果,相对于参数化的几何体来说就比较困难,特别是在移动端设备下。

然后我们采用的方式,就是用Spatial Hashing来作为三角形的一个粗略查找方式,结合缓存的邻近三角形结果在迭代开始时,生成一次粒子三角形的碰撞对,在后续的迭代中判断粒子是否在三角形的范围内,如果超出范围我们会通过连接关系,进行限制步幅的查找来获取适合的三角形,可以缓存它的结果作为下一次的使用。

下面右边的图,就是项链和角色身体的表现,可以看到效果还是比较稳定的。

面部碰撞体它可以看作一个特殊的Mesh Collider相对于基本的Mesh Collider来说,面部碰撞体的特性比较固定,比较平滑。从模型中心出发,基本上会有三角形重叠。

所以我们直接使用16x16的CubeMap,来一起计算各个方向上的三角形,这样子我们碰撞计算的时候,就可以快速查找到临近的三角形,相当于替换掉上一个Mesh Collider当中Spatial Hashing的粗略查找结果。

游戏当中布料模拟的次碰撞是最难处理的部分,出于性能上的考虑我们给出的方案是由美术预先对物料进行分层,然后考虑这些层之间的碰撞。使用Spatial Hashing作为查找的加速结构,另外为了避免层之间卡住的情况,我们只考虑单法线方向的碰撞,如果穿透了则略过,交给后面的步骤来修复它。

在实际实践中,我们使用上一次Spatial Hashing的粒子位置,和当前的粒子位置来进行碰撞,这样就可以简单的解耦的数据,避免它的依赖。然后下图右边是我们层间碰撞的例子。

对于已经穿透的部分,我们参考了Untanging Cloth的方式,然后提出一个轻量的解决方案,就是通过布料分层从布料的固定点出发,计算不同层级间的边和三角形的交点。

因为我们的资产结构的关系,所以说它必然为一个Uniform网格,因此我们可以通过这个网格的交点,来比较简单的推测出其他粒子的推出三角形,最后对穿透的粒子三角形施加弹簧约束来解决他们的穿透。

在实际实践中,由于Substep的关系,穿透的概率相对来说是不大的,因此我们会采用分帧分块执行,来减轻它的系统压力,下面右图是一个三层的穿透分离的测试,可以看到各种布料可以从穿透当中恢复过来。

接下来的,是实时表演控制,实时表演在《恋与深空》中占了相当大一个部分,比如剧情表演中就大量使用。

《恋与深空》中的大部分剧情表现,都是依托于Cutscene来实现的,实现各种各样的效果与控制的调节,这里要感谢工具同学开发和做一套非常强大的Cutscene工具。在他们的基础上,我们开发了多种功能轨道来具体的调控物理效果。

物理相关的功能轨道,其实我们做了非常非常多的准备,下面只是一部分比较常用的功能轨道,后面我会比较详细的介绍它们的具体功能。

下面是我们一个动卡的Cutscene Physcs Track例子,因为我们的美术对于整个游戏的画面表现抠的非常非常细,虽然说只是一个普通看上去的镜头,它在实际的位置的配置当中是非常复杂,从这个图中可以看出,美术用了大量的轨道来保证画面能够达到他们的预期效果。

Cutscene Physcs Track 示例

然后是SmoothBlendPose,在表现当中一个非常常见的问题就是动作瞬间切换带来的物理抖动,这个无论是在剧情表演中还是在换装当中都非常容易出现。

我们开发了一个较为通用的办法,通过记录初始物理姿态,在切换的时候就是用初始姿态与当前姿态进行姿态插值计算,这样就可以大幅度缓解这个抖动。当然这可能会带来一些时间开销,一般来说会在几毫秒到几十毫秒左右,大多数情况下,都是可以接受的。

我们还会额外提供一些参数,比如插值次、插值步幅大小,然后美术可以根据实际的需要去调整。下面图片右侧是拍照换装切动作时,会有一个大幅度的动作切换,可以看到它的表现还是相对稳定的。

当然,SmoothBlendPose始终存在一些局限性,它是通过Pose间差值得到的一个结果,它并不能够保证完全的顺畅,特别是在一些剧情表演的复杂切镜下。

这种情况下,我们提供了一个比较直接的方案,就是一键,由美术直接保存某个时间的物理状态,在播放的时候,直接将物理状态用到布料上,这样就可以完美避免切镜带来的布料抖动问题。

参数编辑轨道,单一的物理参数很难满足剧情当中各种不同场景下的表现。比如有时候,希望布料软一些,硬一些,大一些,小一些。

我们提供编辑参数的轨道,通过这个轨道来实时的修改参数,绝大部分的参数都可以被我们这个轨道来覆盖到,可以非常方便美术来针对一小段的时间帧进行参数修改。

这个参数修改其实还可以用来做一些特殊的效果。比如说下图当中,美术会利用这个参数轨道来对约束参数做一些编辑,这样可以实现一个实时的类似于布料断开状态的效果。

动画轨道,完全的物理轨道不足以支撑整个游戏方方面面的表现,很多时候需要动画和物理的结合来做一些互动,我们通过动画轨道来实现动画和物理的衔接与融合,清晰的控制不同时间帧上的表现。

在实际的制作流程当中,动画在DCC里面和最终进引擎的表现差异非常大,还包括一些引擎的支持率的修改系统之后,动画可能会和其他地方有穿透,所以我们会在动画融合的基础上再叠加上物理碰撞的效果来避免一些穿插。

下面是项链在物理和动画之间相互交互的效果,包括从物理到动画的状态切换,以及在不同动画之间的切换。

撞体轨道和风场景轨道,他们都可以在Cutscene当中动态创建、销毁,根据不同的画面表现需求,灵活地改变碰撞体和风场的状态。

通过角色部件类型,还有布料的层分组,来细节控制所要影响的对象范围,并且碰撞体和风场轨道的绝大部分参数都可以添加动画帧来控制,包括碰撞体的形态大小,风场的方向、范围、强度、湍流等,方便美术细节把控物理效果跟风吹变化。下图就是碰撞体和风场的表现例子。

接下来是基于Unity DOTS的开发,我们整个套物理系统都是构建在DOTS上,DOTS的工具非常强大,在C、功能迭代,还有Debug,都非常的便利。目前来说,我们最高可以支持2000+骨骼粒子的模拟。

当然,在针对性的在这个项目使用当中,我们也做了一些优化来进一步的提升性能。第一个就是Cache Job。模拟当中Job教务数量和依赖关系是相对比较确定的,Job data并不频繁变化,针对的一般为相同数量和依赖关系的Job组进行多次循环。

Unity Jobs在发起任务的时候,都需要重新创建Job data,虽然你可以提前发起任务来缓解在此线程上的执行,但是它依然卡主线程。基于以上的观察,我们开发了Cache Job的方案,就是预先创建好Job data,并且每次执行时复用,避免每次重新创建Job带来的一些性能开销。

实际实现上相对来说比较简单,因为它是一个专用的结构,只考虑一些固定的使用场景,我们额外添加了一个Atomic Queue来存进Cache Job,使用Fetch-and-Add Array来具体存它需要的Job data,下图右边是我们执行Cache Job的一个简单的流程示意图。

Brust它会针对不同的平台生成高性能的Simd code。在Brust Inspector当中,你可以看到它所生成的一些Simd code经过检查它的Brust Inspector,还有经过我们一些实际的测试,在某些场景下,我们也可以通过手写它的Arm Neon Intrinsics来进一步的提升性能。

下面是具体的使用案例,对市面上流行机都有比较好的性能提升(骁龙855开始、苹果a11开始),特别是做展开用指令集能得到更高的性能提升。

对于点乘,我这里列出了3种方式,使用neon intrinsics相比于mathematics在测试用例中可以获得约30%的性能提升。如果目标机型支持armv8.2的话,可以使用新增的规约加法指令,来进一步的提升性能。一般来说现在市面上的大部分流行机型都是支持armv8.2的。

另一个例子是float4x4的转制,对于转制计算,我们可以看到Mathematics生成的Simd Code的性能就是非常低的,通过手写Intrinsics我们就可以得到一个巨大的性能提升。

当然,如果只是直接的转制,也可以得到更快的性能,但之所以要像前面这么做,是因为我们一般在项目中,是通过这4个float转制,来将点乘变成矢量乘,所以这里写成这样子。

但在实际的使用当中,你的Mathematics的代码实际是类别进你具体的一个上下文当中的,它最终生成的Simd Code可能会相当于你自己的代码测试,差别会非常大。

所以说在具体优化的时候,你还要根据代码的上下文进行一个具体的调整,可以根据Brust Inspector分析测试还有一些优化手册来具体修改。

最后是我们的碰撞检测模块,首先要回答一个问题,就是Unity已经有一套非常成熟的物理模块,然后我们为什么要脱离Unity成熟的物理模块,再重新开发一套?

因为《恋与深空》中有相当多不同种类的玩法,玩法及种类也相对独立,有一些模块,比如说战斗,需要有特殊的一个Trigger触发和退出机制,并且他们希望在底层有更多的支持,所以执行流程上,也希望有更多灵活的控制。

然后我们在细分探索上,也有一些自己的想法,就是在只需要碰撞测试的情况下,我们利用DOTS能够提升它的性能。

在《恋与深空》的实现当中,我们的碰撞体测试模块基本实现了Unity原生的所有碰撞插件功能,针对战斗还有其他模块,我们定制了Update和Trigger相关逻辑。

并且对于查询结果,在底层去保证的线程安全,将上层可以无负担调用,结合DOTS进行轻量化的结合实践以及一些结合实际需求的优化。在性能测试当中,我们最高获得了15%的性能提升。

下面是游戏战斗的画面,整个角色的移动包括一些技能运动,都是用我们自己的这套碰撞检测模块来实现的。

这边也给出一个比较简单的查询流程示例,因为真机上我们实际线程数量固定为4,所以对于Memory Allocater来说我们可以预先分配好它的线程数量,在分配的时候,直接根据当前的线程索引来获取所需要的一个内存。

然后我们使用基于SAH的Dynamic BVH作为加入结构。在插入、删除,以及超出范围的时候,对当前操作节点的临近几个层级进行旋转、平衡,在修改效率以及数的质量之间做了一个平衡。

因为碰撞检测的功能相对来说比较概括,对于精度没有那么高的要求,所以我们适当的也牺牲了一些精度,简化了一些碰撞检测算法,来提升它的性能。

为了满足战斗的需要,我们还设置了特殊的Trigger触发逻辑,触发Trigger的进入和退出,不要求它必须成对出现,可以看到下图右边的一个流程示意图 。在A触发B的函数中移除B以后,会触发所有B存在的Overlap Collider。这里和Unity原生的不一样,原生Unity中在Trigger里去删除掉B时,是不会触发其他碰撞体的Trigger。

最后,我们会通过History计数来标记Collider版本,来解决整个战斗当中它对一些角色或者说碰撞体的复用,可能导致的潜在问题。我的分享结束了,谢谢大家。

游戏葡萄招聘内容编辑,

相关内容

热门资讯

《恋与深空》首次深度技术分享:... 真的是干。 整理/秋秋&依光流 10月24日下午,叠纸《恋与深空》团队在Unite Shanghai...
比高·私域IP引流变现 本文给大家分享一套比高·私域IP引流变现资源课程视频,希望可以帮助有需要的同学51自学联盟分享比高私...
红人星球《抖音同城快速变现课》... 本文给大家分享一套红人星球《抖音同城快速变现课》适用于实体店做本地生意的老板资源课程视频,希望可以帮...