游戏葡萄公众号文章

《代号:神不言》干货分享:祖龙如何用UE5做出「热辣滚烫的肉体」?

在你身边的他,究竟应该是什么样子?

游戏葡萄

公众号 · 85 篇文章

图片

在你身边的他,究竟应该是什么样子?


整理/秋秋&大田

10月22日,在Unreal Fest Shanghai 2026上,祖龙娱乐围绕旗下在研新作《代号:神不言》,带来了两场技术演讲,分别聚焦角色开发与移动端光影表现。

《代号:神不言》是祖龙娱乐最新研发的一款UE5女性向游戏。今年4月,游戏在B站公开首曝PV后,至今播放量已经超过1100万。当时就有玩家感叹:「这技术真的是乙女游戏可以吃的吗?」

图片
图片

据了解,《代号:神不言》由祖龙娱乐VVANNA事业部打造,团队过往作品包括《龙族幻想》《以闪亮之名》,也是国内最早批量落地UE移动端工业化管线的研发技术团队之一。今年2月,VVANNA工作室正式升级为VVANNA事业部,同时成立了专属的引擎技术攻坚团队「女娲实验室」,试图进一步拉高女性向游戏的画面表现力上限。

图片

具体来说,团队希望借助UE5底层渲染、Substrate材质、MetaHuman人物、MegaLights灯光技术等一系列技术手段,更细致地还原角色的皮肤质感、神态情绪与肢体动态。用他们自己的话说,就是「我们要用冰冷的技术,做热辣滚烫的肉体」。

而这次Unreal Fest上的两场演讲,也让外界得以进一步了解,这些画面表现究竟是如何实现的。

其中,第一场由祖龙娱乐首席艺术家刘冰主讲,内容相对简单,主题为《超越写实:基于 MetaHuman 的美型风格化角色探索——〈代号:神不言〉角色开发实践》。

在《代号:神不言》的审美里,女性向游戏中的角色并非越写实越好,真正重要的是让角色既符合玩家的审美,又能呈现出可信的情绪与生命力——为此,团队甚至会主动弱化部分过于写实的面部结构。

图片

第二场则由祖龙娱乐女娲实验室首席渲染工程师Qian Shen带来,主题为《〈代号:神不言〉:移动端渲染的光影设计》,重点分享了团队如何在移动端实现更接近PC端的高品质画面,比如如何更好展现角色的眼睛、身体皮肤上的水渍、局部的光影表现。

图片

从两场演讲来看,《代号:神不言》的技术探索为行业提供了一个值得参考的方向:如何让技术真正服务于产品的审美与体验。

一方面,写实技术并不意味着必须追求完全真实的角色形象,还得能在成熟的技术框架上建立自己的美术风格;另一方面,当女性向游戏越来越重视角色表现力、镜头语言与情绪传达,如何在移动端有限的性能条件下,将资源投入到玩家最容易感知的画面细节中,也成为研发团队需要解决的问题。

图片

以下为两场演讲内容的整理。注意部分技术术语及口语表达经过转写与适当润色,可能与演讲者原意存在细微出入,仅供参考。


01

《代号:神不言》角色开发实践:

追求可信的美型风格化


在《代号:神不言》角色的设计与制作过程中,我们一直在探索一个问题:在你身边的他,究竟应该是什么样子?

今天,我想借这个机会,跟大家分享一下我们基于MetaHuman进行的一些风格化角色探索。

图片

我们基于MetaHuman的高质量控制框架,探索出了一套美型风格化角色的实现方案。接下来,我会从几个方面介绍我们在角色设计上的实践。不过在这之前,还是先请大家看一段最新的游戏实机画面。

已关注
关注
重播 分享 赞
观看更多
    游戏葡萄

    0/0

    00:00/01:49
    进度条,百分之0
    00:00
    /
    01:49
    01:49
    全屏

    倍速播放中
    您的浏览器不支持 video 标签

    继续观看

    《代号:神不言》干货分享:祖龙如何用UE5做出「热辣滚烫的肉体」?

    转载
    ,
    《代号:神不言》干货分享:祖龙如何用UE5做出「热辣滚烫的肉体」?
    游戏葡萄
    已同步到看一看写下你的评论


    在《代号:神不言》的角色设计上,我们并不希望将风格局限在某一种类型中,也不会刻意追求超写实的效果。我们的思路是以真实的结构和渲染为基础,融入一些非现实的角色设计,最终塑造出一种可信的美型风格化表达。

    图片

    在这个过程中,MetaHuman为我们提供了一个可信的技术底座。它拥有高质量的面部结构与拓扑(模型网格的布线方式,决定表情形变是否自然)、成熟的Facial Rig(面部绑定:用控制器驱动面部骨骼和形变,做出各种表情)与动画生态,以及标准化、可扩展的角色生产框架。

    有了这些基础,我们就可以把更多精力放在角色本身的设计上。比如,如何在真实结构的基础上,塑造出更符合审美的角色比例;如何弱化真实结构带来的扫描感,同时保留角色应有的真实感。我们希望通过这样的方式,建立《代号:神不言》独有的写实美型风格,让角色不仅足够好看,也拥有能够让玩家信服的情绪与生命力。

    图片

    不过,大家从刚才的视频里应该也能看到,MetaHuman默认的标准框架,与我们想要实现的角色形象之间,还是存在一些冲突。

    因此,我们也对原有框架做了一些调整。

    首先是角色比例的重构。对我们来说,真实结构并只是美型风格化角色的一个起点。在此基础上,我们还需要根据角色的审美需求,进一步调整他的外形。

    其次是表情上的取舍。肌肉和褶皱的表现越真实,不一定就越符合角色的审美。相反,有些过于写实的结构,我们反而需要尽可能地弱化,比如角色的法令纹。

    还有一个很重要的问题,就是动态表情的校准。角色在静态画面中足够漂亮,并不代表他在对白、做出大幅度表情的时候,依然能够保持同样的美感。我们希望角色不仅在静帧下好看,在真正动起来以后,也能经得住整个动画系统的检验。

    图片

    说到底,我们的目标是希望让用户感受到:在你身边的他,就应该是这个样子。

    围绕这样的目标,我们在现有技术框架上进行了四个层面的扩展,分别是造型的重构、表情的重构、渲染的重构,以及基于RBF(Radial Basis Function,径向基函数:根据角色当前姿态,在预设的几组姿态之间插值,驱动对应的修正形变)驱动的服装联动。

    图片

    首先是造型的重构。我们的思路是,在改变角色外观的同时,尽量不改变MetaHuman原有的技术路线和框架标准,避免重复造轮子。

    在保留这些技术基础的前提下,我们重新调整了角色的头脸结构、五官关系与身材比例,包括眼球与眼睑之间的关系、嘴唇与口腔的结构等细节,都进行了针对性的处理,让角色能够呈现出我们希望的美型效果。

    图片

    第二个层面是表情形态的重构。我们为角色建立了专属的Expression Layer(表情层),希望在保留MetaHuman原有动画能力的同时,让角色的表情更符合我们的美术风格。

    比如,我们对MetaHuman框架中351个表情节点进行了定制化处理,适当弱化一些过于写实的面部结构,减少它们对美型表现的影响,让角色在做出各种表情时,依然能够保持自身的美型特征。

    图片
    图片

    第三是细节渲染。这里我们的思路是根据角色的实际需求,有选择地进行增减。对于一些能够增强角色质感的细节,我们会适当强化;而对于那些虽然符合现实、却可能影响美型表现的部分,我们则会选择弱化。物理正确是我们进行渲染的基础,但最终呈现出怎样的视觉风格,仍然取决于艺术上的选择。

    图片

    最后一个层面是基于RBF驱动的服装联动。我们希望角色在运动过程中,服装也能根据身体姿态产生自然的变化。为此,我们通过RBF驱动服装产生对应的形变,改善角色运动时的贴合与联动表现。比如,当角色做出动作、关节发生弯曲时,服装的袖口和裤脚也会相应扩张,让服装能够更自然地配合角色运动。

    图片

    总体来说,MetaHuman的框架与算法,为《代号:神不言》的角色研发提供了很大的帮助。今天,我们还带来了另外一段开发中的视频演示,大家可以再看一下目前的实际效果。这些画面效果也能够同时在PC端和移动端上稳定运行。

    已关注
    关注
    重播 分享 赞
    观看更多
      游戏葡萄

      0/0

      00:00/00:56
      进度条,百分之0
      00:00
      /
      00:56
      00:56
      全屏

      倍速播放中
      您的浏览器不支持 video 标签

      继续观看

      《代号:神不言》干货分享:祖龙如何用UE5做出「热辣滚烫的肉体」?

      转载
      ,
      《代号:神不言》干货分享:祖龙如何用UE5做出「热辣滚烫的肉体」?
      游戏葡萄
      已同步到看一看写下你的评论


      对我们来说,MetaHuman提供的是一套成熟的角色技术基础,而《代号:神不言》要做的,就是在这套基础上,继续探索写实与美型风格化之间更大的空间。以上就是我今天分享的全部内容,谢谢大家。


      02

      《代号:神不言》移动端渲染

      的光影设计


      大家好,我是来自祖龙娱乐的Qian Shen,今天给大家分享一下《代号:神不言》这款游戏在移动端渲染上的一些设计思路。

      图片

      先简单说一下这款作品和我们上一款作品《以闪亮之名》的一些异同。和《以闪》相比,《代号:神不言》同样有精细复杂的角色,角色的渲染效果也是其中的一个重点。不同之处在于,《神不言》里面加入了大量影视化灯光的设计,对光影表现提出了更高的要求。同时,游戏中还有很多角色特写镜头,我们也希望把这些细节处理得更加精致,尽可能传达出设计师希望通过角色表达的情绪。

      大家从刚才的视频里应该也能感受到,每个镜头都有自己的打光设计,通过光影来塑造不同的镜头语言和情绪。比如这两张对比图,就能很直观地看到打光方式带来的差异。所以,对我们来说,传统的一道主光+一道环境间接光,已经很难满足这样的需求了。

      图片

      为了实现这些效果,我们将渲染管线调整成了比较常见的延时渲染管线(Deferred Rendering:先把场景的几何和材质信息写入缓冲区,再统一计算光照,适合多光源场景)。由于我们需要在渲染过程中采样G-Buffer(存放每个像素法线、颜色、粗糙度等材质信息的一组缓冲区),以及进行其他一些处理,因此放弃了原先的One Pass流程,也就是在同一个渲染Pass中完成G-Buffer写入和光照计算的方式。

      图片

      现在的流程是在Base Pass(将场景物体的材质信息写入G-Buffer的阶段)之后,先处理各种需要的Feature,再继续后续的Lighting工作。这样虽然会打断原有流程,但也为我们实现更复杂的渲染效果提供了空间。

      材质方面,为了进一步提升表现力,我们使用了UE5的Substrate材质系统,主要应用在角色的各种服装上。不过,Substrate原本主要面向PC端开发,如果直接搬到移动端,还是会面临不少问题。一方面,我们需要针对移动端进行定制化改造;另一方面,如果完整使用Substrate的树形结构,通过Blend混合多个Slab(Substrate中的基础材质层),无论存储还是解析,都会产生比较大的性能开销。

      图片

      因此,我们最终选择将它控制在One Closure(每个像素只保留一个材质闭包,不进行多层叠加),放弃了复杂的树形结构。

      但在具体的渲染特性上,我们还是希望移动端能够尽可能接近PC端的效果。比如布料、各向异性(高光沿某个方向拉伸的效果,常见于头发、丝绸和拉丝金属)、3S(SSS,次表面散射:光线进入皮肤等半透明材质内部,经过散射后再射出的效果),以及透射等特性的混合方式,我们都做了相应的适配。

      此外,我们还根据设计师的需求,开发了一些定制化的Feature,用来实现不同服装的材质表现。当然,这些特殊的渲染特性目前主要应用在角色身上。对于普通场景,我们还是尽可能采用传统的PBR(Physically Based Rendering,基于物理的渲染)方式,以节省性能开销。

      接下来,我想具体介绍一下其中几种材质的处理方式。

      首先是皮肤。对于《代号:神不言》这样偏写实风格的游戏来说,3S几乎是不可缺少的一环。我们在《以闪亮之名》中就已经使用了Screen Space,《代号:神不言》也延续了这一方案。

      在《以闪亮之名》中,我们会在Base Pass之前,提前渲染一次需要进行3S处理的材质。这一阶段只计算Diffuse(漫反射)相关的光照,随后进行Filter(滤波),模拟光线在皮肤内部散射的效果。等到Base Pass正式渲染这些物体时,再将之前处理好的结果与高光合并,就能得到最终的皮肤表现。

      而在《代号:神不言》中,由于采用了延时渲染,我们改用了和PC端更接近的流程:先完成Lighting,再像后处理一样对光照进行Filter,最后合并Specular(镜面反射,也就是高光部分)。

      图片

      这种方式也存在一些取舍。因为我们在Lighting之后进行3S处理,会打断原有的渲染Pass,而它原本应该能够直接衔接后面的Translucent(半透明物体渲染)阶段。

      如果把3S放到前面处理,也未必能获得更好的收益,像皮肤这样的模型可能还需要额外渲染一次。既然如此,我们就利用这个Pass被打断的机会,顺便完成一些其他工作,比如处理全屏光照的相关参数,以及前面需要预处理的内容。

      另外,相比PC端的原有管线,我们在这里也做了一些调整。传统PC管线会记录一个亮度比值,用来区分Diffuse和Specular,并在Filter过程中只处理Diffuse部分。如果只有Scatter(散射光照),这种方式其实没有太大问题。但在我们的游戏中,不管是皮肤还是眼睛,都可能存在自发光效果,这时候沿用原来的处理方式,就容易出现不稳定的情况。

      大家可以看一下这两张图。左边使用的是之前的方案,在加入自发光之后,最终颜色与设计师希望得到的效果出现了偏差;右边则是我们调整后的结果。正好我们在Lighting阶段已经使用了一个新的Pass,不再受到G-Buffer的限制,于是干脆把Diffuse和Specular拆开,额外占用一个RGB通道,换取更准确、更稳定的最终表现。

      图片

      接下来是皮肤上的水渍效果,我们也做了一些比较有意思的处理。

      大家可以想象一下,水珠或者水痕实际上是有体积的,它们的表面法线和皮肤本身并不相同。如果完全忽略这种差异,最终效果就会不够自然。但如果直接拿水珠的法线去修改皮肤的法线,又会影响皮肤原本的光照效果。比如左边这张图,看起来就不像水附着在皮肤表面,反而更像皮肤本身鼓起来了一块。

      图片

      所以,我们采用了两套法线,让水渍和皮肤分别计算自己的BRDF(双向反射分布函数,描述表面如何反射光线的数学模型),最后再把两部分结果叠加起来。这样既能保留皮肤原本的质感,也能表现出水珠、水痕附着在皮肤上的效果。同时,我们还使用Mask图(遮罩贴图)来控制水渍出现的位置和强度,方便美术和动画师在制作过程中实时调整。

      图片

      除了皮肤,眼睛也是角色渲染中非常重要的一部分。

      首先是虹膜的Diffuse,也就是虹膜的焦散效果。相比直接通过Power(幂函数)模拟高光,我们选择了一种更接近真实物理表现的焦散模拟方式,来还原光线在虹膜中的聚集效果。接着是角膜上的高光。这里我们使用了比较传统的GGX高光分布模型,并结合3S处理,让眼睛看起来更加水润,而不是过于干涩、生硬。最后,我们还对眼睛和周围皮肤之间的衔接进行了一些Blur(模糊)处理,使两者的过渡更加自然。

      图片
      图片图片图片图片图片

      讲完这些具体材质,下面再来看看Lighting和着色部分。

      前面提到,我们的角色材质比较复杂,往往需要组合多种Feature。比如各向异性材质可能还会叠加闪点效果,甚至再加上3S。当这些特性组合在一起时,着色的计算开销就会明显增加,G-Buffer也可能不够使用。

      针对这个问题,我们其实考虑过几种方案。一种是完全使用Deferred(延时渲染),另一种是Forward(前向渲染),还有一种则是两者结合,让复杂材质走Forward,普通材质继续使用Deferred。

      最终,我们还是优先选择了Deferred方案,对G-Buffer进行了定制化改造,同时对一些复杂特性进行编码压缩,尽可能控制G-Buffer的大小。

      但实际测试后我们发现,移动端的性能仍然存在瓶颈。相比传统PBR,我们加入了大量额外的材质特性。如果继续沿用PC端那种Uber Shader(将各种材质功能集中在一个大型着色器中,通过分支控制的方式),寄存器开销就会非常大,甚至影响整个计算过程的稳定性。

      因此,我们必须对Shader进行拆分。如果采用Forward渲染,这件事相对简单一些。因为在CPU端就已经知道每种材质需要使用哪些特性,可以直接绑定对应的Shader。但对于Deferred渲染来说,我们就需要使用其他方式,比如通过Stencil(模板缓冲)为不同材质打标记,或者采用分块计算的方式,将不同Shader拆分开来。

      我们最终选择的是Tile方案,也就是将屏幕划分成一个个小块,再根据每个区域实际需要的材质特性,选择对应的Shader。

      大家看这张图,绿色、粉色以及其他颜色,代表的就是不同Shader的分支。其中绿色标记的是带有闪点效果的材质。这样一来,我们就能更精细地控制每个Tile需要计算哪些内容。比如某个区域虽然使用了包含闪点特性的材质,但闪点强度实际上为零,那么这个Tile就可以选择不计算闪点的Shader,避免不必要的性能消耗。

      图片

      当然,这套方案也需要和设计师一起配合。毕竟材质效果并不是越多越好,我们还是要结合实际需求,找到效果和性能之间更合适的平衡点。

      接下来是Local Light的处理。如果场景里的灯光数量比较少,使用Light Volume(通过光源的包围几何体逐个计算光照的方式)其实是比较合适的。但如果需要大量打光,Light Volume的开销就会迅速增加。因为它不仅要考虑灯光数量,还要考虑不同材质类型的组合。

      此外,如果每个Shader在开始时都要读取一遍G-Buffer,同样会带来比较大的开销。因此,对于多光源场景,我们更倾向于采用Cluster(分簇光照:将视锥空间划分成多个区域,记录每个区域受到哪些灯光影响)的方式来处理。

      下面,我们正式进入阴影部分。

      首先是Local Light的阴影。《代号:神不言》使用了大量影视化灯光,所以场景中的灯光数量会比较多,相应的阴影数量也会增加。理论上有光就有影,为了保证最终画面的表现力,我们还是希望尽可能保留这些阴影,但这也意味着更大的运算压力。考虑到游戏中绝大部分场景是静态的,我们原本也可以选择将阴影直接Bake(烘焙)到Lightmap(光照贴图)中。

      不过,这样做会遇到两个问题。首先,动态角色无法正确接收这些预先烘焙的阴影。其次,Lightmap本身可能存在精度不足的问题,比如在压缩过程中,不同通道之间可能相互干扰,影响最终的阴影表现。

      所以,我们最终还是选择了Shadow Map(阴影贴图)的方案:静态物体的阴影提前Cache(缓存)起来,动态物体则单独渲染,再把两部分结果叠加。

      此外,如果采用Shadow Map,我们还会提前生成一份Screen Space Shadow,也就是Shadow Mask(屏幕空间阴影遮罩),在Lighting阶段直接使用计算好的阴影结果。这样就不需要在每次光照计算时,都重新进行复杂的阴影处理,从而提高计算资源的利用率。

      另外一个很重要的问题,就是控制阴影数量。如果同一个像素上叠加了太多层阴影,实际上很难从画面中看出明显区别,但计算开销却会不断增加。因此,我们目前将这个数量控制在4个,并结合Tile来管理阴影。

      具体来说,每个Tile只需要保存对当前区域有效的Shadow Map,并将参与计算的阴影数量控制在4个以内。这样一来,即使单个Tile受到限制,整个屏幕空间仍然可以同时显示超过4个阴影,也能为设计师提供更灵活的打光空间。

      当然,我们也和设计师一起制定了相应的规则,并开发了一些检查工具,方便他们在实际制作过程中控制阴影数量。

      图片

      下面再说一下点光源的阴影。

      在游戏中,我们绝大部分情况下都会优先使用Spotlight(聚光灯),因为它的性能开销通常比Point Light(向四面八方发光的点光源)更低。如果确实需要模拟Point Light,有时也可以通过两个Spotlight进行组合。

      但总有一些场景必须使用真正的点光源。这时候,我们就考虑采用四面体阴影,代替传统的Cubemap(立方体贴图)方案。传统Cubemap需要从六个方向生成阴影,而四面体方案只需要四个方向,因此能够节省一部分开销,效果也比双抛物面(Dual Paraboloid)方案更好。

      大家可以看这张图,我们通过四面体生成阴影,最后再将结果拼接到一张Texture2D(二维贴图)上。这样不仅更方便管理,如果后续有PS2D相关需求,处理起来也会比Cubemap更加灵活。

      图片

      接下来再聊聊阴影精度。

      这个问题对于《代号:神不言》尤其重要,因为游戏里存在大量角色特写镜头。在这些镜头中,角色身上的首饰或者其他细小物件,很容易因阴影精度不足而出现漏光。虽然可能只是一个不起眼的小问题,但放在特写镜头里,就会让画面显得不够精致。

      从根本上来说,玩家看到的主相机视角,与灯光生成阴影时使用的相机视角并不一致,两者之间总会存在一定的精度差异,因此很难找到一个完全没有瑕疵的解决方案。

      我们首先尝试了各种Bias(阴影偏移)方法,比如Constant Bias(固定偏移)、基于Slope(表面倾斜程度)的偏移,以及基于Normal(表面法线方向)的偏移。这些方案在不同情况下都有一定效果,能够改善漏光问题,但也都不是万能的。Bias调整得太大,可能出现漏光;调整得太小,又容易出现Shadow Acne(阴影粉刺,也就是表面出现不自然的条纹状自阴影)。

      因此,我们经常需要在这两种问题之间做取舍。当然,还有一些更复杂的方案,比如Receiver Plane Depth Bias(根据接收阴影表面的斜率自适应计算偏移),效果也不错,但性能开销会更高。所以Bias肯定还是需要的,不过想要进一步改善阴影质量,往往还需要配合更高分辨率的Shadow Map。

      说得简单一点,就是大力出奇迹。但Shadow Map的尺寸毕竟不能无限增加,因此,我们需要想办法提高现有阴影贴图的利用率。

      我们的思路是,尽可能把有限的阴影分辨率集中在当前画面真正需要的地方,必要时甚至可以牺牲一些边缘区域的阴影细节,优先保证画面主体的表现效果。举个例子,Spotlight的照射范围可能远远大于主相机的可见范围。如果按照常规方式生成Shadow Map,就需要把Spotlight范围内的所有物体都考虑进去。但其中很多物体,玩家实际上根本看不到。

      比如这张图,镜头里只出现了角色的一只手,但灯光的照射范围却覆盖了整个身体。如果按照完整范围分配Shadow Map,真正落到这只手上的像素可能非常有限,在特写镜头下自然就容易出现漏光。但如果我们把Shadow Map的有效范围集中到这只手上,就能明显提高当前画面的阴影精度。至于角色身上其他看不到的部分,也就没有必要浪费分辨率了。

      图片

      下面我们再来看Directional Light,也就是方向光的阴影。

      《代号:神不言》中有一个城市场景,而且支持Time of Day,也就是游戏内的昼夜时间变化,所以方向光的阴影处理会更加复杂。

      我们大致按照距离,将阴影分成两个部分。近处主要使用传统的CSM(Cascaded Shadow Maps,级联阴影),通过不同距离的阴影层级,兼顾近景精度和远景覆盖范围。这套方案既可以适应24小时的光照变化,也能够处理动态物体。如果角色本身的阴影精度仍然不够,我们还可以额外叠加Object Shadow,为单个物体生成更精细的阴影。

      为了减少不必要的Shadow Map开销,还需要配合各种剔除方案。除了最常见的Frustum Culling(视锥剔除),我们还会使用Shadow Caster Culling(投影物剔除)。简单来说,就是判断某个物体投射出的阴影,是否真的能被玩家看到。如果它产生的阴影完全不会出现在当前画面里,那我们就没有必要继续渲染它。

      图片

      这种方法尤其适合高楼林立的城市场景。比如玩家面前有一栋高楼,遮挡了后方的大量区域,那么这些区域中很多物体产生的阴影,其实都不需要继续计算。

      我们还可以进一步结合场景本身的特点进行优化。例如,在群山环绕的远景中,如果太阳处在日出或日落阶段,光照角度已经低于山峰的遮挡范围,那么就可以考虑直接关闭对应的方向光计算。因为这些光本来就无法照射到当前区域,继续计算也没有意义。

      至于中远距离的阴影,我们就需要更多地依赖Cache或者分帧计算了。毕竟城市场景本身就比较复杂,再加上昼夜变化,以及玩家可能随时转动镜头,如果所有阴影都实时更新,开销会非常大。

      图片

      但缓存也不是那么容易做的,因为镜头和光照条件都在变化,之前计算好的结果未必能一直使用。因此,我们采用了一种基于Tile的缓存方式。基本思路是将场景划分成多个区域,每个区域都有对应的Channel,每一帧只更新其中一个Tile,把原本集中的计算任务分散到不同帧中完成。

      同时,对于当前镜头没有看到的Tile,我们也会保留它们之前的缓存结果。这样,当玩家重新转动镜头时,就不一定需要从头计算。

      当然,缓存也会存在失效的情况。比如场景中的物体发生加载或卸载,或者LOD(Level of Detail,细节层级)发生变化,原有缓存就可能不再准确。但即使出现这种情况,我们也不一定要立即刷新全部内容,而是可以根据重要程度、权重等因素进行排序,优先更新对当前画面影响最大的区域。

      由于这套方案主要面向静态场景,因此动态物体通常需要排除在缓存之外。大家可以通过这张可视化图片,更直观地理解整个缓存系统的工作方式。

      图片

      这里还有一个问题:如果方向光的角度一直在变化,缓存又应该怎么处理?

      实际上,我们利用的是方向光不会在短时间内快速变化这一特点。比如在游戏的昼夜循环中,相邻两个时间段的方向光可能只旋转了1度或2度。这样,我们就可以提前预测下一个时间段的光照角度,并分帧计算、缓存对应的Shadow Map。等到游戏时间真正切换时,下一阶段需要的阴影数据其实已经准备好了。这样玩家就不会明显感觉到阴影随着时间变化,一块一块地突然跳动。

      当然,这个方案也有前提,就是时间变化不能太快。我们目前会为每个时间段预留十几秒的缓冲时间,让系统有机会提前完成计算。而在两个时间段真正切换的瞬间,我们还会对两份阴影结果进行融合,保证整个变化过程更加平滑。

      最后,我们再来聊一下GI和反射。

      首先是GI,也就是全局光照。如果希望角色拥有高质量的渲染效果,间接光照就非常重要,尤其是在影视化打光和角色特写镜头中。实际上,全局光照也是当前写实渲染中,移动端与PC端画面表现差距比较明显的部分。

      我们希望角色不仅能受到直接光源的影响,也能够呈现环境中更细腻的光照变化。比如,阴影区域内部依然可以有不同程度的遮蔽,也就是通过高质量的AO(Ambient Occlusion,环境光遮蔽)体现缝隙和接触区域的明暗变化;同时,还要表现光线经过物体反弹后产生的微妙照明效果。

      大家可以看这张图,角色下巴附近就能够接收到反弹的光照,让整个画面更加自然。

      图片

      为了尽可能接近PC端的效果,我们在移动端依然采用了Lumen(UE5的动态全局光照与反射系统)。不过,完整的Lumen对于移动端来说还是过于昂贵,至少在目前这个阶段,直接把PC端的全部功能搬过来,很难保证性能。

      因此,我们必须针对移动端做一些简化和调整。

      首先是光照更新。因为我们的很多场景和灯光本身都是静态的,所以可以提前Bake好相关的输入源等信息,在游戏运行时直接使用,减少实时计算的开销。

      同时,我们希望CutScene(过场动画)能够拥有更好的GI效果,因此更倾向于采用高质量的Final Gather(最终聚集,从周围环境收集间接光照的过程)。

      这里涉及Screen Probe Gather,也就是在屏幕空间中分布一定数量的Probe(探针),再为每个探针分配一些射线,用来收集周围环境中的Radiance(辐射亮度)。

      在射线追踪这一部分,我们主要保留了SSGI(屏幕空间全局光照)和远距离兜底使用的Probe Irradiance(探针预先记录的辐照度),放弃了中距离的SDF Tracing(利用有向距离场进行射线追踪)等计算。这样能够减少一部分开销,但即使经过这些调整,整个GI系统的消耗仍然不低。

      因此,我们还是选择把高质量GI主要集中在角色身上。对于普通场景,则继续采用传统方案,或者使用Probe Volume(在空间中布置光照探针的方式)来处理。

      当然,这样做也会带来新的问题。因为角色和场景使用了不同的光照计算方式,两者的衔接区域有时可能会显得不够自然。如果这种差异比较明显,我们就可以通过Capsule Shadow(胶囊体阴影)等方式进行补充,让角色和周围环境更好地融合。

      在Sequence(UE的过场动画编辑与播放系统)中,我们同样会使用这些方案。而且,为了追求更好的演出效果,灯光师还可能针对每个剧情镜头单独设计打光,这就意味着我们需要准备多份不同的光照数据。

      图片

      大家可以看一下实际效果。左边是之前使用Probe的方案,右边则是我们调整后的Screen Probe方案。

      图片

      在角色手臂与扶手接触的地方,可以明显看到GI和AO带来的变化。通过更加自然的间接光照与遮蔽效果,手臂看起来能够更好地融入周围环境。

      另一张对比图也是类似的道理。采用新方案后,身体上的光照可以反弹到脖子上,带来更自然的照明效果。与此同时,衣领附近的AO也更加明显,让接触区域的层次感更强。

      图片

      最后,我们再介绍一下反射部分。

      因为《代号:神不言》采用的是现代都市背景,而且整体偏写实,所以反射效果在画面中非常重要。和古代场景或者以岩石、土地为主的旷野环境相比,现代都市中会有更多Glossy材质,也就是那些带有光泽、能够形成模糊倒影的表面,比如金属、漆面等等。尤其是在地面、墙面这样的大面积平面上,反射是否正确,其实很容易被玩家察觉。

      图片

      不过,从某种程度上来说,我们优化反射,并不完全是为了让倒影更漂亮,反而更多是为了解决反射带来的漏光问题。因为这类错误一旦出现,往往会非常明显。虽然可以利用更高密度的GI信息来校正Reflection Capture(反射捕获探针),但也很难彻底避免所有问题。于是我们整体还是沿用了UE的反射处理思路:先在屏幕空间进行Trace(射线追踪),如果没有命中,再转向世界空间继续追踪。

      在世界空间中,我们使用了硬件光追,因为它能够更准确地找到反射位置,最终效果也更好。尤其当反射本身就是画面主体时,这种准确性就显得非常重要。

      当然,移动端的光追性能仍然有限,所以我们不会直接用它来承担完整的实时反射计算,而是更多地借助光追找到正确的位置,再去采样预先捕获的反射数据。如果这种方式仍然无法得到正确结果,我们才会在射线击中点重新计算光照。

      同时,我们也支持Glossy反射,而不只是纯镜面反射,因此在得到光追结果后,还需要进行Denoise(降噪)处理。

      下面我具体解释一下这套反射方案。我们主要采用的是一种Pre-capture(预先捕获)的思路。大家看这张示意图,紫色部分是场景表面,蓝色代表主视角和反射光线。

      在这种情况下,反射光线已经超出了SSR(Screen Space Reflection,屏幕空间反射)的有效范围,因为SSR只能利用当前屏幕上已有的信息。如果我们提前通过Cubemap捕获了环境反射,比如图中绿色的小球,那么最简单的处理方式,就是直接使用这张Cubemap来补充SSR没有命中的区域。

      但这里有一个问题。如果按照传统方式,直接根据反射光线的方向去采样Cubemap,得到的其实是图中的绿色虚线方向,结果可能完全不正确。我们真正需要采样的,是绿色实线所对应的方向。

      有了光追之后,解决这个问题就简单多了。我们可以通过Ray Tracing找到光线真正的Hit Point(击中点),再用这个位置减去反射球的位置,得到正确的采样方向。这就是我们利用Ray Tracing辅助采样反射球的基本思路。

      这种方式有一个很大的好处:我们不需要实时计算反射位置的Radiance,只需要从预先准备好的Cubemap中进行采样,因此对性能比较友好。

      当然,我们还希望进一步减少光追本身的开销。比如在生成用于光追的场景结构时,我们会使用简化后的低面数模型。大家看图中橙色的虚线,就是相应的简化版本。在某些情况下,甚至直接使用一个平面来代替复杂几何体,也不会带来特别明显的差异。因为最精细的Contact反射,也就是物体与表面靠近时的局部反射,基本已经由SSR负责处理了。

      不过,这套方案同样不可能覆盖所有情况。首先是动态物体,比如角色,它们本身就很难完全依靠预先捕获的反射数据处理;其次,反射球也不可能捕获到场景中的所有信息,它的结果会受到放置位置的影响。

      举个例子,如果反射球和真正需要反射的位置之间存在障碍物,那么反射球捕获到的,可能是障碍物背面的信息,而不是我们希望得到的实际反射内容。

      在这种情况下,继续使用Cubemap就会出现错误。我们只能回到光追的Hit Point,在真正的击中位置实时计算高光效果。

      考虑到移动端的性能限制,这个过程也不能完全照搬传统光栅化的计算流程。我们需要对贴图读取、采样等环节进行适当简化,尽可能提升计算效率。对于非纯镜面的Glossy反射来说,一些细微的计算误差其实并不容易被察觉,因此在保证整体效果的前提下,我们也能够接受一定程度的近似处理。

      图片

      最后,大家可以再看一下这套方案的实际效果。

      在这张可视化图片中,蓝色代表SSR成功命中的区域;绿色代表SSR没有命中,但可以通过Ray Tracing辅助采样Cubemap解决的区域;红色则代表前面两种方式都无法正确处理,需要最终进行实时计算的区域。如果完全使用Cubemap,大家可以看到,在琴键与地面的衔接处,会存在比较明显的反射漏光。

      图片

      加入SSR之后,这部分漏光有所减少,但依然存在大量SSR无法覆盖的区域。因此,我们才需要把SSR、Ray Tracing辅助采样Cubemap,以及必要时的实时光照计算结合起来,在移动端有限的性能条件下,尽可能获得更加准确、自然的反射效果。

      图片图片图片

      以上就是我今天要分享的全部内容,谢谢大家。

      图片
      图片
      图片
      图片

      游戏葡萄招聘内容编辑,

      点击「阅读原文」可了解详情


      点击下方名片,关注公众号

      (星标可第一时间收到推送和完整封面)

      前往微信阅读全文

      内容来自公众号,可前往微信查看原文。

      查看作者的更多文章 →订阅更新、RSS 与阅读指南 →