揭秘ADAM | 光照的使用技巧和经验
我们对Oats Studios开发的《ADAM》项目,已经揭秘了 Timeline的运用、服装设计与布料模拟、Alembic导入。今天将分享来自Made with Unity团队中的高级技术美术Jean-Philippe Leroux的文章《ADAM中的光照的使用技巧和经验》。Jean-Philippe在ADAM项目中负责为Oats Studios的灯光师提供支持,帮助他们实现令人惊叹的实时效果。
在ADAM中基础设置-光照基础
Unity支持非常多的平台,这同时也意味着会有许多的光照工作流程可供选择。开始Oats团队将Color Space(色彩空间)设置为Linear。这是我们在设置一个新项目时首先要做的事情,因为它对于光照计算至关重要。唯一不使用这个色彩空间的理由是:如果你的目标平台是低端设备,无法支持此功能。
然后将Rendering Path(渲染路径)设置为Deferred。这不仅可以允许使用一些诸如屏幕空间反射这样的酷炫渲染技术,它还通过取消灯光数量限制,大大简化了光照工作流程,因为大部分的灯光拥有巨大的几何体积。
对于Tonemapping(色调映射),Oats团队选择的是Unity的Post-Processing Stack中的ACES。ACES是电视和电影产业作为所有图像源的基础而推出的标准。它提供了一种很重要的自然对比,那是现代电视蓬勃发展的基础之一,而且它还正确保留了白色避免被剪裁。
由于ADAM电影的很大部分是在“人化”角色,因此色调映射是视觉发展(通过光照、着色器等将情感表现到角色上的艺术)中关键步骤。此外色调映射实际上还会决定你将如何照明和曝光你的镜头。
《ADAM 3》中场景
全局光照GI
预计算实时全局光照是ADAM项目的一个关键性选择。它提供了合理的光线反弹计算,因为所有的镜头都为角色使用了动态灯光,而且太阳的位置在每个镜头都有调整。太阳和动态灯光一起为提供了所需的间接光照输入。
在ADAM项目中,关于Unity实时全局光照解决方案要注意的一点是:只有方向光的阴影是被支持的。所有其它光源的阴影都不在计算范围中,所以它们会穿过每个物体和墙壁。因此我们需要想个办法让《ADAM 2 》房间中包含明亮灯光所生成的全局光照。
Oats团队使用了一个简单的技巧来达成这个目的。他们使用在摄像机视图中被剔除的发光平面提供全局光照效果,而不会将光线漏到房间之外。
摄像机剔除的发光平面在房间中的布置
在《ADMA 2》的房间中使用发光平面解决动态全局光照问题
Perforce配置问题
在开发中,当Oats开始将全局光照的更新版本推送到他们的Perforce服务器时出现了一个问题:团队中的所有人都丢失了全局光照,并收到错误消息。
经过排查,最后发现是默认的Perforce配置导致了一个意外问题。因为LightingData.asset虽然是二进制文件,但Perforce服务器默认将它们视为文本文件,所以在整合时使它们产生了损坏。为了使一切回到正轨,我们立刻更正了已配置的文件类型,添加.asset,重新生成全局光照,确保文件被作为二进制提交,因为它们已经以文本文件形式存在于仓库中了。
处理新的太阳位置
我们注意到的另一个问题是,每次太阳位置改变后都会出现突变。像制作普通电影一样,Oats团队也为每个摄像机镜头设计光照。这意味着一个镜头一个镜头的更改太阳位置,将需要进行一次完全的实时全局光照更新。不幸的是,即便将实时全局光照的CPU使用率设置为Unlimited(无限),更新也不会在新镜头的第一帧就准备好,导致每次太阳位置的改变都会产生一次明显的突然变化。
为了应对这个问题,我们想出了一个临时解决方案:在上面的Timeline Director中,我们为每个镜头逐一添加一个二帧长度的缓冲区,这个缓冲区没有被Frame Recorder输出。现在Unity 2017.2可在Frame Recorder中使用DynamicGI.IsConverged命令,自动处理此问题。
添加二帧长度的缓冲区
处理Alembic缓存
“现在Unity已添加了对Alembic的支持,它是个非常的桥梁。我们需要它来缓存巨大的几何数据集。”Oats Studios的特效总监Chris Harvey表示。
我们用于布料与面部模拟的Alembic缓存实际上就是网格。在ADAM中,它们位于世界原点,并据此计算全局光照探头。为了保证所有的东西都能被正确处理,Oats将“Anchor Override”渲染器探头设置到了角色的骨盆上。如此一来,探头将会基于角色在布景中的位置进行正确计算,而不是根据缓存的轴心点。
设置Anchor Override
使用Dynamic Decals资源包
在《ADAM 3》中,注意观察那些很酷的涂鸦,鹅卵石,灰尘和其它细节。Oats团队从Dynamic Decals资源包里拿了不少东西来实现它们。但是在使用实时全局光照时,效果并不是很理想,因为贴图无法被正确照亮,在阴影中显得非常暗。
在延迟渲染中,全局光照被解析之前,这些效果会在处理反射时写入到缓冲区。当我们使用天空盒作为环境光时就会出现问题。如果你使用的是渐变或颜色,你不会遇见这个问题。我们使用解决方案是:使用一个Lambert球以及一个DecalAmbient着色器球,编写它自己的Ambient Override,并对值进行调整直到尽可能匹配。
自定义Decal Ambient Override vs 一个Lambert球
阴影
你可能知道的,阴影对于表现光的质量非常重要。而且说实话,这个领域在过去十年内一直没有显著的功能性大突破。不过,ADAM中的光照质量源于对现有技术的深入理解和掌握。
首先普及一点背景知识:所有的灯光都应该投射阴影,而且应该都是完全不透明的。但许多开发者会使用阴影透明度,以为它会填充阴影区域,但实际上它会破坏光照的连续性,因为光照仍然是有方向的,背面不会受光。看看下图中Oats团队是如何使用全局光照来填充阴影区域的,减少了对阴影透明度的需求,获得了很好的效果。
注意阴影强度在 0.8和 1之间的区别
Oats团队还通过对聚光灯阴影过滤进行了一个简单的修改,大大提升了阴影质量。他们重写内部延迟着色,将PCF过滤提高到7x7的分辨率。如果你想尝试这个技巧,要注意:它仅适用于聚光灯,点光源阴影不会因此得到改善。
Oats团队利用到的另一个Unity 2017.1特性是为每个光源自定义阴影分辨率,你可以在检视窗口的Debug选项卡上找到它。分辨率必须是2的幂次方,最高不能超过8k。
如果你打算尝试这个功能,那在使用高分辨率阴影贴图时要小心。更高的分辨率不一定就等于更好的质量。分辨率越高,阴影就会越清晰,但这通常不会是你想要的效果,因为那背离了使用高质量区域光的初衷。永远记住,灯光质量等于柔和的阴影和扩散的镜面反射。下图中可以看到ADAM中不同设置下的阴影分辨率和过滤之间的区别。
阴影分辨率 vs 过滤的影响:默认PCF 3x3(左)和PCF 7x7(右)
使阴影偏移正常
正确设置阴影偏移非常关键,他们想让阴影连接到一起,但又不会产生阴影瑕疵。在Unity中,聚光灯阴影偏移与剪裁平面的值紧密相关。要确保连接的完美,需要将其尽量接近主体。用于角色照明的起始值差不多是二个单位。下图是展示效果。
合适的阴影偏移设置(0.005,0.1,5) vs 默认偏移设置(0.05,0.4,0.2)
设置级联
定向光的级联分布设置也需要逐个镜头进行修改,Oats团队使用了一条Timeline自定义轨道。他们还使用了 SE Screen-Space Shadows资源包,使阴影质量进一步得到了提升。将它与Cascade Shadow Map (CSM)一起结合使用后,他们获得了完美的接触阴影,那是再好的偏移设置也无法达到的效果。
《ADAM 3》中场景 -没有 Screen-Space阴影
使用Timeline做逐个镜头的照明
一旦确认了一个序列的光照视觉发展后,Oats团队将它在Timeline中分开,以便能按镜头进行调整。基本上,他们就是为每个镜头复制视觉发展中所做的光照布置,然后通过Timeline进行激活。
由于使用了基础的Switch Active轨道会过度填充Timeline,Oats团队创建了一个自定义Switch Active Asset剪辑,使他们可以在同一个轨道上为每个剪辑一次激活二组灯光。这使得一切清爽而简单。
自定义Switch Active Asset设置
将每个镜头的光照进行单独组织,免去在对某个镜头进行小调整时影响其它镜头的风险。如果你打算尝试这种做法,强烈建议你采用一种遵循镜头号码和组序的简洁命名规范。正如我们所发现的,这将大大提升你的效率,并能帮助其他与你一起工作的人。
Timeline中一条被逐个镜头分解后的序列
完美控制精准光源(Punctual Light)
在制作早期,Oats团队表达了对精准光源进行更好控制的需求。具体的说,他们希望控制光源的强度衰减和扩散。Made with Unity的软件工程师John Parsaie为他们创建了一个可以利用剪影(Cookie)栏的资源。这提供了二个可以进行曲线化控制的参数和一个平滑钳制的参数。更酷的事情是,所有灯光仍然能够对全局光照和反射产生影响。
自定义脚本:控制传播距离衰减(Attenuation)和强度衰减(Falloff)
添加闪烁的灯光
为了让ADAM中的火焰和闪光更加动态真实,我们还创建了一个脚本,可进行灯光位置、强度和色调的调节。这个脚本使这些组合的视觉效果更加逼真。将它附加到一个空对象,它会向下传递给所有灯光和特效子对象。
Light Fire Flicker:Oats用于位置设置、强度和色度调节的脚本
效果在场景视图中也可以见,这在进行视觉开发时非常有用。不过,我们在使用中碰到了一点小问题:它一开始会阻止立方体贴图和全局光照烘焙的完成。当发现到脚本是问题的根源后,我们在烘焙时用了另一个命令禁用所有的闪烁脚本。
烟与火
《ADAM 2》开场时,一系列令人印象深刻的熊熊火焰为场景增添了许多戏剧性和紧张感。那些囚犯在穿越黑暗的死寂之地时,是否会屈服于那“炽热”。许多人渴望了解怎样做出如此精彩的效果。据Oats团队的工作人员Stephen Cooney说,他们结合了许多很酷的业内技巧,并且做了很多分层。
燃亮夜空:《ADAM 2》的开场
我们对大多数的火焰元素使用了动画纹理图集。我们用Houdini生成了一部分,还用到了一些库存的Unity纹理图集。火焰在纹理中被视作“热量”,然后在着色器中重新映射为任意强度,并使用一条功率曲线进行分级。
(左)Houdini中制作的循环地面火焰 (右)每帧火焰流动贴图
我们将这与一个平铺的火焰纹理结合,增加一些额外的飞扬尘埃。当最终的“热量”计算出来后,会被重新映射到冷热二种颜色之间。我们使用光学流动贴图来进行帧与帧之间的平滑。这对于只有几帧长度的大烟柱火焰贴图非常有用。
小型火焰组成了非常长(但分辨率更小)的纹理图集,而烟柱部分是一个帧数很低,但分辨率很高的爆炸形状(流动贴图使这变得很容易)。
一个用于表现烟柱(红色热量,绿色光照)的爆炸纹理以及它的流动贴图
外观的主要部分是我们通过手动调整视觉顺序完成的。而且,由于火焰被视作“热量”,然后被重新映射到实际的值(细节纹理覆盖其上),这使得更容易获得在视觉上有吸引力的亮度。这些用Unity的Post-Processing就可以完成,无需重新考虑纹理。
粒子光照系统,使粒子看起来会发光,这对烟雾效果有用,帮助我们将不同的粒子系统整合到一起。由于光源可以动画化,因此烟雾的亮度也会随之而动,地面也会获得同样的亮度。我们还这个应用于闪光,以“照亮”烟雾。基本上,它让我们可以将发光粒子系统以某种方式与自定义漫反射系统相连接。
反乌托邦式的营火: 囚犯们听着 Needalus 解释他们的来历
最终感想
与Oats Studios这样一支技艺精湛的团队紧密合作,给我们带来了不少经验。Oats Studios团队中的灯光与图形专家们使用我们现成的游戏引擎创造着栩栩如生的CG短片。在这个项目的过程中,Oats Studios证明了Unity不仅具备制作出色电影质量效果的一切条件,同时还减少了迭代次数和成本开销。我们学到了很多,看到他们不断地扩展特效和叙事的可能性边界,以及所需的一切想象力和辛勤工作。
最后Oats的CG总监Abhishek Joshi表示:在Unity中进行实时照明,对我们来说是个创造性的巨大飞跃。源于离线光线追踪渲染,速度和交互性让我们可以获得在非实时工作流程中从未有过的创意自由与迭代速度。这是动画内容创作的未来。
文章资源
Dynamic Decals
https://www.assetstore.unity3d.com/en/#!/content/76410
Post-Processing Stack
https://www.assetstore.unity3d.com/en/#!/content/83912
SE Screen-Space Shadows
https://www.assetstore.unity3d.com/en/#!/content/77836
GI
https://unity3d.com/cn/learn/tutorials/topics/graphics/introduction-precomputed-realtime-gi
小结
ADMA系列揭秘就到此告一段落了,我们希望《ADMA》项目中所积累的技巧与经验能对未来使用Unity创作实时电影和动画的团队产生帮助。更多精彩内容尽在Unity官方论坛(unitychina.cn)!
揭秘ADAM系列文章
ADAM揭秘 | Unity Alembic导入工具的开发历程
官方活动
时间:1月26日 (明天)
时间:2018年1月14日
地址:https://www.bagevent.com/event/1031633
点击“阅读原文”访问Unity官方社区!