在一些 2D 游戏中引入实时光影效果能给游戏带来非常大的视觉效果提升,亦或是利用 2D 光影实现视线遮挡机制。例如 Terraria, Starbound。
2D 光影效果需要一个动态光照系统实现, 而通常游戏引擎所提供的实时光照系统仅限于 3D 场景,要实现图中效果的 2D 光影需要额外设计适用于 2D 场景的光照系统。虽然在 Unity Assets Store 上有不少 2D 光照系统插件,实际上实现一个 2D 光照系统并不复杂, 并且可以借此机会熟悉 Unity 渲染管线开发。
本文将介绍通过 Command Buffer 扩展 Unity Built-in Render Pipeline 实现一个简单的 2D 光照系统。所涉及到的前置技术栈包括 Unity, C#, render pipeline, shader programming 等。本文仅包含核心部分的部分代码,完整代码可以在我的 GitHub 上找到:
SardineFish/Unity2DLightinggithub.com2D Lighting Model
首先我们尝试仿照 3D 场景中的光照模型,对 2D 光照进行理论建模。
在现实世界中,我们通过肉眼所观测到的视觉图像,来自于光源产生的光,经过物体表面反射,通过晶状体、瞳孔等眼球光学结构,投射在视网膜上导致视觉细胞产生神经冲动,传递到大脑中形成。而在照片摄影中,则是经过镜头后投射在感光元件上成像并转换为数字图像数据。而在图形渲染中,通常通过模拟该过程,计算摄像机所接收到的来自物体反射的光,从而渲染出图像。
1986年,James T. Kajiya 在论文 THE RENDERING EQUATION [1] 中提出了一个著名的渲染方程:
3D 场景中物体表面任意一面元所受光照,等于来自所有方向的光线辐射度的总和。这些光经过反射和散射后,其中一部分射向摄像机(观察方向)。(通常为了简化这一过程,我们可以假定这些光线全部射向摄像机)
而在 2D 平面场景中,我们可以认为,该平面上任意一点所受的光照,等于来自所有方向的光线辐射度的总和,其中的一部分射向摄像机,为了简化,我们认为这些光线全部进入摄像机。这一光照模型可以用以下方程描述:
即,平面上任意一点,或者说一个像素 (x, y) 的颜色,等于在该点处来自 [0, 2π] 所有方向的光的总和。其中 Light(x, y, θ) 表示在点 (x, y) 处来自 θ 方向的光量。
该方程来自 @Milo Yip 的一篇文章:
Milo Yip:用 C 语言画光(一):基础zhuanlan.zhihu.com