动画编辑器一直缺一盏会动的灯
在游戏引擎里挪一下灯,所有影子跟着走;在动画编辑器里挪灯,影子得你一张张重画。
灯要动起来的那个镜头
做过动画的人都碰到过这种镜头:吊灯在饭桌上方晃,车灯扫过卧室的天花板,人物在窗前等着,太阳慢慢落下去。画已经画完,节奏也对了,偏偏这时光要走,而光是画在画里的。于是只能在每张关键姿势上重画一遍暗部,或者拿渐变和遮罩拼出光影,一帧帧手动调,再祈祷中间画别穿帮。
游戏引擎里没人重画。灯一挪,引擎每一帧都会算出每个表面朝哪边、它和灯之间隔着什么。差别就在这里:动画和合成软件把光当成画出来的、或者拍进素材里的东西;游戏引擎和三维软件则把光算出来。这两套做法各自存在了几十年,却从没在同一个动画编辑器里碰过头。
它们分开是有道理的,只是多半是成本上的道理,不是审美上的。成本已经变了。Keyframe 现在把一盏算出来的灯放进了一个 After Effects 式的编辑器,而且是可选的:它像位置一样能打关键帧,之后留着、改掉还是关掉,由你决定。
光是画的、拍的,还是算的
手绘动画里,光是画出来的。影子的形状和高光画在每一张画上,常常单独占一层色阶;它们会动,是因为有人一张张把它画得在动。合成里,光跟着素材一起来:片子在现场已经打好了光,合成师要做的,是让每个新加进去的元素看上去也站在同一盏灯下。
动画与合成
- 画出来影子的形状画在每一张画上
- 拍进去素材自带拍摄现场的光
- 手动挪遮罩和渐变,一个个打关键帧
游戏引擎与三维
- 灯能摆放、能做动画的对象
- 表面每一点都知道自己朝哪边
- 影子每一帧按挡光的东西算出来
游戏引擎从另一头做起。灯是一个对象,有位置、颜色和衰减;表面带着自己的朝向,来自几何体,或者来自法线图——一张按像素记录朝向的图;影子则每一帧根据挡在灯前的东西算出来。
2D 游戏把同一套机制用在平面画上。Unity 的 2D 灯光 (外部网站,在新标签页打开)、Godot 的 2D 灯光 (外部网站,在新标签页打开),以及 Spine 为 Unity 提供的精灵着色器 (外部网站,在新标签页打开),都能借一张为它准备的法线图给平面画打光。可围绕画稿和素材建起来的动画编辑器,一直没把这套东西接进来。
在画里,光是一种选择
第一个原因是合成用不着。素材本来就带着光,真要重新布光,就得回到三维里把场景重建一遍。给素材重新打光的工具不是没有,比如 DaVinci Resolve 的 Relight 效果 (外部网站,在新标签页打开),它按画面里感知到的深度生成一张表面图,让虚拟灯光能落在上面。但在合成里,和底片对不上的光通常是要修掉的错,而不是拿来做动画的效果。
第二个原因更根本:手绘动画里,物理是画师的参考,不是裁判。脸被正上方的光照着,鼻子底下照样不画影子,因为那块影子看起来像脏了。房间里身后明明没有窗,人物边上还是勾着一圈轮廓光。人物一低落,整个画面就转冷,屋里的东西却一样没变。赛璐珞上色把这一切归成两三个平涂色阶,放在最好看的位置。手绘的脸也很少是一个前后一致的三维形体:鼻子、眼睛、下巴各自按看起来最顺的角度画,没有哪个打了光的模型会长成那样。
最有力的证据,来自那些想让三维看起来像手绘的人。做 Guilty Gear Xrd (外部网站,在新标签页打开) 时,Arc System Works 用三维模型做角色,再把模型上每个主要部位的法线都手工改过,好让影子落在动画师会画的位置,而不是几何体算出来的位置。一旦目标是手绘的样子,连游戏引擎的物理也得被掰弯来迁就。
所以,一个只按光学定律给每一层打光的动画编辑器,是在和用它的人作对。这个反对意见是对的,它也决定了算出来的光该以什么方式出现:由你选来用,而不是不由分说地发生在你的画上。
缺的那几块,以前太贵
另外两个原因是技术上的。要让一张画像有体积那样受光,就得知道画上每一处朝哪边:要么有法线图,要么有能推出法线的深度图。游戏的法线图要么从三维模型烘焙,要么由人手画。专门干这件事的 Sprite Lamp (外部网站,在新标签页打开),要画两到五张同一画面的灰度明暗稿,每张假设光从一个方向来,再由它合成法线图。游戏里的精灵画一次用好几年,这笔账算得过来;动画师的下一个镜头就算不过来了。
最后一块是画自己给自己投影:帽檐在额头上投下一道影,围巾在下巴上投下一道影。这是实时渲染的技术,不是图层效果。渲染器对每个像素沿着高度场朝灯的方向一步步走,看中间有没有更高的东西挡着,游戏里的 视差遮蔽贴图加软阴影 (外部网站,在新标签页打开) 就是这么做的。这需要一个知道灯在哪里、知道每个像素有多高的渲染器,而一叠图层加效果链里没有这样的东西。
- 2006游戏实时画出表面起伏投在自身上的影子
- 2015Guilty Gear Xrd 掰弯三维法线,让它像手绘
- 2024Depth Anything 从一张图读出深度
- 2026这些合进一个浏览器里的动画编辑器
变的是第一块。从单张图估深度的模型研究了很多年,但直到最近才好用、快到能放进日常工作里;2024 年发表的 Depth Anything (外部网站,在新标签页打开) 就是其中之一。一张以前要细细手画几个小时法线的图,现在几秒钟就有一个能用的表面。再加上浏览器里有了显卡渲染器,游戏引擎的那盏灯终于装得进动画编辑器了。
把游戏引擎的灯装进动画编辑器
Keyframe 在浏览器里把这几块拼到一起。深度模型在你自己的设备上运行,渲染器通过 WebGPU 跑在你的显卡上。预览和导出用的是同一个渲染器,拖时间线时看到的光,就是导出来的光。
它的灯就是编辑器里普通的 灯光图层 (在新标签页打开):点光、聚光、平行光、环境光和环境贴图光,和摄像机在同一个三维空间里,在同一条时间轴上打关键帧。把图片图层设为 3D、前后错开、打开投影,每一层都会把自己的轮廓投到后面的层上,透明的地方光会透过去。对纸雕场景来说这在物理上就是准的,因为这些图层本来就是一张张平的纸。
单独一张画,则靠它的 受光表面 (在新标签页打开) 得到起伏。由深度生成 在你的设备上把画面估出的深度变成法线图,于是每个像素都会转向灯或背着灯。自身投影 让这些起伏给自己投影,画面细节起伏 再把画面本身细小的明暗当成起伏补上,毛线的纹路、彩铅的笔触这种模型看不出来的细节也能受光。
从编辑器导出,未做后期。法线图由 Agent 生成,灯也是它摆的,会动的那盏也由它打的关键帧。
这段片子的起点是下面第一张图,画的时候特意不带任何光。编辑器里的 Agent 为它生成了法线图,摆了一盏暖色主光和一盏很弱的环境光,再给主光的路线打了关键帧。Agent 用力过猛的地方,我们像改助手的活儿那样手动改了回来。
- 原画

- 光在她左边

- 光在正面

- 光在她右边

你不要,它就不开
这些都不会自己打开。合成里没有灯时,图层就是它原本的样子;图层的表面默认是平的,自身投影 和 画面细节起伏 都是 0%。要不要用,一层一层由你开;生成的法线图,撤销一次就收回。
开了之后,算出来的光也只是个起点。好看的地方留着,不好看的地方打关键帧把它挪到更好的位置,只有手画的影子才行的地方,就在上面画。它也能和画里原有的光放在一起:一层上是手画的轮廓光,整个场景上是算出来的主光,同在一个合成里。光是时间轴上的一个属性,不是一纸判决。
算出来的光还会出错的地方
渲染器里头,物理仍然是裁判,推翻它的工具还没有。影子没有自己的颜色,只有深浅和软硬;没有把光分成赛璐珞那样两三个平涂色阶的设置;除非把一个图层的接收阴影整个关掉,否则没法让某一道影子别落在某一张脸上。眼下只能用遮罩、混合模式和叠在上面的手绘图层绕过去。
没有光线追踪,也没有全局光照。红墙上的光不会反弹到白衬衫上;每盏灯直接照到表面,其余一概由环境光代替。
自身投影短,而且可能很硬。它朝灯的方向只看法线图长边的四分之一,所以横过整张脸的长影子会被截短。起伏的高度是从法线积分出来的,起伏调得很高、光又贴着表面扫过时,误差积累的地方会留下一道硬边。上面这段片子里,Agent 一开始把起伏调得太高,光一到侧面,半张脸都被一块边缘生硬的黑影盖住,最后是我们手动调回来的。
还有,画里已经画了光的图,会和新灯打架。一张光从左边来的肖像,你的灯移到右边,她的左脸照样亮着,画上去的明暗也会被读成起伏。这个小女孩是特意画成不带光的,大多数画不是。
一盏能打关键帧的灯
重点不是让物理取代画师。该画的光,还是画出来。重点是光终于也成了一样能做动画的东西:定好从哪里开始、到哪里结束,中间让影子自己跟上,然后再决定留下哪些。位置、旋转和颜色,从有关键帧那天起动画师就能这么做;缺的一直是光。
