extends Node # ============================================================================ # 探针 P1 —— Godot 4.7 hint_screen_texture / SCREEN_TEXTURE 语义 # 架构依据:§11 P1 / §5.2(ADR-2 单趟 fused 后处理的 CanvasLayer 拓扑) # 实测手册:docs/engineering/2026-10-19-f-w1-probe-p1-manual.md # 结论回填:docs/engineering/probes/P1-result.md # # 三问: # ① 背景/世界色是否含入 SCREEN_TEXTURE 采样(后处理 L1 能否看见 L0) # ② CanvasLayer 排序语义(L1 后处理在 L0 世界之上、L2 UI 之下) # ③ UI 层是否被后处理污染(UI 保持 crisp、不被 shader 调制) # # 场景在 _ready() 中代码化搭建(不手写 .tscn 降低出错面)。 # 键位:1 直通 | 2 反色 | 3 红染 | 4 纯绿 | V 显/隐后处理层 | S 截图 user:// | Esc 退出 # ============================================================================ enum PostMode { PASSTHROUGH, INVERT, RED_TINT, SOLID_GREEN } var _post: ColorRect var _post_visible := true var _mode: int = PostMode.PASSTHROUGH var _mat: ShaderMaterial var _hud: Label var _shot_n := 0 func _ready() -> void: _build_world() _build_post() _build_ui() _print_environment() func _build_world() -> void: var world := CanvasLayer.new() world.name = "L0_World" world.layer = 0 add_child(world) var bg := ColorRect.new() bg.name = "Background" bg.color = Color("#23384F") # 已知底色:后处理里能看见它 = 世界含入采样 bg.set_anchors_preset(Control.PRESET_FULL_RECT) world.add_child(bg) var marker := ColorRect.new() marker.name = "WorldMarker" marker.color = Color("#D08A2E") marker.position = Vector2(400, 240) marker.size = Vector2(480, 240) world.add_child(marker) var world_label := Label.new() world_label.name = "WorldLabel" world_label.text = "L0 World: bg #23384F + marker #D08A2E" world_label.position = Vector2(24, 180) world_label.add_theme_color_override("font_color", Color.WHITE) world.add_child(world_label) func _build_post() -> void: var post_layer := CanvasLayer.new() post_layer.name = "L1_PostProcess" post_layer.layer = 1 add_child(post_layer) var sh := load("res://tests/probe_p1_screen_texture/probe_p1.gdshader") as Shader _mat = ShaderMaterial.new() _mat.shader = sh _mat.set_shader_parameter("mode", PostMode.PASSTHROUGH) _post = ColorRect.new() _post.name = "PostProcessRect" _post.material = _mat _post.mouse_filter = Control.MOUSE_FILTER_IGNORE _post.set_anchors_preset(Control.PRESET_FULL_RECT) post_layer.add_child(_post) func _build_ui() -> void: var ui_layer := CanvasLayer.new() ui_layer.name = "L2_UI" ui_layer.layer = 2 add_child(ui_layer) var root := Control.new() root.name = "UIRoot" root.set_anchors_preset(Control.PRESET_FULL_RECT) ui_layer.add_child(root) # UI 样本:四色板 + 一块纯白。被后处理污染 = 颜色变了/出现着色/纸纹 var chip_colors := [ Color("#1A1614"), Color("#EDE6D8"), Color("#B03A2E"), Color("#3A5A6B"), Color("#FFFFFF"), ] var chip_names := ["墨 #1A1614", "骨白 #EDE6D8", "朱砂 #B03A2E", "靛 #3A5A6B", "纯白 #FFFFFF"] for i in chip_colors.size(): var chip := ColorRect.new() chip.name = "Chip%d" % i chip.color = chip_colors[i] chip.size = Vector2(200, 40) chip.position = Vector2(960, 48 + i * 56) root.add_child(chip) var lbl := Label.new() lbl.name = "ChipLabel%d" % i lbl.text = chip_names[i] lbl.position = Vector2(1010, 54 + i * 56) if chip_colors[i].get_luminance() > 0.5: lbl.add_theme_color_override("font_color", Color.BLACK) else: lbl.add_theme_color_override("font_color", Color.WHITE) root.add_child(lbl) _hud = Label.new() _hud.name = "HUDHelp" _hud.text = _help_text() _hud.position = Vector2(24, 648) _hud.add_theme_color_override("font_color", Color.WHITE) root.add_child(_hud) func _help_text() -> String: var mode_names := ["PASS直通", "INVERT反色", "RED红染", "GREEN纯绿"] # 条件表达式含数组下标 → Variant;`:=` 推断触发 INFERENCE_ON_VARIANT(4.7.2 按错误)→ 显式标注 var mode_name: String = mode_names[_mode] if _mode >= 0 and _mode < mode_names.size() else "?" return "探针 P1 | 1 直通 2 反色 3 红染 4 纯绿 | V 显/隐后处理层(当前:%s)| S 截图到 user:// | Esc 退出 | 当前 mode=%s" % [ "显示" if _post_visible else "隐藏", mode_name] func _input(event: InputEvent) -> void: var key_event := event as InputEventKey if key_event != null and key_event.pressed and not key_event.echo: match key_event.keycode: KEY_1: _set_mode(PostMode.PASSTHROUGH) KEY_2: _set_mode(PostMode.INVERT) KEY_3: _set_mode(PostMode.RED_TINT) KEY_4: _set_mode(PostMode.SOLID_GREEN) KEY_V: _post_visible = not _post_visible _post.visible = _post_visible _hud.text = _help_text() KEY_S: _screenshot() KEY_ESCAPE: get_tree().quit() func _set_mode(m: int) -> void: _mode = m _mat.set_shader_parameter("mode", m) _hud.text = _help_text() var mode_names := ["PASS直通", "INVERT反色", "RED红染", "GREEN纯绿"] print("P1 mode → %d(%s)" % [m, mode_names[m] if m >= 0 and m < mode_names.size() else "?"]) func _screenshot() -> void: var tex := get_viewport().get_texture() if tex == null: push_warning("P1: viewport texture 为空,回退:请用系统截图(Win+Shift+S)") return var img := tex.get_image() if img == null: push_warning("P1: get_image() 失败,回退:请用系统截图(Win+Shift+S)") return var path := "user://p1_mode_%d_%02d.png" % [_mode, _shot_n] _shot_n += 1 var err := img.save_png(path) print("P1 screenshot → ", path, " err=", err) func _print_environment() -> void: var v := Engine.get_version_info() print("=== P1 probe 环境(截图请连同此段一起归档)===") print("godot: %d.%d.%d %s" % [int(v.major), int(v.minor), int(v.patch), str(v.status)]) print("rendering_method: ", ProjectSettings.get_setting("rendering/renderer/rendering_method")) print("adapter: ", RenderingServer.get_video_adapter_name()) print("viewport: ", get_viewport().get_visible_rect().size) print("stretch: ", ProjectSettings.get_setting("display/window/stretch/mode"), " / ", ProjectSettings.get_setting("display/window/stretch/aspect")) print("=== 键位:1 直通 | 2 反色 | 3 红染 | 4 纯绿 | V 显隐后处理 | S 截图 | Esc 退出 ===")