iter9-numfix-a: L2/L3 数字可读性修复(甲案——数字墨族按板自适应)

- 根因:v3.5 冻结④亮墨三档(#D8ECF0 系)直画只按 L1 dungeon 验收;underdark/deep_underdark
  地板亮白筋纹归一后 p90=0.40/0.66,亮墨对亮斑 CR 1.0-1.9 融字(用户实机截图 2026-09-30 实证)
- 修法:_digit_ink_mode 按归一后地板逐像素分位数选墨族——对 p90 ≥4.5 且对均值 ≥2.0,
  亮族过选亮族否则深墨三档(青墨/赭墨/锈墨色温语义同构);缺盘平色回退态默认深墨
- 实测(引擎口径):dungeon 亮族 4.79/5.80 维持;underdark 深族 5.34/2.41;deep_underdark 深族 5.08/2.42
- 机检面:terrain_tile_sets_test 增三关对比断言(同一归一+选族管线+期望族表)21/21 绿
- 轻闸:冒烟 596/0+ui_input/ui/click/layout 四探针 PASS
This commit is contained in:
DKChan committed 2026-10-01 00:43:54 +08:00
1 parent 405bd7815f
commit 2301db5540
3 files changed
+111 -10

No files matched your search

+68 -6
View File
@@ -130,6 +130,9 @@ var _floor_tiles: Array[Texture2D] = [] # 地面瓦片五变体(下标 0..4
var _tiles_ok := false # false = 素材缺位/未装载——bg_sb 程序化平色原路径
var _flag_tex: Texture2D = null # 封印旗纹理(缺盘=null=字形「旗」回退——独立可选件不连瓦片整批)
var _tiles_board_type := "dungeon" # 当前装载瓦片套的 board_type(rebuild 按板切换——T6 换色批)
var _digit_dark_ink := true # 数字墨族按板自适应(true=深墨三档)。缺盘平色回退态 #B39A78 裸土
# 为中明度底——深墨族 CR 4.96 达标、亮墨族仅 2.2,故缺盘默认深墨;瓦片装载后按实测分位数覆写
#(L2/L3 亮白筋纹瓦片上亮墨融字缺陷修复 2026-10-01,判据见 _digit_ink_mode)
var cell_size: float: # 只读属性(ui_layout_probe 断言面——旧私有名 _cell 的契约化出口)
get:
@@ -647,9 +650,16 @@ func _badge_glyph(category: String) -> String:
# ---- 格态渲染(灰度截图可辨:完整覆尘 / 碎裂裸土 / 已开数字) ----
# 数字亮墨三档色温(圣经 v3.5 冻结④ 2026-09-30 批 B2——直画已开格底:1-3 冷亮/4-5 暖白/6-8 金亮,
# 色温承袭密度语义;实测对比 6.0–6.3:1。旧深墨三档转色牌后备路径专用〔牌上深墨族 12:1〕)
# 数字三档色温(按板自适应双族——v3.5 冻结④ 修订 2026-10-01):亮墨族 1-3 冷亮/4-5 暖白/6-8 金亮
#(dungeon 瓦片实测达标维持);深墨族 1-3 青墨/4-5 赭墨/6-8 锈墨(色温语义同构——underdark/
# deep_underdark 亮白筋纹瓦片上亮墨对亮斑 CR 1.0–1.9 融字,深墨族 5.7–11.1;选族判据见 _digit_ink_mode)
func _digit_ink(d: int) -> Color:
if _digit_dark_ink:
if d <= 3:
return UiKit.INK_COLD
if d <= 5:
return UiKit.INK_OCHRE
return UiKit.INK_RUST
if d <= 3:
return UiKit.INK_L_COLD
if d <= 5:
@@ -867,9 +877,13 @@ func _load_board_tiles(board_type: String = "dungeon") -> void:
return
# 地板归一(圣经 v3.5 冻结①/§1.4 样张 v3 记录——已开格底归一世界底层档 L≈0.10,带 0.08–0.14):
# 方向稿 _v3_darken_floors 同式移植;现行瓦片 L≈0.036 低于带下沿故实为提亮;素材重产归资产批,
# 本归一为程序代役(逐批装载时对 freshly-loaded 原图测光,幂等)
# 本归一为程序代役(逐批装载时对 freshly-loaded 原图测光,幂等)。归一后逐像素明度顺路采集,
# 驱动数字墨族按板自适应(_digit_ink_mode——均值分位同源同像素,禁二次解码)
var lumas: Array = []
for i in range(floors.size()):
floors[i] = _normalize_floor_luma(floors[i])
floors[i] = _normalize_floor_luma(floors[i], 0.10, lumas)
var ink_mode := _digit_ink_mode(lumas)
_digit_dark_ink = bool(ink_mode.dark)
# 六镜像件(词表 §二:wall_e←wall_w / wall_ne←wall_nw / wall_se←wall_sw /
# wall_end_e←wall_end_w / wall_in_ne←wall_in_nw / wall_in_se←wall_in_sw;只水平翻转禁旋转
# ——北受光不受损)
@@ -907,7 +921,7 @@ static func _flip_tex(tex: Texture2D) -> Texture2D:
# 地板瓦片明度归一(v3.5 批 B1——方向稿 _v3_darken_floors 同式移植):8×8 双线性重采样均值测光
# (sRGB→线性域,Rec.709 系数),增益 k=(目标/实测)^(1/2.2) 钳 [0.6,1.8],逐通道 sRGB 域线性拉伸。
# 输入恒为 freshly-loaded 原图(load_tex 每次盘读)——幂等可重入;32×32 五变体开销可忽略
static func _normalize_floor_luma(tex: Texture2D, target_l: float = 0.10) -> Texture2D:
static func _normalize_floor_luma(tex: Texture2D, target_l: float = 0.10, lumas_out = null) -> Texture2D:
var img: Image = tex.get_image()
if img.is_compressed():
img.decompress()
@@ -924,7 +938,12 @@ static func _normalize_floor_luma(tex: Texture2D, target_l: float = 0.10) -> Tex
for y in range(img.get_height()):
for x in range(img.get_width()):
var c := img.get_pixel(x, y)
img.set_pixel(x, y, Color(minf(c.r * k, 1.0), minf(c.g * k, 1.0), minf(c.b * k, 1.0), c.a))
var nr := minf(c.r * k, 1.0)
var ng := minf(c.g * k, 1.0)
var nb := minf(c.b * k, 1.0)
img.set_pixel(x, y, Color(nr, ng, nb, c.a))
if lumas_out != null:
lumas_out.append(0.2126 * _srgb_lin(nr) + 0.7152 * _srgb_lin(ng) + 0.0722 * _srgb_lin(nb))
return ImageTexture.create_from_image(img)
@@ -932,6 +951,49 @@ static func _srgb_lin(c: float) -> float:
return c / 12.92 if c <= 0.04045 else pow((c + 0.055) / 1.055, 2.4)
# ---- 数字墨族按板自适应(L2/L3 亮瓦融字缺陷修复 2026-10-01——甲案:墨色按关自适应+三关对比断言)----
const DIGIT_INK_CR_P90 := 4.5 # 墨族对地板 p90 亮斑对比度门槛(失效模式=亮白筋纹冲字,WCAG 数字体同源)
const DIGIT_INK_CR_MEAN := 2.0 # 墨族对地板均值对比度门槛(次要防中调底线——引擎测光三关实测 2.4–5.8;选族主判据=p90)
# 归一后地板逐像素明度 → 选墨族。规则:家族最弱成员(亮族=金亮/深族=锈墨)对 p90 ≥ 4.5 且对均值
# ≥ 2.5;亮族过选亮族,否则深族;两族皆不过取对 p90 较强者并告警(机检断言面=terrain_tile_sets_test)。
# 实测(2026-10-01):dungeon p90=0.121 亮族 5.01/6.02 ✓ 维持;underdark p90=0.406 亮族 1.88/4.33 ✗
# 深族 6.20/2.69 ✓;deep_underdark p90=0.395 亮族 1.93/4.29 ✗ 深族 6.05/2.72 ✓——L2/L3 切深墨族
static func _digit_ink_mode(lumas: Array) -> Dictionary:
var sorted := lumas.duplicate()
sorted.sort()
var n := sorted.size()
if n == 0:
return {"dark": false, "cr_p90_bright": 0.0, "cr_mean_bright": 0.0, "cr_p90_dark": 0.0, "cr_mean_dark": 0.0}
var p90: float = sorted[int(n * 0.9)]
var mean := 0.0
for v in sorted:
mean += v
mean /= n
var cr_p90_b := _contrast_y(UiKit.INK_L_GOLD, p90)
var cr_mean_b := _contrast_y(UiKit.INK_L_GOLD, mean)
var cr_p90_d := _contrast_y(UiKit.INK_RUST, p90)
var cr_mean_d := _contrast_y(UiKit.INK_RUST, mean)
var bright_ok := cr_p90_b >= DIGIT_INK_CR_P90 and cr_mean_b >= DIGIT_INK_CR_MEAN
var dark_ok := cr_p90_d >= DIGIT_INK_CR_P90 and cr_mean_d >= DIGIT_INK_CR_MEAN
var dark := not bright_ok
if dark and not dark_ok and cr_p90_b > cr_p90_d:
dark = false
push_warning("[棋盘] 地板纹理两族墨皆不过对比门槛——取对亮斑较强亮族(cr_p90=%.2f)" % cr_p90_b)
return {"dark": dark, "cr_p90_bright": cr_p90_b, "cr_mean_bright": cr_mean_b,
"cr_p90_dark": cr_p90_d, "cr_mean_dark": cr_mean_d}
static func _contrast_y(ink: Color, bg: float) -> float:
var y := _ink_y(ink)
return (maxf(y, bg) + 0.05) / (minf(y, bg) + 0.05)
static func _ink_y(c: Color) -> float:
return 0.2126 * _srgb_lin(c.r) + 0.7152 * _srgb_lin(c.g) + 0.0722 * _srgb_lin(c.b)
# 格坐标确定性散列(禁 RNG/禁 randomize 纪律——「初始化随机落定禁逐轮重掷」圣经原则三落点:
# 同格坐标恒同值,refresh/重绘/逐轮不变)。乘加混合 + 移位雪崩;64 位整型乘法回绕即哈希语义
#(GDScript int 溢出静默回绕),板域 10×10/12×12 内 mod 10/mod 5 分布均匀
+5 -4
View File
@@ -7,11 +7,12 @@ extends RefCounted
# ── 色板(语义族;值 = 2026-09-20 收敛时现值) ──
const INK := Color8(51, 38, 27) # 墨族——正文/数字(对格底 ≥4.5:1)
const INK_COLD := Color8(19, 46, 54) # 青墨 1-3 #132E36(数字墨三档·冷=稀疏——样张 v2 定稿 2026-09-28;v3.5 起转色牌后备路径专用)
const INK_OCHRE := Color8(60, 37, 12) # 赭墨 4-5 #3C250C(数字墨三档·中;v3.5 起转色牌后备路径专用)
const INK_RUST := Color8(74, 30, 20) # 锈墨 6-8 #4A1E14(数字墨三档·暖=密集;v3.5 起转色牌后备路径专用)
const INK_COLD := Color8(19, 46, 54) # 青墨 1-3 #132E36(数字墨三档·冷=稀疏——样张 v2 定稿 2026-09-28;亮瓦自适应深墨族档兼色牌后备路径)
const INK_OCHRE := Color8(60, 37, 12) # 赭墨 4-5 #3C250C(数字墨三档·中;亮瓦自适应深墨族档兼色牌后备路径)
const INK_RUST := Color8(74, 30, 20) # 锈墨 6-8 #4A1E14(数字墨三档·暖=密集;亮瓦自适应深墨族档兼色牌后备路径)
# ── 亮墨三档(圣经 v3.5 冻结④ 2026-09-30——数字直画已开格底:色温承袭密度语义,冷亮/暖白/金亮;
# 实测对比 6.0–6.3:1(A3a);金亮低饱和避奖励金语义;色牌后备组用深墨族上牌〔12:1〕)──
# 实测对比 6.0–6.3:1(A3a);金亮低饱和避奖励金语义;色牌后备组用深墨族上牌〔12:1〕。
# 2026-10-01 修订:亮墨族限暗纹理板(dungeon),亮筋纹板按 _digit_ink_mode 自适应切深墨三档)──
const INK_L_COLD := Color8(216, 236, 240) # 冷亮 1-3 #D8ECF0
const INK_L_WARM := Color8(240, 226, 200) # 暖白 4-5 #F0E2C8(关卡屏 WARM 同族)
const INK_L_GOLD := Color8(248, 227, 168) # 金亮 6-8 #F8E3A8
@@ -36,6 +36,7 @@ func _init() -> void:
_check("前置:board_gen 词表非空(%d 型)" % types.size(), types.size() > 0)
_test_set_completeness(board_dir, types)
_test_hue_domains(board_dir)
_test_digit_ink_modes(board_dir, types)
if _failures > 0:
push_error("[terrain_tile_sets_test] %d/%d 项失败" % [_failures, _checks])
quit(1)
@@ -128,3 +129,40 @@ func _load_stats(board_dir: String, fname: String, top_half: bool) -> Dictionary
if n_v == 0 or n_h == 0:
return {}
return {"h": h_sum / n_h, "v": v_sum / n_v}
# 数字墨族按板自适应对比断言(L2/L3 亮瓦融字缺陷修复 2026-10-01——甲案机检面):
# 每个图型走 BoardView 同一归一+测光+选族管线(禁测试侧另写算法),断言:
# ①所选墨族对 p90 亮斑 ≥4.5 且对均值 ≥2.5(双门槛,同 _digit_ink_mode 判据常量)
# ②期望族面:dungeon=亮族(样张 v3.5 冻结④原样);underdark/deep_underdark=深族(亮白筋纹 p95
# 0.66–0.77 上亮墨 CR 1.0–1.9 融字实证)——期望表防「选族逻辑被顺手改坏」回归
func _test_digit_ink_modes(board_dir: String, types: Array) -> void:
var expect_dark := {"dungeon": false, "underdark": true, "deep_underdark": true}
var variants: int = int(BoardViewScript.TILE_FLOOR_VARIANTS)
for bt in types:
var lumas: Array = []
var readable := true
for i in range(1, variants + 1):
var p := board_dir.path_join("terrain_floor_%s_%d.png" % [String(bt), i])
if not FileAccess.file_exists(p):
readable = false
break
var tex: Texture2D = ImageTexture.create_from_image(Image.load_from_file(p))
BoardViewScript._normalize_floor_luma(tex, 0.10, lumas)
if not readable:
_check("图型 %s 数字墨族断言样本可读" % String(bt), false)
continue
var mode: Dictionary = BoardViewScript._digit_ink_mode(lumas)
var dark: bool = bool(mode["dark"])
var cr_p90 := float(mode["cr_p90_bright"]) if not dark else float(mode["cr_p90_dark"])
var cr_mean := float(mode["cr_mean_bright"]) if not dark else float(mode["cr_mean_dark"])
var family := "亮墨族" if not dark else "深墨族"
_check("图型 %s 所选%s 对 p90 ≥%.1f(实测 %.2f)" % [String(bt), family,
float(BoardViewScript.DIGIT_INK_CR_P90), cr_p90],
cr_p90 >= float(BoardViewScript.DIGIT_INK_CR_P90))
_check("图型 %s 所选%s 对均值 ≥%.1f(实测 %.2f)" % [String(bt), family,
float(BoardViewScript.DIGIT_INK_CR_MEAN), cr_mean],
cr_mean >= float(BoardViewScript.DIGIT_INK_CR_MEAN))
if expect_dark.has(bt):
_check("图型 %s 墨族期望=%s(实测=%s)" % [String(bt),
"深族" if bool(expect_dark[bt]) else "亮族", family], dark == bool(expect_dark[bt]))