FIELD NOTES
NOTE 03 · FROM IMAGE TO MODEL
从设定图到能进游戏的模型
让大模型直接产出 3D 角色失败之后,我把任务拆成了更窄的环节。这是那条路线的完整记录。
以下内容是开发者的个人记录,涉及内部里程碑、技术选择与失败过程。它描述的是当前状态,不是最终形态,也不构成任何发布承诺。
那条走不通的捷径
最初我希望从角色设定图直接得到可以进入游戏的模型。
这个想法看起来完全合理:设定图已经确定了造型、配色和武器;模型只是它的三维版本; 那么把图交给一个足够强的模型,让它推导出网格,应该是最短路径。
结果很快暴露出问题。
不是「生成得不好看」——生成的东西经常挺好看的。问题是:
- 结构不成立。 正视图和顶视图不是同一个物体的两个投影。
- 手部不可读。 握点在哪儿?武器是从哪只手出来的?说不清。
- 武器轮廓糊掉。 斧刃的齿列、剑的宽度、盾的厚度,全都变成了「大概是那个意思」。
- 最要命的是:它无法被验证。 我没办法对着一个语义模糊的网格说「这里错了」, 因为我说不出「这里」是哪里。而一个说不清哪里错的东西,也就没办法修。
所以我停了。不是因为模型不够强,而是因为我把任务问错了。
二、把任务拆窄
之后我把它拆成一串更窄的环节,每一步都能单独判定通过或失败:
- 固定视觉意图。 设定图(Production Sheet)是结构合同,不是参考图。 每张图要含:一个角色身份、一致的正交/多角度视图、剪影、色板、装备分离件、 部件分解和尺寸提示。每个视图必须保持同样的身体、服装、色板、手别、武器尺寸和挂点数量。
- 零成本预检。 在任何付费调用之前:单主体、同身份、同姿势、完整肢体、正确手别、 尺寸与哈希、正/侧/背与真正交顶视图的一致性审计。顶视图不一致时, 先修输入并版本化,不让生成工具替输入合同背锅。
- Meshy 只做基础几何。 image-to-3D / multi-image-to-3D,默认
should_texture=false、should_remesh=false的 topology-first 任务,一次只回答一个几何假设。 - 本地确定性派生。 网格与结构修复、比例修正、拆件、颜色绑定。
- 刚性部件绑定与动画适配。
- 导入 Godot,实机验证。
- 人工视觉审批。
第 3 步是唯一花钱的一步,也是唯一不确定的一步。其余全部是确定性的本地流程。
三、运行时为什么不用骨骼
Godot 这边有一条听起来很奇怪的硬规则:角色不用 Skeleton3D、Skin 或 BoneAttachment3D。
视觉适配器会主动拒绝带这些节点的资源。
角色是 rigid_parts:每个逻辑部件是一个合并的 ArrayMesh,共享同一个体素间距(0.019 m)。
运行时永远不加载原始 GLB——Meshy 的源 GLB 是归档件,放在 art/source/meshy/ 下,
带 .gdignore、额度账本和 SHA-256 注册表,只作为确定性派生链的输入存在。
为什么这么做?
- 体素风格的角色本来就是分块的,刚性部件在视觉上没有损失;
- 合并网格意味着 draw call 可控,20 个敌人同屏时这件事很重要;
- 最关键的是:它是可验证的。一个刚性部件要么在正确的位置,要么不在。 蒙皮权重的「稍微有点怪」是没法写进校验器的。
游戏逻辑只知道 visual_id 和动作名。它不知道模型来自哪条链、有几个部件、
用的是 Meshy 派生还是纯 Godot 编写的回退版本——后端切换是一个运行时开关的事。
四、角色比例是数字,不是感觉
批准里明确写了运行时高度比:Goblin 0.68、Swordsman 1.00、
ordinary Minotaur 1.72、Boss 2.45。
这条很重要,因为生成图里的表观比例被压缩过,而那张图对运行时尺寸没有权威。 批准显式地废止了图里的比例,只承认这组数字。
保真度是用渲染剪影 IoU 量的,阈值统一是 0.55:
| 角色 | 剪影 IoU |
| --- | --- |
| Swordsman | 0.611897 |
| Goblin | 0.600124 |
| ordinary Minotaur | 0.681249 |
| Boss | 0.560647 |
Boss 只比阈值高一点。我留着这个数字,因为它诚实地表示了「刚过」。
五、Boss 被我打回来过
邪恶牛头人的重做过程是这样的:
V4 被拒绝。 具体原因有两条,都是我在正式的 boss_roar 帧上看出来的:
解剖学左手腕/手臂有结构断裂;月牙形的斧刃不够锐利。
注意这两条的性质:它们是命名的结构缺陷,不是「我觉得不好看」。 这个区分决定了下一步走哪条路——命名缺陷可以进入修正流程, 纯审美不满可以直接 STOP,但不允许变成随机重掷。
V4 保持字节不可变的被拒历史。 它不会被删掉,也不会被覆盖。
V5 是一次追加的、只针对那两个缺陷的本地修正。
V6 重建了手腕(一段连续的宽到窄锥形护腕),并换掉了武器头: 一柄更大的、七齿六谷、双面带牛角眼部族纹样的斧。
V6 通过后进入运行时晋升。这中间我没有偷偷放宽任何阈值—— 「临界失败先修派生,不用 formal 反复试探,也不反向放宽阈值」是写进规则里的。
Goblin 和 ordinary Minotaur 的恢复过程更长:Phase A、Phase B Wave-1、Wave2 的 v2 到 v6。 最终在 Wave2-v6 上我接受了当前结果并主动叫停——不是因为它完美, 而是因为继续迭代的边际收益已经低于成本。这条停止规则也写进了文档: 再要开 v7、Phase C 或付费修正,需要一次新的、显式的重新开启。
Wave2-v6 的正式机器封存覆盖 192 个产物。运行时晋升本身没有产生任何新的网络调用、
生成任务或额度消耗——它只是把指针指过去。
六、名册上现在有谁
正式公开的只有已经确认的:剑士、吸血鬼、哥布林、牛头人、邪恶牛头人。
官网角色页上那些标着 CLASSIFIED 的剪影不是故弄玄虚。它们对应的是实际存在于仓库里、 但还没有走完审批流程的东西。在它们被正式确认之前,我不会公开名称、背景或形象, 也不会暗示当前的设计就是最终设计——因为按这个项目的历史看,它大概率不是。
七、我从这条路上学到的
AI 在「把一个定义清楚的问题做完」上非常强,在「替你定义问题」上非常弱。
我第一次失败,不是因为工具不行,而是因为我给了它一个我自己都没想清楚的任务。 当我把「给我一个能进游戏的角色」换成「从这五张一致的正交视图里,产出一个满足这些占据率约束的基础几何」, 成功率立刻变了。
另外一条,也许更重要:要为失败留出位置。 被拒绝的 V4 还在仓库里,字节不变。零 Event 的那次运行还在记录里。 如果一个流程只允许成功被留下,那它记录的就不是真实的开发过程, 而是一个事后整理出来的故事。