2D 灯光和阴影
前言
本教程以 灯与影 演示项目解释了2D灯光的工作原理. 本节首先简要介绍了最终demo所使用的资源, 然后介绍了如何逐步实现类似demo的场景.
本教程的所有资源都可以在 GitHub 上的官方演示仓库中找到。我建议您在开始之前下载。或者也可以在项目管理器中下载。在启动 Godot 时在顶部栏中选择“模板”选项卡并搜索“2D Lights and Shadows Demo”。
场景布置
对于这个演示, 我们使用四种纹理: 两种用于灯光, 一种用于那些会产生阴影的物品, 一种用于背景. 如果想单独下载它们, 我在这里列出了所有链接.
第一个是演示中使用的背景图像( bg.png ). 你不一定需要背景, 但我们还是在演示中用了一个.
第二个是用作影子的纯黑色图片 (caster.png ) . 对跳跃游戏, 它可能是墙或任何其他投射阴影的物体.
接下来是灯本身 (light.png ) . 如果单击该链接, 您会注意到它有多大. 用于灯光的图像应覆盖您希望灯光覆盖的区域. 此图像为1024x1024像素, 因此您应该使用它来覆盖游戏中的1024x1024像素.
最后, 我们有聚光灯图像 (spot.png ) . 该演示使用灯泡来显示灯光的位置, 使用较大的灯光图片来显示灯光对场景其余部分的影响.
节点
该演示使用了四个不同类型的节点:
CanvasModulate 用于使场景变暗。
Sprites 用于显示灯泡、背景和产生阴影的物体的纹理。
Light2Ds 用于点亮场景. 光通常的工作方式是在场景的其余部分添加选定的纹理以模拟光照. 但它可以以其他方式使用, 例如屏蔽部分场景.
LightOccluder2Ds 用于告诉着色器, 场景的哪些部分投射阴影. 阴影仅出现在 Light2D 所覆盖的区域, 它们的方向基于 Light 的中心.
灯光
Lights 覆盖各自纹理的整个范围. 它们使用Additive Blending将其纹理颜色添加到场景中.
Lights 有四个 模式
: add
, sub
, mix
, 和 mask
.
Add
将光纹理的颜色添加到场景中. 它会照亮灯光下的区域.
Sub
从场景中减去光的颜色. 它使灯光下的区域变暗.
Mix
混合了灯光的颜色和底层场景. 产生的亮度介于灯光颜色和下方颜色之间.
Mask
用于遮盖灯光覆盖的区域. 根据光的颜色隐藏或显示遮盖区域.
对于这个demo, 灯光有两个组件, Light 本身(这是灯光的效果), 和 Sprite 灯泡(一个显示光源位置的图片). 子节点 Sprite 不是让 Light 工作的必要条件.
阴影
阴影是通过让 Light 与 LightOccluder2D 的范围相交来制作的.
默认情况下, 阴影处于关闭状态. 要打开它们, 请单击 Light 并在Shadows部分下面选中 启用
.
在演示中我们使用带有纹理的 Sprite 来制作 “投射影子的物体”, 但实际上您只需要几个 LightOccluder2Ds . LightOccluder2D 本身看起来像一个黑点, 在这个演示中 Sprite 只是一个黑色方块.
渐进式教程
既然我们已经介绍了需用到的节点的基础知识, 那就可以开始逐步实现demo中的场景了.
首先添加一个 Sprite 并将其纹理设置为 背景图片 . 在你的游戏中这可以是你选择的任何背景. 对于我们这种风格的阴影, 这张图最可能是地板的纹理.
接下来创建三个 Light2D’s 并将它们的纹理设置为 light image . 你可以在上面的栏目中更改颜色. 默认情况下, 阴影关闭并且 mode
设置为 add
. 这意味着每个灯光都会将自己的颜色添加到下面的任何颜色中.
接下来为每个 Light 节点添加一个 Sprite 子节点, 并将 Sprite’s 纹理设置为 blob image . 他们都应该保持在 Light 节点的中心.blob是灯本身的图像, 而 Light 显示灯光对场景的影响. LightOccluder2D’s 会将光的位置视为 Light 节点的中心, 这就是为什么我们希望blob位于父节点 Light 的中心.
备注
这里将不涉及演示中的动画。有关创建动画的信息,请参见 动画功能介绍 。
现在场景看起来太亮了. 这是因为三个灯都在为场景添加颜色. 这就是演示场景使用 CanvasModulate 的原因. CanvasModulate 将整个视区乘以特定颜色.
在场景中添加 CanvasModulate 并将其颜色设置为 rgb(70, 70, 70)
. 这将使场景足够暗, 以清楚地看到灯光的效果.
现在, 我们来添加会投射阴影的物体.
该演示使用了一个名为 “casters” 的 Node 来组织投射阴影的物体. 在场景中添加 Node2D . 它会被用来把所有投射阴影的物体变成一个大组. 这样我们就可以同时显示和隐藏它们.
每个阴影投射器都由具有 LightOccluder2D 子节点的 Sprite 组成. 在演示中, Sprite 的纹理设置为 caster image . 子节点 LightOccluder2D 是所有神奇的事情发生的地方. 在游戏中 Sprite 可能不仅仅是一个黑色的方块; 它可以是任何可以投射阴影的物体的图片: 一面墙, 一个宝箱或其他任何东西.
LightOccluder2Ds 告诉游戏Occluder(遮光物)是什么形状.Occluder是一个多边形的容器 OccluderPolygon2D . 对于这个演示, 由于我们的墙是正方形, 我们将 Polygon
设置为正方形. 其他设置保持为默认.
对于第一个设置, Closed
可以是 on
或 off
。 闭合的多边形遮挡来自所有方向的光线。 开放多边形仅遮挡来自一个方向的光线。
Cull Mode
让您选择剔除的方向. 默认值为 “已禁用”, 这意味着无论灯光在哪一侧, 遮挡物都会投射阴影. 另外两个设置 Clockwise
和 Counter-Clockwise
指的是多边形顶点的弯曲顺序. 弯曲顺序用于确定光线的哪一侧在多边形内. 只有朝外的光线才投下阴影.
为了说明它们的差异, 这张图片里是一个相应的 LightOccluder2D 的 Closed
设置为 off
的 OccluderPolygon2D . 这是为了可以看到多边形的轮廓:
备注
Cull Mode
设置为 Disabled
. 全部三条轮廓线都投下阴影.
备注
Cull Mode
设置为 Clockwise
. 只有顶部和右侧线条投射阴影.
备注
Cull Mode
设置为 Counter-Clockwise
. 只有底部的轮廓线投下阴影. 如果 Closed
设置为 on
, 左边会有一条额外的垂直轮廓线也会投射阴影.
当你添加 LightOccluder2Ds 时, 阴影仍不会出现. 你需要回到 Light2Ds 并在Shadow部分下设置 Enable
为 on
. 这将打开带有硬边缘的阴影, 如下图所示.
为了给出看起来更好的柔和边缘阴影, 我们设置变量 filter
, filter smooth
和 gradient length
. Godot支持 Percentage Closer Filtering (PCF) , 它在像素周围提取阴影贴图的多个样本, 并模糊它们以创建平滑的阴影效果. 样本数越多, 阴影看起来越平滑但运行速度越慢. 这就是为什么Godot默认提供3-13个样本并让你可以自己选择用几个样本. 该演示使用PCF7.
备注
这是使用演示中设置渲染的阴影. gradient length
设置为 1.3
, filter smooth
设置成 11.1
, filter
设置为 PCF7
.
备注
filter
设置为 PCF13
. 注意这里阴影变宽了, 这是因为样本之间的距离是依赖于变量 filter smooth
的.
为了使用filtering(过滤), 你需要设置 filter smooth
变量. 这决定了样品之间的距离. 如果您想让柔软区域延伸很远, 您可以增加 filter smooth
的大小. 然而, 在低样品和大过滤平滑的情况下, 你会看到样本之间形成的线条.
备注
filter smooth
设置为 30
.
演示中的不同 Light 节点使用不同的filter smooth值. 玩玩它, 看看你喜欢什么样的.
备注
filter smooth
设置为 0
.
最后谈谈变量 gradient length
. 对于一些平滑阴影, 最好不要在对象上立即开始阴影, 因为这会产生硬边. Gradient length(渐变长度)变量让阴影刚开始的时候平滑渐变, 以减少硬边缘的影响.
备注
gradient length
设置为 0
.
备注
gradient length
设置为 10
.
您需要稍微调整设置以找到适合你项目的设置. 没有对每个人都正确的解决方案, 这就是Godot为什么提供如此多灵活性. 只要记住 filter
值越高, 阴影的计算成本也越高就行了.