Files
mtgodot-poc/docs/GODOT-POC-PLAN.md
T
shenleiandClaude Opus 5 fb4d2d222b docs: 文档审计——修正失效链接与过期结论
按 docs/ 目录逐篇核对,只改与事实/路径不符的部分,不动尚未验证的计划条目:

- `docs/steps/**` 在早前整理时已迁到 `docs/reference/steps/**`,全仓的旧路径
  引用(PLAN.md / README.md / M0-gr2-reader.md 及 libgr2 的头注释)一并改正。
- CLIENT-GAP.md / CLIENT-GAP-FIX.md / BACKLOG.md / MIDREVIEW.md:把已经落地的
  条目从「待办」改为已完成,删掉与代码现状矛盾的描述。
- ANDROID-TESTING.md / CLIENT-PORT.md / CLIENT-ROADMAP.md / GODOT-POC-PLAN.md /
  SHINSOO-WORLD-RENDERING.md / PARITY-GAP.md:同上,另补当前实际的构建/测试入口。
- THIRD-PARTY.md:补齐实际在用的第三方来源与许可说明。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SJugvEJwz3FK4hw9ti3SRb
2026-09-08 17:15:17 +09:00

27 KiB
Raw Blame History

Godot 渲染 Demo — 开发计划

内部研究方案,不对外公开。

2026-08-29 更新:并行的 bgfx 自研引擎方案(xrender-poc / reference/PLAN.md 经中期评审(MIDREVIEW.md停止开发,本方案成为唯一在研路线。 libgr2 / formats / oracle / tools 已从 xrender-poc vendored 进本仓库 ../libgr2../formats../oracle../tools),不再是 submodule / sibling 引用。 下文中出现的 xrender-poc/xxx 路径按 reference/README.md 的映射表读。 bgfx demo 截图作为交叉核对基线留在 ../test/bgfx-reference/

状态 已被工作范围超越(2026-09-08 复核)。Phase 1macOS)完成,见 MIDREVIEW.mdPhase 2 的 iOS / Android 交叉编译与 APK 导出也已完成(BACKLOG.md F1/F2、PLATFORMS.md),故文中「Phase 2 本轮不做」不再成立。§01「明确排除」清单已大面积失效,见该节的复核注。当前工作以 BACKLOG.mdCLIENT-GAP.mdRENDERING-REPAIR-PLAN.md 为准
技术栈 Godot 4.7.1 stable · GDExtensiongodot-cpp 精确提交 101ae384.7 API)· C++20
目标平台 Phase 1macOS(当前)→ Phase 2Android(一加 13 / Vulkan)· iOSiPhone 16 / Metal)。自用,三台现代设备,不涉及 GLES3 / Compatibility
判定周期 Phase 1 ≈ 3.55 周(单人)→ 中期评审Phase 2 = 三设备各一次 bring-up + 性能留档(自用,无对外 go/no-go)
复用 libgr2gr2 v6 读取器)· formats/textscript · msa · msm)· oracle/ golden · bgfx demo 截图
自研 Metin2Model GDExtension 节点(gr2 → Skeleton3D + ArrayMesh + 材质)

00 · 阶段划分

阶段 平台 里程碑 回答什么 产出
Phase 1 macOS M0' · M1 · M2 · M2.5 ① gr2 → Godot 场景对象能否正确映射;② 动画运行时(采样 / retarget / 事件)能否移植;③ Metin2 观感能否在 Godot 里还原 中期评审报告:桥接层工作量实测 + 观感对比 + 剩余风险
Phase 2 Android(一加 13)· iOSiPhone 16 M3(·M4 可选) ④ 三端渲染一致;⑤ 两台移动设备性能 / 生命周期 三设备 bring-up 报告 + 性能留档

关键澄清Godot 在 macOS 上渲染一个蒙皮 gr2 几乎不可能失败Phase 1 的价值是把平台无关的 GDExtension 工程(占工程量大头)做完并确认视觉保真度可达。bgfx 自研引擎方案已于 2026-08-29 停止开发,Godot 是唯一在研路线;本项目自用、不对外发布,没有"押哪条路线"的产品决策。Phase 2 只剩"三台目标设备(Mac / 一加 13 / iPhone 16)上能不能跑 + 性能够不够自己用"。

进入 Phase 2 的前置:M2.5 门禁通过、中期评审确认桥接层与观感可接受即可推进。三台目标设备都是现代硬件,全程不涉及 GLES3 / Compatibility 渲染器,不做中低端 / 老机器。


01 · 目标与判定标准

Phase 1 要证明的三件事(macOS

  1. gr2 → Godot 场景对象libgr2 读出的骨架 / 蒙皮网格 / 权重能否正确映射到 Skeleton3D + ArrayMesh + Skin,覆盖多种骨架(不止 warrior)。
  2. 动画正确 — 每帧从 libgr2::sample_pose 驱动 Skeleton3D,结果与 bgfx demo / Granny oracle 逐帧一致;跨文件 retarget、motion event 成立。
  3. 观感可还原 — 多 texture-stage 材质、alpha test、顶点色、additive 混合、fog、方向光阴影在 Godot 里做出来,与原客户端目视接近。

Phase 2 要证明的两件事(移动端,本轮不做)

  1. 三端一致 — 同一 GDExtension + Godot 工程在 iPhone 16Metal+ 一加 13Vulkan)渲染与 Mac 一致。
  2. 性能 / 生命周期够自用 — 两台设备单角色 / 多角色帧率可接受(旗舰基线,非发布门槛),后台 / 恢复稳,Godot 节点开销可控。

明确排除(两个阶段都不做)

⚠️ 本清单已失效(2026-09-08 复核)。 下列 9 项中 8 项后来都做了 —— POC 判定通过后项目 继续做成了完整客户端,范围扩张是有意的(SHINSOO-WORLD-RENDERING.md 的「定位」一节最早 记录了 UI 这一条)。逐项现状:

原「不做」项 现状 落点
SpeedTree 植被 🟡 已做 proxy formats/spt.cppBACKLOG E10
地形(Metin2 户外地图) 已做 Metin2World + formats/terrain_mesh.cppBACKLOG E8/E11/E12
UI / Python 脚本层 已做 project/ui/*uiscript 装载器 + 多个 1:1 窗口移植)
eterpack 已做 mtpack + packtoolBACKLOG G1
GPU 蒙皮优化 已做 MTGODOT_GPUSKIN=1m2_material SRC_SKIN
LOD 策略 已做 lod_distances + crossfadeBACKLOG C9
多角色 AI 仍不做 ——
网络 已做 mtnetm2dev + 40250 classic 双后端)
玩法 大量已做 CLIENT-GAP.md / CLIENT-ROADMAP.md P0P10

SpeedTree 植被、地形(Metin2 户外地图)、UI / Python 脚本层、eterpackPhase 1 用散文件)、GPU 蒙皮优化、LOD 策略、多角色 AI、网络、玩法。

地形与 .mse 特效在 Phase 1 也不做,但 M2.5 会做通用 ShaderMaterial + 混合模式的地基,为后续正式移植时的地形 / 特效渲染铺路。

判定口径

  • M2.5 门禁通过 + 中期评审"可接受" = 推进 Phase 2。中期评审已判定桥接层工作量与观感均可接受(MIDREVIEW.md);bgfx route 已停,无「转回」分支。
  • Phase 2 若撞上方案性死路(自写蒙皮着色器在 iPhone 16 / 一加 13 上跑不出、Godot 节点开销在自用规模下就卡)——记录清楚、就地想办法(回落 CPU LBS / RenderingServer 直调 / uniform 传骨骼),不再有另一条引擎路线兜底。
  • Phase 2 末交付:三设备 bring-up + 性能留档报告(自用参考,不做对外选型结论)。

与 bgfx route 的关系(历史对照,bgfx route 已于 2026-08-29 停止开发)

bgfx routePLAN.md Godot route(本文件)
渲染器 自研(bgfx 薄封装 + .sc 着色器) Godot 内置渲染器
平台壳 / 输入 / 音频 / 打包 自己拼(SDL3 / 薄壳 + 各库) Godot 全包 + 编辑器
gr2 解析 libgr2 libgr2(同一份)
动画运行时 自研(复用 EterGrnLib 逻辑) 映射到 Skeleton3D / AnimationMixer
阴影 / 环境 / sky 自研 Godot 内置(M2.5 直接用)
长期 自己养一个引擎 跟随 Godot 版本(GDExtension ABI 绑 minor

libgr2 在两条路里都是核心,完整复用。


02 · 架构总览

metin2-client/            # 建仓时叫 mtgodot-poc,后更名
  extension/                  GDExtensionC++godot-cpp 4.7
    src/
      register_types.cpp      注册 Metin2Model / Metin2AnimPlayer
      metin2_model.{h,cpp}    load_gr2 → Skeleton3D + ArrayMesh + Skin + material
      metin2_anim.{h,cpp}     每帧 libgr2::sample_pose → Skeleton3D bone pose;跨文件 retargetmotion event
      gr2_bridge.{h,cpp}      libgr2 POD 视图 → Godot 数组打包;basis + 单位换算(集中一处)
      dds_loader.{h,cpp}      DDS → Godot Image(散文件路径用;res:// 里的 .dds 交 Godot 原生导入)
      m2_material.{h,cpp}     texture-stage 描述 → ShaderMaterialM2.5
    (libgr2 / formats 在仓库根,顶层 CMake add_subdirectory 进来)
    SConstruct / CMakeLists   godot-cpp 构建(Phase 1 只出 macOS arm64
  project/                    Godot 4.7.1 demo 工程
    main.tscn                 orbit 相机 + DirectionalLight3D(+shadow) + WorldEnvironment(sky) + Metin2Model
    main.gd                   加载资产、切模型 / 动画、截图、性能 HUD
    assets/                   warrior + 另 2 种骨架的 gr2/dds
      .gdignore               ← 让 Godot 不去 import .gr2(见下)
    export_presets.cfg        macOSPhase 1
  test/
    golden/                   godot-macos-*.png
    compare.py                与 test/bgfx-reference/ 参考截图 + oracle 对拍
  docs/
    GODOT-POC-PLAN.md         本文件
    steps/                    按需拆

分层(Phase 1

内容
平台 / 窗口 / 输入 / 打包 GodotmacOS
渲染器 Godot 内置 Forward+macOS / Metal
资源运行时 Metin2Model GDExtensiongr2 → Skeleton3D / ArrayMesh / Skin / ShaderMaterial
动画 每帧 libgr2::sample_poseSkeleton3DB 方案);A/B 决策推迟到 Phase 2(Mac 上信号不足),M2 只做一次 50 角色压力采样留档
解析 libgr2(复用) · formats/msa/msm,复用) · DDS
数学 / 坐标 Godot Transform3D / Basisgr2 art-tool basis → Godot 右手 Y-up + 单位缩放,在 gr2_bridge 一次性处理,约定见 §03

两个实操约定(Phase 1 T1 前定死,写进 gr2_bridge 注释)

  • .gr2 不进 import 流程project/assets/.gdignore.gr2Metin2Model 在运行时用绝对路径 / user:// 直接读;.dds 可留在 res:// 交 Godot 原生导入,或也走运行时 dds_loader(二选一,T1.3 决定并记录)。
  • 单位缩放:定 M2_TO_GODOT = 0.01Metin2 约 100 unit ≈ 1 Godot m),相机 near/far、DirectionalLight3D 阴影范围按此设。若与资产实测不符,在 T1.1 调整并记录。

03 · 技术选型

选择 理由
引擎版本 Godot 4.7.1 stable(本机已装),锁死不随手升 GDExtension ABI 绑 minor;升级作独立任务
扩展机制 godot-cpp 101ae38034304346a46ea9ea84ae156d3e860496GDExtension(非模块编译) gitlink 精确锁定,目标 API 4.7;升级作独立任务
构建工具 godot-cppCMake 路径(本机已有 cmake;不装 SCons)或 brew install scons 二选一 Phase 1 只出 macOS arm64,摩擦最小
gr2 解析 xrender-poc/libgr2 静态库嵌入 extension 与 bgfx route 同一份,已过 9166 fuzz + oracle
动画方案 B(每帧写骨骼)A(烘 Animation决策推迟到 Phase 2 B 直接复用 libgr2 采样、最保真;A 的动机(多角色 CPU)在 Mac 上压不出来
骨骼权重 ArrayMesh 4 权重优先;>4 影响则 ARRAY_FLAG_USE_8_BONE_WEIGHTS M1 T1.2 早验,三种骨架都查
贴图 见 §02 实操约定(.dds 原生导入 vs 运行时 dds_loaderT1.3 定) 两条都留
材质 自定义 ShaderMateriallight() 自定义着色贴 Metin2 观感);M1 先 StandardMaterial3D 上屏,M2.5 换 多 stage 只做近似,列差距清单
渲染器 Forward+ / Mobile renderer 三台目标设备(Mac / 一加 13 / iPhone 16)都是现代硬件,全程不涉及 Compatibility(GLES3)
阴影 / sky Godot 内置 DirectionalLight3D shadow + WorldEnvironment procedural skyM2.5 接入 成本近零,Mac 观感必要
资产来源 assets/warrior + 另 2 种骨架 的 gr2/dds 到 project/assets/,散文件 不接 eterpackPhase 2 / M4
真值源 xrender-poc/oracle golden + bgfx demo 同机位 / pose / t 截图 复用现成对拍基建
仓库 新建 mtgodot-poc/libgr2 / formats submodule 指向 xrender-poc 隔离,不污染 bgfx route

04 · 里程碑

M0' · 脚手架(macOS12 天)

目标GDExtension 骨架 + libgr2 集成 + Godot 工程能跑,仅 macOS。

任务 完成判据
T0.1 godot-cpp 4.7 GDExtension 骨架,注册空节点 Metin2Model(继承 Node3D Godot 4.7.1 编辑器里能添加该节点、无报错
T0.2 构建集成 libgr2 静态库(CMake 或 SCons),仅 macOS arm64 libgr2 符号进 extension.dylib 加载成功
T0.3 Godot 工程骨架:main.tscnorbit 相机 + DirectionalLight3D + WorldEnvironment + 空 Metin2Model),main.gdorbit 控制 + 截图键) 编辑器运行出带 sky 的场景 + 一个 cube,鼠标可轨道
T0.4 project/assets/.gdignoreexport_presets.cfg 加 macOS preset 导出一次 macOS .app,空场景能跑

门禁 M0'macOS 上跑起「Godot 场景 + sky + cube + orbit 相机」,导出的 .app 也能跑。


M1 · 静态渲染(11.5 周)

目标warrior + 另 2 种骨架的 bind pose + 贴图在 Godot 里正确显示,多部件组装。

对标 reference/steps/M1-static-render.md T2T5。

任务 完成判据
T1.1 gr2_bridgelibgr2::SkeletonSkeleton3Dbone 名 / parent / rest Transform3D);basis + 单位缩放在此处理,约定写进注释 骨架层级树与 gr2dump --members 一致;三种骨架的骨骼数都正确
T1.2 libgr2::MeshArrayMeshARRAY_VERTEX/NORMAL/TANGENT/TEX_UV/BONES/WEIGHTS+ Skinbind 矩阵);处理 >4 权重 白模轮廓 = Blender 里同模型;无破面;三种骨架都过
T1.3 贴图路径决策(.dds 原生导入 vs 运行时 dds_loader),实现选定方案;warrior 贴图(实测 512×512 DXT3 5mip UV 无错位 / 无镜像;决策写进 extension/README.md该文件未产出2026-09-08 复核;决策实际记录在 MIDREVIEW.md §3「贴图」与 extension/src/dxt.cpp 注释里)
T1.4 材质:StandardMaterial3Dalbedo 贴图 + unshaded 先看轮廓),可切白模 贴图目视正确
T1.5 多部件(body / weapon / hair)组装,武器挂 BoneAttachment3D 部件数正确、武器跟手骨
T1.6 test/compare.py:与 bgfx demo 同机位截图 几何一致(允许色彩空间 / 光照差异)

门禁 M1warrior + 2 种骨架 bind pose 下与 bgfx demo 同机位截图几何像素级接近;顶点数、部件数、骨骼数与 oracle dump 一致。


M2 · 骨骼动画(1.52 周)

目标:从 GDExtension 每帧驱动 Skeleton3D 播动画,含跨文件 retarget 与 motion event。

对标 reference/steps/M2-anim-skinning.md

任务 完成判据
T2.1 Metin2AnimPlayer_processlibgr2::sample_pose(t) → 写 Skeleton3D 每骨 local Transform3D 单个动画连续播放、不抖
T2.2 跨文件 retarget:骨架 gr2 + 独立动画 gr2 / .msa 按骨名对齐(必要时 RetargetModifier3D / 骨名映射表) warrior 骨架播 dance_1(独立文件)姿势正确
T2.3 motion event.msa/.msm 里的帧事件(放音 / 特效锚点 / 震屏)解析并派发(Phase 1 只需回调打点,不接实际特效) 事件在正确帧触发,日志可见
T2.4 main.gd:idle + 一个动作,按键 / HUD 按钮切换 切换无爆姿势
T2.5 逐帧对拍:同 tSkeleton3D 世界骨骼矩阵 vs bgfx demo / oracle 差值在坐标系 / 单位换算误差内(沿用 M2 的 ~6.5e-5 量级口径);全程无 NaN
T2.6 全量采样自检:181 个 warrior 动画逐个 load + sample 0 崩溃、0 NaN
T2.7 留档:50 角色同播动画的帧时间 / _process 耗时采样(不作门禁,给 Phase 2 A/B 决策用) 数据写进 test/godot-macos-stress.json

门禁 M2:181 动画全部加载采样无 NaN;选定动作与 bgfx demo 同 t 视觉一致、数值在换算误差内;motion event 触发帧正确。


M2.5 · 材质与观感保真(1–1.5 周)★ Phase 1 的核心门禁

目标:把 Metin2 的固定管线材质在 ShaderMaterial 里近似出来,让 Mac 版渲染"看起来做好了"。

任务 完成判据
T2.5.1 m2_materialMetin2 材质描述(texture-stage op / arg / alpha op)→ 自定义 ShaderMaterialGodot shading languagelight() 自定义) 单 stage MODULATE(TEXTURE, DIFFUSE) = tex * vertex_color 与 bgfx demo texture_stage.sh 输出一致
T2.5.2 多 stage 近似:MODULATE2X / ADD / BLENDDIFFUSEALPHA 等常见组合 warrior 全套贴图正确显示,与原客户端目视接近
T2.5.3 alpha testD3DCMP_*+ alpha blend + additive(装备发光) 半透明 / 发光部件正确,排序无明显错误
T2.5.4 顶点色 + fog(线性 / exp2 与 bgfx demo 对拍一致
T2.5.5 接 Godot DirectionalLight3D 阴影 + WorldEnvironmentprocedural sky + ambient 角色有投影、受环境光;整体画面完整
T2.5.6 差距清单:列出无法 1:1 还原的项(排序 corner case、特定 blend op、mip / 各向异性差异) 写进中期评审报告

门禁 M2.5:warrior 完整着装 + 动画,在 Godot 里与原客户端 / bgfx demo 目视接近(结构化对比 + 直方图,不做像素比);差距清单里没有"方案性死路"项。


M3 ·(Phase 2,本轮不做)Android + iOS bring-up + 性能

一加 13Vulkan+ iPhone 16Metal)真机跑起来、三端一致、性能留档、生命周期。iOS 需把 GDExtension 按 arm64 静态库编出来(链进 app 二进制)。不涉及 Compatibility 渲染器。详见后续 steps/M3-mobile.md(届时再写)。

M4 ·(Phase 2 可选拉伸)

接真实 eterpack、试水一个 .mse 特效、多 texture-stage 精确对拍。


05 · 工作量(Phase 1macOS

里程碑 单人 2 人并行
M0' 12 天 1 天
M1 11.5 周 1 周(网格 / 骨架分工)
M2 1.52 周 11.5 周(动画 / 对拍分工)
M2.5 11.5 周 1 周(shader / 材质映射分工)
Phase 1 合计 ≈ 3.55 周 ≈ 2.53.5 周

前置依赖:xrender-poclibgr2(已完成)、oracle goldenM2 对拍要)、bgfx demoM1/M2/M2.5 截图对拍要,已可跑)、Godot 4.7.1 export templates(需在编辑器内下载)。


06 · 风险登记册

Phase 1macOS

风险 触发信号 缓解 / 退路
godot-cpp + libgr2 构建集成摩擦 M0' 链接 / 加载失败 只出 macOS arm64,摩擦面最小;CMake 路径优先,SCons 备选
.gr2 被 Godot import 流程扫到报错 打开工程时一堆 import 错误 project/assets/.gdignore.gr2 走运行时绝对路径 / user://T1 前定死
gr2 basis / 单位换算到 Godot(左手 → 右手 Y-up + 缩放) M1 模型躺 / 镜像 / 骨骼反向 / 大小离谱 gr2_bridge 一次性处理,定 M2_TO_GODOT,用朝向明确资产手校,写注释
Skeleton3D 骨骼数上限 / 8 权重路径行为 M1 T1.2 蒙皮爆开 / 部位错位 三种骨架都查 gr2dump>4 权重走 8-bone flag
多 stage 固定管线材质无法在 ShaderMaterial 近似到可接受 M2.5 T2.5.2/3 关键装备观感明显错 这是 Phase 1 主要方案性风险;差距清单区分"可延期"vs"死路"。中期评审已判定为可延期(观感打磨,见 MIDREVIEW.md);bgfx route 已停,无「转回」分支
半透明 / additive 排序 corner case M2.5 T2.5.3 发光部件穿插 记入差距清单;Godot 的 render_priority / depth_draw 调,不追求 100%
motion event 语义(.msa/.msm 帧事件类型) M2 T2.3 事件类型没覆盖全 Phase 1 只需打点回调,实际特效 Phase 2;未覆盖类型列清单

Phase 2(移动端,本轮不激活,仅登记)

风险 缓解 / 退路
每帧 CPU LBS 全量重建 mesh 的成本(多角色) MTGODOT_GPUSKIN=1 自写蒙皮着色器(已实现);多线程构建 + eterpack 共享资产
自写蒙皮着色器(texelFetch + RGBAF + BONE_INDICES)在 iPhone 16 Metal / 一加 13 Vulkan 上的行为 Phase 2 各跑一次;出问题回落 CPU LBS 或改 uniform 数组传骨骼。三台都是现代设备,无 GLES3 约束
Godot 节点开销(大场景规模) MultiMesh / RenderingServer 直调兜底
GDExtension ABI 绑 Godot minor 锁 4.7.1,升级作独立任务
iOSGDExtension 须静态链接进 app 二进制(libgr2 出 iOS arm64 .a),签名 / 模板脾气大 自用免费 provisioning 够用;预留 23 天 bring-up

07 · 验证方法论

  • 真值源xrender-poc/oracle 的 Granny golden 数据 + xrender-poc bgfx demo(同机位 / pose / t 截图与数值 dump,Metal 后端在同一台 Mac 上跑)。
  • 每个门禁test/golden/godot-macos-<case>.png + 骨骼矩阵 / 顶点 dump,跑 test/compare.py 与 bgfx route 对拍。
  • 资产集xrender-poc/test/assets.list 里的 warrior 相关文件 + 另选 2 种骨架(记入本仓库 test/assets.list)。
  • 对拍容差:几何 / 骨骼矩阵按坐标系 + 单位换算误差内严格比;颜色 / 光照因渲染器不同不做像素比,只做结构化目视 + 直方图。

08 · 交付物

Phase 1(本轮)

产物 位置
mtgodot-poc/ 仓库:GDExtension 源 + Godot 4.7.1 demo 工程 新仓库
macOS 导出配置 project/export_presets.cfg
与 bgfx demo 的几何 / 动画对拍报告 test/godot-snapshot.json 未产出2026-09-08 复核)。实际落地的是 test/compare.py + test/compare-report.json(进程 / 截图 / 结构硬门禁),与 bgfx 的比对停留在 test/bgfx-reference/ 的人工交叉核对
材质差距清单 中期评审报告内
50 角色压力采样(供 Phase 2 A/B 决策) test/godot-macos-stress.json
中期评审报告 桥接层工作量实测 + 观感对比截图 + 剩余风险 + "是否进入 Phase 2"建议

Phase 2(后续)

产物
iOS .ipaiPhone 16+ Android APK(一加 13)+ 两台真机性能 / 生命周期报告
三设备 bring-up 报告:三端渲染一致性截图 + 各设备帧率留档(自用参考,不做对外选型结论)

选型变更记录

  • 2026-08-29 · 设备范围定死(自用):目标 = MacmacOS / Metal+ 一加 13Android arm64 / Vulkan+ iPhone 16iOS arm64 / Metal),各一台。取消对外 go/no-go 门禁(bgfx route 已停、项目自用);Phase 2 收敛为「三设备各一次 bring-up + 性能留档」。全程不涉及 GLES3 / Compatibility 渲染器,不做中低端 / 老机器。SHINSOO 的 W0→W1+ 因此无外部门禁。
  • 2026-08-29 · 范围收敛为 Phase 1 = macOS only;新增 M2.5 材质与观感保真 作为 Phase 1 核心门禁;动画 A/B 决策推迟到 Phase 2Godot 版本钉死 4.7.1 / godot-cpp 4.7。
  • 2026-08-29 · M1 T1.3:贴图走 运行时 dds_loadersrc/dxt.cpp,端口自 xrender-poc)。理由:Godot 4 的 Image.load() 不支持 .dds,且资产从 res:// 外的绝对路径加载(.gr2.gdignore 同理)。DXT1/3/5 + BGRA8level 0 + generate_mipmaps()
  • 2026-08-29 · 动画方案B 方案(每帧 gr2::sample_pose 驱动)。两条蒙皮路径,都用 libgr2 的 skin 矩阵完整仿射(shear 保留):默认 CPU LBSmetin2_anim.cppMetin2Model::cpu_skin,每帧重建 ArrayMesh);MTGODOT_GPUSKIN=1自写蒙皮顶点着色器m2_material SRC_SKIN,逐骨 4×3 矩阵存 RGBAF 纹理,Metin2Model::gpu_skin 每帧更新,绕过 Skeleton3D)。原因:Godot 内置 GPU 蒙皮 / set_bone_pose 会正交化骨骼矩阵、丢掉 Granny 烘在 rig 骨(bone_front_*/Bone_shoulder_*warrior 7 / sura 16)上的 sheartools/anim_probe 定位,非 libgr2 —— world[] 对拍 Granny ≤4.1e-5)。旧 Skeleton3D::set_bone_pose 路径已删。A 方案(烘 Animation)走 Skeleton3D 骨骼、同样丢 shear,不用。
  • 2026-08-29 · 坐标/单位gr2_to_godot() = gr2 行主序 Mat4 的 4×4 转置 → Godot Transform3DZ-up cm → Y-up mrotate(-90°,X) + scale(0.01))放在 Metin2Model 节点自身 transformmake_conv)。warrior/warrior_lord/assassin/shaman_lord 实测 flip_z=falseflip_winding=falseunit_scale=0.01 正立、朝 +Z、无镜像。

M2.5 T2.5.6 — 材质无法 1:1 还原 / 待办项清单

不再单独维护 —— 全部并入 BACKLOG.md B 段(B1B11)。下表为历史快照。

现状 影响 出路
libgr2 POD API 不暴露材质数据 —— 只有 material_count/texture_count,无材质名、无贴图文件名、无 texture-stage op、无 D3DBLEND_*/alpha-test 标志 贴图靠文件名约定 + 目录大小写不敏感扫描_resolve_texture);blend 靠表面名关键字启发式guess_blendhair→alpha-test、cape/skirt→alpha、effect/glow→add,其余 opaque warrior 5/5、assassin 17/17、shaman 1/1 表面命中贴图,但多材质槽 → 具体贴图/混合的精确映射做不到;换皮/多贴图变体、精确 alpha-test 阈值、MODULATE2X/ADDSIGNED 等 stage op 无法复现 需要给 libgr2 加材质 API(新文件 gr2_material.cpp,走类型树取 Materials[].Name + Maps[].Texture.FromFileName + shader/blend hint)。这也正是 xrender-poc M1 T5「多 stage 材质对拍待 oracle」的同一缺口,两条 route 共用修法。
顶点色 gr2::Vertex POD 无 color 字段;shader 已留 COLOR 通道,默认白 Metin2 PC 模型基本不用顶点色,影响小;特效/地形会用 libgr2 若暴露则 build_meshARRAY_COLOR
TriGroup.material_index 未接线 已做(2026-08-29 gr2_bridge::build_parts() 把一个 gr2 mesh 按 tri_groups 拆成 N 个 RenderPart → N 个 Godot surface,贴图取 Mesh::material_textures[matidx]mesh-local,非全局 Materials[])。GPU 和 CPU 蒙皮路径都走 RenderPart
ShaderMaterial 静态 Shader 退出泄漏 shader_for() 用 function-static Ref<Shader>Godot 退出时报 "1 shader never freed" 仅退出时一条 warning,无功能影响 改成每材质自持 Shader,或注册 cleanup
alpha 排序 corner case 半透明/additive 用 render_priority 粗排,未做逐三角/OIT 多层半透明部件可能穿插 记录,不追求 100%Phase 2 M2.5 打磨)
法线变换 CPU 与 GPUSRC_SKIN 着色器)两条路径都用混合矩阵的上 3×3、不逆转置 —— 与 Granny runtime 一致(见 docs/reference/steps/M2-anim-skinning.md)。非均匀缩放骨骼下这是 Granny 自己的近似,我们与之一致。 已一致