前面几十篇里,我们把「AI 出素材」这件事讲透了:怎么生成、怎么统一风格、怎么导入 Godot、怎么切像素。但 AI 出的贴图有个天然缺点——它是一张「被均匀照亮」的平面图,亮得平平的。玩家一眼看过去,房间是亮着的,但你说不出光源在哪、哪里是暗的、哪里危险。今天补上这块「观感的最后一公里」:2D 光照与氛围。它能让同一张 AI 素材,瞬间从「贴纸」变成「有纵深、有情绪的场景」。

今日速览

  • 默认的 Godot 2D 场景是**unshaded(无光照)**的,所以直接放个 PointLight2D 只会「更亮」,不会「变黑」——必须先放 CanvasModulate 把环境压暗,光才有意义。
  • 一套完整的 2D 光照是四件套:CanvasModulate(环境底色)+ PointLight2D(火把/子弹这类点光)+ DirectionalLight2D(太阳/月亮这类平行光)+ LightOccluder2D(投影的遮挡体)。
  • 光照按**叠加(Add)**为默认,所以「黑夜」不是光变少,而是环境色变暗;Mix / Subtract 混合模式是特效用的。
  • 阴影要出现,光必须开 Shadow > Enabled,并且场景里得有 LightOccluder2D(或 TileMapLayer 的遮挡层)——两者缺一不可。
  • 光源是「按屏幕像素」花钱的:灯越大、开的阴影越多越贵。用 Texture Scale 和 Range / Item Cull Mask 把光影响的范围收窄,是独立游戏最实用的性能开关。

核心学习内容

1. 为什么你的 2D 场景「加了灯也不黑」

这是新手最大的困惑。Godot 官方文档第一句就说:2D 场景默认是没有光照的,所有东西按原样显示。此时你放一个 PointLight2D,它只是把原本就亮的东西再照亮一点,画面整体反而更刺眼了。

正确的做法是先放一个 CanvasModulate 节点,给它一个深蓝/深灰的颜色,作为整屏的「环境底色」(ambient)。这个颜色代表「没有任何光源照到的地方」的最终颜色。有了它,点光扫过的地方亮、光外的地方暗,明暗对比才出现——而对比,才是氛围。

记住这个因果:PointLight2D 负责「提亮」,CanvasModulate 负责「压暗」。只做前者不做后者,等于白做。

还有个小坑:画布背景色(background color)不参与光照。如果你想让「地面」被照亮,必须让地面有一张真实的贴图(Sprite2D 或 TileMapLayer),否则背景永远是一块死板的纯色。想省事可以用 Sprite2D 的 Region + Texture > Repeat,快速铺一张可平铺的 AI 地面图。

2. 四件套的分工与关键参数

节点角色必调参数
CanvasModulate环境底色(决定「黑」到什么程度)color(夜=深蓝,黄昏=暖橙)
PointLight2D火把、灯泡、子弹、魔法texture(灰度光斑)、texture_scale(光大小)、energy(强度)、height(配合法线)
DirectionalLight2D太阳 / 月亮(平行光)height、max_distance(阴影剔除距离)
LightOccluder2D让物体投影occluder 多边形、occluder_light_mask

关于光的纹理:PointLight2D 的形状完全由一张(通常是灰度的)纹理决定,纹理尺寸=光的尺寸。你手上没有现成的光斑图,可以直接给 Texture 新建一个 GradientTexture2D,把 Fill 设成 Radial(径向),让渐变从中心的不透明白过渡到边缘的透明,就得到一张能用的圆形光斑——这招在「不想再去找素材」时非常省事。

关于混合模式(Blend Mode):默认的 Add(叠加) 适合 99% 的场景,火把、路灯都用它。Subtract(相减) 是做「负光」——物理上不真实,但做「吞噬光线的黑洞」或「阴影怪物」这类特效很好用。Mix(混合) 会按光的纹理做线性插值,需要光的纹理带 alpha 通道,适合做「染色」而不是「加亮」。

关于 item_cull_mask 与 occluder_light_mask:这两个是配对的。前者控制「这盏灯能照亮哪些节点」,后者控制「这个遮挡体给哪些灯投阴影」。比如「洞口的篝火不该照亮洞外的雨」,就靠这套掩码精确控制。

3. 让 AI 素材「活」起来:火光闪烁 + 昼夜循环

静态的光还是「一张图」,会呼吸的光才是「氛围」。两个最容易出效果的动态化玩法:

① 火光闪烁:不要硬改 energy 的随机值(会闪得很假),用噪音驱动。让 energy 在 base ± amplitude 之间做平滑噪声波动,火光就有机地跳动了。同一个 PointLight2D 挂到玩家、怪物身上的「火把」复用,整场光照风格立刻统一。

② 昼夜循环:不要动灯的开关,去 Tween CanvasModulate 的 color。白天环境色接近白(甚至略暖),黄昏转橙,夜晚转深蓝;同时让 DirectionalLight2D 的颜色和 energy 同步变化。因为「黑」是环境色决定的,所以 Tween 一个颜色就能把整张地图从白天推到夜晚——这就是把 AI 素材变成「会经历时间的世界」的性价比最高的一招。

落地建议:把「火光闪烁」和「昼夜循环」各写成一个可复用的 Node 脚本(挂在光或 CanvasModulate 上),这样以后任何一个新关卡,拖进去就有效果,不用重配。

🎯 DeepSeek 提示词

提示词 1|生成「火光闪烁 + 昼夜循环」Godot 4 脚本

适用场景:你已经放好了 PointLight2D / CanvasModulate,想让它们动起来,缺一段靠谱的 GDScript。

你是 Godot 4.x 游戏开发专家。请为我写一个 GDScript 脚本,实现两个可复用的光照效果。

【角色与目标】
输出面向 Godot 4.3+ 的 GDScript,代码可直接复制粘贴运行。

【任务】
1. script A(挂在 PointLight2D 上):用 FastNoiseLite 噪音驱动 energy,
   使光在 base_energy ± amplitude 之间平滑闪烁,模拟火光/烛光,禁止用裸随机数。
2. script B(挂在 CanvasModulate 上):实现昼夜循环——用 Tween 或
   _process 在给定的昼夜颜色数组(白/暖橙/深蓝)之间平滑过渡,
   并同步调整一个 DirectionalLight2D 的 energy 与 color。

【输入】
- 以 @export 变量暴露:基础能量、波动幅度、闪烁速度、昼夜周期秒数、
  各时段颜色(Array[Color])、关联的 DirectionalLight2D 路径。

【输出格式】
- 两段独立的完整脚本,每段带 `extends` 与 class_name。
- 关键行加中文注释。
- 末尾给一段「如何挂载 + 如何在检查器里配置」的 3 步说明。

【约束】
- 只用 Godot 4 原生 API,不引入第三方插件。
- 噪音必须平滑,闪烁不能出现「跳变」。
- 昼夜循环要能被 @export 的周期控制,且可暂停。

提示词 2|为场景设计一套 2D 光照氛围方案

适用场景:刚做完一个关卡,想让 DeepSeek 给你一份「光怎么打」的参数表,而不是自己瞎试。

你是资深 2D 关卡美术。我会给你一个场景描述,请输出一套 Godot 4 的 2D 光照配置方案。

【背景】
默认 2D 场景是 unshaded 的,我必须先加 CanvasModulate 才能压暗环境。

【任务】
针对场景主题,给出:CanvasModulate 环境色、需要的 PointLight2D 列表
(每盏的位置语义、颜色、energy、texture_scale、blend_mode、
height)、是否有 DirectionalLight2D(颜色/energy/height)、
哪些物体需要 LightOccluder2D。

【输入】
场景主题:<例如:雨夜的地牢入口,一盏篝火,远处有月光从缺口照进来>

【输出格式】
Markdown 表格,列:节点类型 | 用途 | 关键参数 | 备注。
表格后附 3 条「最容易被忽略但很重要」的提醒。

【约束】
- 遵循 Godot 4 光照规则:CanvasModulate 负责压暗,光负责提亮。
- 参数要具体到数值(颜色给 hex,energy 给 0-2 之间的数)。
- 指出哪些设置会增加性能开销,并给出收窄范围的建议。

提示词 3|审查 2D 光照「没效果 / 卡顿」的常见坑

适用场景:灯放了但场景不黑、阴影不出现、帧率掉了——让 DeepSeek 按清单排雷。

你是 Godot 4 性能与渲染专家。我在做 2D 光照,遇到了问题,请帮我定位。

【我的现象】<例如:放了 PointLight2D 但画面没有变暗 / 开了影子却没有阴影 / 加了 8 盏灯掉帧>
【我的配置】<粘贴你的节点树 + 关键参数,或描述>

【任务】
1. 按优先级列出最可能的 3-5 个原因(例如:没加 CanvasModulate、
   没开 Shadow>Enabled、缺 LightOccluder2D、遮挡多边形与贴图不匹配、
   灯太大/开了太多阴影导致像素开销过高)。
2. 每条原因给出:如何 30 秒内验证 + 具体修复步骤。
3. 给一份「2D 光照性能检查清单」,按优化收益从高到低排序。

【约束】
- 以 Godot 4.3+ 的实际行为为准,不要编造不存在的属性。
- 涉及性能时,明确区分「像素填充开销」与「阴影/SDF 开销」。
- 输出要能让我照着逐条勾。

学习心得

回到「用 DeepSeek 从零做一款上架 Steam 的游戏」这个目标——光照是最便宜的「卖相升级」。玩家在商店页看截图的那 3 秒,决定他点不点进来,而一张「有暗部、有光源、有情绪」的截图,明显比一张均匀明亮的贴纸截图更「像一款正式作品」。更进一步,前面我们用 AI 批量生成素材,最怕的就是「风格不统一」;而一套统一的光照规则(同样的环境色、同样的火光色温、同样的混合模式)会像滤镜一样,把风格各异的 AI 素材「盖」成同一个世界的色调——这其实是「素材风格统一」在渲染层的最后一招。今天这套四件套,直接搬进你正在做的原型里,半小时就能看出差别。

明日关注

  • 把「火光闪烁」做成可复用脚本,挂到玩家和怪物身上,验证整场光照风格是否统一。
  • 用 Tween 给 CanvasModulate 做一个「黄昏→夜晚」的过渡,并截图对比商店页素材。
  • 数一下当前关卡的光源数量,用 Range / Item Cull Mask 收窄影响范围,测一测掉不掉帧。

本文由自动化学习流水线每日生成,坚持即学即记。