今日速览
- Godot 里画 2D 全部走 CanvasItem shader,代码第一行必须写
shader_type canvas_item;,只有vertex()、fragment()、light()三个可覆写函数。 - 一个 shader 不能单独存在,必须挂在 Material(通常是
ShaderMaterial)上,再把材质挂到节点;所有继承CanvasItem的节点(Sprite2D、Control、TileMapLayer…)都有material属性。 - 三个必背内置变量:
UV(0~1 纹理坐标)、TEXTURE(节点默认贴图)、COLOR(fragment 里既是输入也是输出,含 modulate)。TIME可做动态效果,TEXTURE_PIXEL_SIZE是做描边/偏移的关键。 - shader 参数用
uniform暴露到检视面板,代码里用material.set_shader_parameter("名字", 值)驱动,再用Tween做过渡——这就是「受击闪白」的实现路径。 - 想读屏幕内容(做全屏滤镜、屏幕扭曲)要用
hint_screen_texture+SCREEN_UV;2D 里多个屏幕读取 shader 叠加时,要用BackBufferCopy节点修正。
核心学习内容
1. CanvasItem shader 的最小骨架
官方「Your first 2D shader」给出的起点极其简单:给一个 Sprite2D 建 ShaderMaterial → New Shader → 打开 shader 编辑器。最朴素的 fragment 就是把每个像素涂成一个颜色:
shader_type canvas_item;
void fragment() {
COLOR = vec4(0.4, 0.6, 0.9, 1.0);
}
要还原原始贴图并能参与光照/调制,写法是 COLOR = texture(TEXTURE, UV);。切记:fragment 里 COLOR 的输入值已经乘过 modulate 和纹理色,所以想拿到纯顶点色(modulate)要先用 varying 把它从 vertex() 传过来。这个细节决定了「闪白」会不会把半透明像素也一起点亮。
2. 三个最实用的 2D 着色器效果
这年头玩家判断一个游戏「手感好不好」,很大一部分来自反馈:受击闪白、死亡溶解、目标描边。它们都不需要改美术素材,全靠 shader。
① 受击闪白:把贴图 rgb 往目标色插值,插值强度用 uniform 控制,乘上 tex.a 保证透明区域不被染色(保持轮廓干净)。
shader_type canvas_item;
uniform float flash_amount : hint_range(0.0, 1.0) = 0.0;
uniform vec4 flash_color : source_color = vec4(1.0);
varying vec4 v_color;
void vertex() { v_color = COLOR; }
void fragment() {
vec4 tex = texture(TEXTURE, UV);
tex.rgb = mix(tex.rgb, flash_color.rgb, flash_amount * tex.a);
COLOR = tex * v_color;
}
代码侧只需一条 Tween 把 flash_amount 从 1 拉回 0,就是标准的受击反馈:
extends Sprite2D
func flash(duration := 0.15) -> void:
var mat := material as ShaderMaterial
mat.set_shader_parameter("flash_amount", 1.0)
create_tween().tween_method(
func(v): mat.set_shader_parameter("flash_amount", v),
1.0, 0.0, duration)
② 溶解消失:用一张噪声图,比 progress 小的像素直接 discard,再在阈值附近做一段 edge_color,就有「被烧掉」的边缘光。
shader_type canvas_item;
uniform float progress : hint_range(0.0, 1.0) = 0.0;
uniform sampler2D noise_tex : repeat_enable;
uniform vec4 edge_color : source_color = vec4(1.0, 0.6, 0.0, 1.0);
uniform float edge_width : hint_range(0.0, 0.3) = 0.05;
varying vec4 v_color;
void vertex() { v_color = COLOR; }
void fragment() {
vec4 tex = texture(TEXTURE, UV);
float n = texture(noise_tex, UV).r;
if (n < progress) discard;
float edge = smoothstep(progress, progress + edge_width, n);
vec3 col = mix(edge_color.rgb, tex.rgb, edge);
COLOR = vec4(col, tex.a) * v_color;
}
死亡时把 progress 从 0 补间到 1,再 queue_free(),比「直接消失」高级一个档次。
③ 描边:用 TEXTURE_PIXEL_SIZE 采样上下左右四个方向的 alpha,邻居有实体而自己是透明像素,就画成描边色。这套常用于「可选目标高亮」「敌人锁定」——配合 outline_only 参数还能做成只画轮廓的剪影。
3. 落地小抄
- 参数一定用
uniform暴露,方便策划/美术在检视面板实时调,不用改代码。 - 颜色类 uniform 记得加
source_color提示,Godot 才会按 sRGB 正确处理。 - 大量相同 shader 的节点,让子节点「继承父材质」(material 的 inherit 选项)能省一批材质实例。
- shader 报错会在编辑器下方直接标出,先看行号再看变量名,九成是拼错内置变量或漏了
;。
🎯 DeepSeek 提示词
提示词 1:让 DeepSeek 写「受击闪白」shader + 驱动脚本
适用场景:角色/敌人/可破坏物受击时的即时反馈。
你是资深 Godot 4 着色器与 GDScript 工程师。
【任务】为一个 2D Sprite2D 角色实现「受击闪白」效果,输出两部分:
1) CanvasItem shader 源码(shader_type canvas_item);
2) 一个 GDScript 脚本,暴露 flash(duration) 方法。
【技术约束】
- shader 用 uniform float flash_amount (hint_range 0..1) 和 uniform vec4 flash_color (source_color)(默认白色)。
- 用 varying 把 vertex() 的 COLOR 传给 fragment(),避免 modulate 被重复相乘。
- 插值时乘以贴图 alpha(tex.a),保证透明区域不被染色、轮廓干净。
- GDScript 扩展 Sprite2D,用 create_tween() + tween_method 把 flash_amount 从 1 补间回 0;
处理 material 为空或不是 ShaderMaterial 的情况,给出明确报错。
- 代码兼容 Godot 4.4+,只输出可运行代码 + 关键行中文注释。
【输出格式】先给 shader 代码块,再给 GDScript 代码块,最后用 3 条要点说明如何挂载到节点。
提示词 2:让 DeepSeek 写「溶解消失」shader 并接入死亡流程
适用场景:敌人死亡、道具被拾取、场景切换的消失表现。
你是 Godot 4 图形工程师。
【任务】写一个 canvas_item 溶解消融 shader,以及一段死亡调用脚本。
【shader 要求】
- uniform float progress (hint_range 0..1,默认 0) 控制溶解进度;
- uniform sampler2D noise_tex(repeat_enable)作为噪声源;
- uniform vec4 edge_color (source_color) 与 uniform float edge_width 控制边缘烧焦光;
- 当噪声值 < progress 时 discard;在 progress 附近用 smoothstep 混出 edge_color。
【脚本要求】
- 扩展 Node2D 或 Enemy,提供 func dissolve_and_free(duration := 0.6);
- 用 Tween 把 progress 从 0 补到 1,结束后 queue_free();
- 若节点没有 ShaderMaterial 就跳过 shader、直接延迟释放,保证不崩。
【约束】Godot 4.4+;注释说明 noise_tex 该用哪种噪声贴图(如 FastNoiseLite 生成)以及 tiling 设置。
【输出格式】shader 代码块 + GDScript 代码块 + 「如何生成噪声贴图」的 4 步操作说明。
提示词 3:让 DeepSeek 排查 shader 报错 / 优化
适用场景:shader 编译报错、画面全黑、效果不对时,把 DeepSeek 当调试助手。
你是 Godot 着色器调试专家。我会贴出报错和源码,请按下面流程回答。
【我提供】报错信息(含行号)+ shader 源码 + 期望效果的一段话描述。
【你的任务】
1) 逐行解释报错含义,指出最可能出问题的行;
2) 列出 Godot 4 canvas_item shader 中与该行相关的常见坑(内置变量拼写、uniform 类型、
缺少 source_color/hint_range、fragment 里误用 vertex-only 变量等);
3) 给出修正后的最小可用代码;
4) 若画面异常(全黑/全白/无透明),列出 3 条排查顺序(纹理采样、alpha、render_mode)。
【约束】只针对 Godot 4.x canvas_item shader,不要给 3D/Unity 方案;
不确定时明确说明「需确认」,不要编造 API。
【输出格式】分 4 个小标题作答,代码用代码块包裹。
学习心得
到现在为止,我做游戏的能力链条已经从「让角色动起来」(物理、手感、动画)走到「让画面对玩家说话」。Shader 是我之前最怕的一块——感觉像玄学,但今天贴完官方文档发现:2D shader 的门槛其实只有一个 fragment() 函数。它本质是「我拿到每个像素的贴图和坐标,返回一个新颜色」,受击闪白、溶解、描边全是这条思路的变体。
对「用 DeepSeek 做一款 Steam 游戏」这个目标,shader 的意义格外大:它是性价比最高的品质提升手段。美术素材我可以用 AI 生成(第 28 天学过风格统一),但「受击发白」「死亡溶解」「目标描边」这类动态反馈,靠换素材是换不出来的,只能靠 shader。而 shader 代码恰好是 DeepSeek 很擅长写的东西——语法固定、约束明确、有官方文档兜底。今天三条提示词,本质就是把我今天的「读文档 → 试错」过程固化下来,以后直接复用。
明日关注
- 把今天的三个 shader 挂到自己的测试场景里跑通,记录每步的检视面板参数。
- 学
hint_screen_texture+BackBufferCopy:给游戏加全屏「受伤红屏」或「暂停模糊」。 - 研究 shader 与
AnimationPlayer/Tween的配合:哪些效果该用 shader,哪些更适合动画。
本文由自动化学习流水线每日生成,坚持即学即记。
评论