逐区块重建:把场景资产完整、正确地铺进引擎

修订说明(2026-09-30):本文记录 2026-06-30 的阶段工作。早期代理方案、样本测量和原版算法证据已重新区分,未完成事项按当时验证范围理解。后续进展见高度图还原与POI、Stamp 和植被岩石布局。

这是「AI 协作做游戏」系列里关于资产逆向的第三站。上一篇把一张关卡从二进制里读懂了——单个区块的摆放清单怎么解析、坐标怎么对上。这一篇要回答下一个问题:读懂之后,怎么把它真正、完整、正确地铺进引擎。

听起来像是「照着清单摆一遍」就行,但真正动手才发现:清单里提了名却没展开的内容、没提名却混进来的东西、以及一批根本不该出现在画面里的辅助体——这三块,才是「读懂」和「铺成」之间真正的距离。

三态约定(全文一以贯之):

– 🟢 实测:从静态解包数据、文件结构、几何不变量直接可验证,或经组装后对账核实。

– 🟡 推断:从数据现象合理归纳,但没有运行时直接证据。

– ⚫ 黑盒:涉及运行时算法、网络同步、加密数据,既未逆向也未抓包——不下结论。

匿名化口径:泛指「某第三人称合作射击游戏」,不点工具名、不点具体资源名;通用技术词(引擎、LOD、材质、贴图、四元数)照常使用。


引子:清单「看着齐全」,铺进去才发现不齐

上一篇结束在一个很干净的状态:一张关卡 = 一份摆放清单。每个物件带着自己的位置、旋转、缩放,区块与区块之间靠地形块拼接,坐标没有加密,结构也交叉验证过——读起来一切都对。

但「读懂一份清单」和「按这份清单把场景立起来」是两件事。

当我真的拿这份清单去引擎里逐个摆放,问题随即显现:有些内容清单里列了字段,却从未被展开,摆出来的场景是空的;有些东西清单里没有单独列出,却跟着混了进来;还有一批带着网格、形似物件的东西,铺出来是穿帮的方块和平面——它们本不该被看见。

于是这一篇的主线,是把「读懂」推进到「铺成」,逐个填掉中间这三块缺口:

  1. 植被 —— 清单里提了名,整类却没展开;
  2. 嵌套预制件 —— 上一篇当「引用」列出,但只到表层,里层套着的内容会丢;
  3. 体积盒 —— 没提名却混进来的辅助体,得识别出来、跳过。

填完这三块,再把全部区块一次性组装成一套可重建的场景,最后划清两类边界:哪些能拼对,哪些拼不出。

还差三块

在往下走之前,先说清这一篇特有的风险。上一篇的风险是「别把静态规律推成运行时机制」;而这一篇是工程实战,主体是已经动手做完、可以验证的步骤,所以它的风险不在「推断运行时」,而在「将未经验证的步骤判定为已完成」。因此后文凡是写「导入完成」「修复到位」「全部铺好」,都以对账数据为凭——失败计数、直方图复核、抽样预览确认——而非「理应如此」。


一、数据从哪来:先划清证据边界

和上一篇一致,这一篇的全部结论来自对游戏静态数据的解包与重建:

  • 资产文件(几何、材质、贴图)的结构与内容;
  • 区块的摆放清单(物件 / 预制件 / 植被 / 各类覆盖);
  • 把这些资产真正导入引擎、组装成场景后的对账结果。

不包含:运行时内存抓取、可执行体反编译、网络协议分析。所以凡是涉及「每局怎么选区块、全局怎么布局、运行时怎么实例化」的部分,一律落在黑盒里,不当作事实。

带着这条边界,开始填第一块缺口。


二、第一块:植被是独立的第三套挂载

区块上挂着的内容,有三套并列的体系:物件列表、预制件引用、以及植被列表。前两套上一篇讲过;植被是被整个跳过的第三套。

🟢 实测:植被不是贴在地面的「假植被」(一张带草木图案的贴图),而是有完整几何的真模型。每一棵在清单里带着自己的路径、位置、以及一组「风偏范围」(注意:是随风摆动的幅度,不是朝向)。

它和物件、预制件的关键区别在于挂载方式最简单:

  • 🟢 植被只挂在区块顶层——预制件的数据结构里根本没有植被这个字段(源码层面确认)。
  • 所以补植被不需要像预制件那样做父子嵌套展开,直接读区块顶层的植被列表即可。
植被的三套挂载与 LOD 链

一棵植被 = 一条 LOD 链

植被最有意思的地方,是每一棵都自带一条细节层级(LOD)链:同一个文件里存了好几级精度,引擎按距离切换——近处用满细节,远处用简化版,最远处退化成一张面片。

🟢 实测(某棵作为例子):近景级约 2.7 万顶点,往下逐级递减,到最远的面片级只剩约 50 个顶点——一张草木轮廓的贴片,用来在远处省渲染开销。各棵植被的级数并不统一:多数到第三或第四级,少数高细节的一直到第五级。

这条 LOD 链是导入时必须保住的。如果导入过程把它压成单级(只留近景几何),满屏植被在远处会用满细节渲染,直接拖垮帧率。所以导入要保留多级节点结构,不能合并。

导入引擎后的一棵植被

放进引擎后,一片植被散布在地形上的样子——是带几何、带阴影的真模型,不是贴在地面的图:

植被散布在地形上

🟢 实测:全部数千棵植被的分布做过精确对账,没有一棵落在已知区块范围之外。也就是说,「摆放」是确定的、可重建的。难点不在摆放,在下一节的材质。


三、植被材质的两个陷阱:都是「形似而实非」

这一节是整篇最容易出错的地方。植被的几何导入顺利,但材质有两个陷阱,都需借助引擎源码或几何不变量才能确证,仅凭直觉处理必然出错。

材质的两个陷阱

陷阱一:材质名具有误导性

症状:导入后树干显示成了树叶的材质——材质槽位绑错了。

最自然的做法是「按名字分配」:哪个材质叫「面片」,就给最远的面片级;哪个叫「图集」,就给主体。

🟢 实测:恰好相反。名字叫「面片」的材质,实际用在近~中景的主体;名字叫「图集」的,才用在最远的面片级。材质名和实际用途并不对应。

更麻烦的是,导出植被时有两个不同的导出通道,它们彼此冲突:一个通道把「几何 ↔ 材质」的对应关系写反了,另一个是正确的。引擎忠实地按那个写反的通道导入,槽位自然全部绑错。

🟢 正解 = 三角面数指纹:三角面数是几何不变量,不随导出格式改变。以那个「对的」导出通道为权威,记录每一块几何的三角面数对应哪个材质;再回到引擎里,按每个槽位几何的三角面数,反查它该用哪个材质,重新赋值。

🟢 实测:上百棵多材质植被里,约百棵受影响。按三角面数指纹重新赋槽后,逐棵复核,错位归零——而且只动槽位映射,不碰几何、不碰 LOD。

陷阱二:采样类型警告,改错了地方

症状:母材质反复报「采样类型不对」的警告,改了三轮都没用。

🟡→🟢 错误方向(前三轮):以为是采样节点上的「类型设置」错了,于是反复改它(法线→线性→遮罩……)。没用——因为警告判定的根本不是这个设置本身。

🟢 真规则(引擎源码坐实):警告的触发条件是「节点的类型设置 ≠ 它绑定的那张默认贴图的实际类型」。而默认贴图一直是一张普通彩色图,引擎永远把它算作「彩色」类型——所以无论把节点类型设成什么,都不等于「彩色」,警告永远在。

根因不在「设的类型」,在「绑的默认贴图类型不匹配」。

🟢 正解 = 给每个纹理参数配一张类型匹配的默认贴图:彩色参数配彩色默认图、法线参数配平面法线图、遮罩参数配一张自建的遮罩默认图。三者匹配,警告归零。

比「消警告」更重要的事

警告只是表面。真正会静默出错的,是贴图压缩设置。

🟢 实测:导入贴图时如果不按用途设压缩,法线贴图和遮罩贴图会被当成普通彩色图处理——法线会被错误地按 sRGB 解码(凹凸方向算错),遮罩数值会偏移(粗糙度 / 金属度 / 环境光遮蔽的响应全错)。画面不会报错,但就是不对。所以:基础色用普通彩色 + sRGB;法线用法线压缩 + 关 sRGB;遮罩用遮罩压缩 + 关 sRGB。设对之后,贴图自身类型也对了,母材质的采样警告反而自然消失。

下图是一棵多材质植被修对后的样子——右侧材质槽位逐个绑上正确的实例,树干是树皮、叶子是叶材质,显示正常:

材质槽位修对后的多材质植被

四、第二块:嵌套预制件,不递归就丢内容

预制件是「一组物件打包成可复用模块」。上一篇把它当「引用」列出来了——但只到表层。真正动手才发现:预制件里还能套预制件。

嵌套预制件递归展开

问题:只展开一层,里层就丢了

如果展开预制件时,碰到「内层还套着一个预制件」就停手,那么里层那一整支内容全部丢失——场景里会出现无法解释的「空洞」。

🟢 解法 = 递归展开,一直拆到底。关键在每下沉一层,坐标要做一次合成:

子物件的世界变换 = 父变换 × 子局部变换(旋转部分是逐层的四元数相乘)

带着父的变换一层层往下传,直到最底层的叶子物件,里层内容一个都不丢。

🟢 实测:补回递归后,数百个可展开的预制件全部摊开,子物件总数对账一致。

展开后是什么形态

🟢 实测(一个容易误解的点):预制件展开后,在引擎里没有独立资产——它被完全摊平成区块里一个个独立的摆放物,和直接摆放的物件不可区分。而且子物件与普通物件共用同一个去重资产库,按资产哈希复用,相同的模型不会重复存。抽查某个区块,两百多个摆放物全是同型结构,无法分辨谁来自预制件、谁是直接摆放。

下图右侧是一个区块展开后的物件列表——全是同一种独立摆放物,一长串排下来,看不出层级,正是「预制件摊平、与直接物件不可区分」的样子:

区块里的物件全部摊平成独立摆放物

一个要撤回的异常

🟡 推断:有一个预制件展开后,几十个物件全堆在原点(局部变换全为零)。从这个「全零变换」的现象判断,它不是用来摆放的,而是一张「变体登记表」型的容器——把一族变体登记在一起,并非真要摆在场上。如果机械地把它也铺出来,就是一片互相穿插的废几何。识别出来后跳过、不落地。

这正是这一块的要点:递归一层都不能少,但「展开」不等于「全都铺」。展开是手段,判断「该不该落地」才是关键。

关于运行时引擎具体怎么实例化预制件——⚫ 黑盒,不在本篇证据范围,不下结论。


五、第三块:体积盒,没提名却混进来的「不该铺」

前两块都是「补漏」——补回提了名却没展开的内容。这一块相反,是「剔除」:把本不属于画面、却混进清单的东西挑出来。

🟢 实测:引擎里有一类辅助体——碰撞盒、导航裁剪 / 范围、触发区、反射探针、混响区、击杀体,以及各种基本几何体和功能挂点。它们的作用是「圈一块范围」,本身不该被看见。

问题在于:它们也带着网格。在摆放清单里,它们和真物件长得一模一样。照搬就会在场景里铺出一堆方块、平面、柱体,全是穿帮。

体积盒识别与剔除

怎么识别:双判据

单靠一个判据会出错,得两个一起用:

  • 🟢 判据①:看节点名。这类体的渲染节点全是「基本体 / 功能体」的命名(方块 / 平面 / 柱体 / 裁剪 / 范围 / 触发 / 击杀……)。关键排除:带真实骨骼或碰撞组件的,是真件,不能误判。有源文件的件靠节点名直接判定,覆盖了两千多件。
  • 🟢 判据②:看几何形态。无源文件、读不到节点名的件,看包围盒:某个轴极度拉伸、整体又放得很大——多半是圈范围用的盒,而不是具体模型。全库逐件几何重扫,盲区为零,把这类无源件也捞了回来。

陷阱:贴花盒

🟢 实测:有一种盒,长得和体积盒一模一样,但它是真内容——往地面投贴花(弹孔 / 污渍 / 标记),用了将近一万次。如果按「像盒子」就删,满地贴花会消失。所以必须在剔除清单里显式排除它,不能单凭几何形态判定。

为什么要「一次性」补全

🟢 实测:早期的剔除清单只扫了一小批,漏网的盒又回到了场景里。于是改为全库逐件重扫,两个判据合并,名单一次补齐——漏网的盒从个位数补到十几个,涵盖基本体、平面、柱体、功能挂点等多种类型。

🟢 关键做法:体积盒不从清单里删(删了会改动原始清单结构),而是留在清单里、组装时按名单跳过。这样原始结构无损,跳过逻辑也可复核。


六、把三块填完:一次性组装,不动旧版

三块缺口填完,剩下的是把全部区块真正组装成场景。

🟢 流水线(每个区块走一遍):

  1. 基础清单 —— 物件 + 递归展开后的预制件子物件(含补回的嵌套内容);
  2. 叠加植被 —— 按坐标把每一棵摆回区块,且保住原有摆放不被覆盖;
  3. 跳过体积盒 —— 按名单在组装时跳过,清单结构不动;
  4. 落地到新目录 —— 全部区块逐个组装,按「是否含地形」分两批;原有版本零改动(生成到全新目录,旧的不碰)。
一次性铺成与两类边界

下图是一个组装好的区块在引擎里的样子——物件、建筑、植被铺在带起伏的地形上,是一整片可重建的真实场景:

组装好的一个区块场景

🟢 实测 · 对账即验收:全部区块组装,失败计数为 0;该跳过的体积盒,跳过数目与名单精确相等、一个不漏。在用户抽样预览了若干区块、确认无误之后,才放量到全量。

这里要再强调一次本篇的纪律:上面每一个「完成」,背后都有一个可核对的数字撑着——不是「应该铺好了」,是「失败 0、跳过数相等、抽样已确认」。这是把「读懂」推到「铺成」时,唯一能让自己不自欺的办法。


七、两类边界:能拼对每一块,拼不出整颗星球

走到这里,可以清楚地划出这一篇能做到的和做不到的。

🟢 能拼正确每一块

每个区块内部的所有内容——物件、递归后的预制件、植被——都能摆回正确的相对位置;材质槽位、细节层级、该剔除的体积盒,也都处理到位。

→ 单个区块及其内容,是「实测可重建」的。摆放坐标没有加密,几何 / 材质 / 层级都能从静态数据复原并落地引擎。而且——本篇所有「可重建」的结论,都以对账数字为凭,不是「理论上可以」。

⚫ 拼不出「完整一颗星球」

单个区块内的摆放变换可以读取。区块在本局世界中的选择和全局位置,当时尚未恢复;静态数据中没有找到对应记录,不能据此确认它们保存在加密数据中。

→ 全局布局与运行时组装,仍然是黑盒。这沿用上一篇那道墙:既没有逆向算法,也没有做网络检测,不下结论、不补全、不假设其实现机制。

换句话说:这一篇把「单块怎么拼对」做到了实测级;「整星球怎么成形」依旧停在黑盒——两者之间,正是上一篇那道墙。


八、总结

回到开头那个问题:读懂一份摆放清单之后,怎么把它真正立成场景?

答案是:逐个填掉「读懂」和「铺成」之间的三块缺口——补回提了名却没展开的(植被、嵌套预制件),剔掉没提名却混进来的(体积盒),再把全部区块一次性组装进一套不破坏旧版的新场景。

🟢 一句核心结论:在静态层,一张场景由「可复用资产 + 可解析的摆放清单」组成,能逐区块完整重建;⚫ 但「某一局拼成的完整星球」如何成形,仍处于运行时黑盒。

这也回应了系列一直在做的事——不是「逆向出一个游戏」,而是用一套可复用的方法,把能从静态数据确认的做扎实、做到落地引擎,同时让运行时的部分严格停在边界上。


九、AI 协作复盘

这是本系列的固定栏目:记录做这一篇时,人和 AI 具体怎么配合、哪里翻了车、人怎么补的位。

AI 帮上忙的地方:

  • 大批量的机械活。数千棵植被的提取、几百个预制件的递归展开、全库逐件的几何重扫——这些「量大、规则明确、容易出错」的活,是 AI 的主场。写探针、跑批、对账,一轮轮迭代。
  • 把坑的根因查到源码级。采样类型警告那个坑,前三轮都在改错地方;最后是回到引擎源码里把判定规则一行行读出来,才定位到「根因在默认贴图类型,不在采样设置」。AI 在「啃源码定位根因」上很有耐心。

翻车与人的补位:

  • 「材质名误导」是人 review 抓出来的。AI 一开始按材质名分配槽位,导出来树干贴成了树叶——这个错 AI 自己没发现,是人看了预览截图当场指出「这树不对」。之后才反过来定位到「两个导出通道打架、名字不可信」,改用三角面数指纹。没有人在回路里看实际渲染效果,这个错会一路滑过去。
  • 「全都铺」的倾向需要人来约束。AI 递归展开预制件时,倾向于「机械地把每个都铺出来」;那个「变体登记表」型的异常件,是靠「全零变换」的现象判断该撤回的——这种「展开 ≠ 全都铺」的判断,需要人明确给出原则,AI 才不会不加甄别地一律落地。
  • 「已完成」的判定边界靠纪律守住。批量任务最容易出现「外层包装报告完成,实际进程仍在运行」「断点续跑逻辑跳过了尚未补齐的步骤」这类虚假完成。这一篇之所以反复强调「每个完成都要有对账数据」,正是被这类问题反复教训出来的——对 AI 而言,「执行结束」与「执行正确」是两回事,必须用对账把二者绑定。

怎么解决的:把「人看渲染效果」固定进每一轮迭代(AI 出结果 → 人看预览 → 反馈),把「展开/剔除的判断原则」前置交代清楚,把「完成」一律绑定到可核对的数字。这一套配合下来,才让「读懂」真正落到了「铺成」。


*配图均为自绘信息图(白底,与正文逐条对应)。文中「完成 / 修复 / 铺好」均以对账实测为凭;凡标 ⚫ 黑盒处,均为未逆向算法或未做网络检测,不作无据推断。*

发表评论

了解 AI Native Game Development 的更多信息

立即订阅以继续阅读并访问完整档案。

继续阅读