跳到主要内容
看完那篇 3D 图书馆的 devlog,我坐在床上把手机举了十分钟

看完那篇 3D 图书馆的 devlog,我坐在床上把手机举了十分钟

今天也没搞懂
今天也没搞懂

· 阅读约 5 分钟

九月底,睡前刷 dev.to,刷到一篇 Oniria 的开发日志。作者把 DEV 的文章搬进了一个 Three.js 的 3D 环境。

本来打算看两眼就睡的。看到一半我坐起来了。

他的做法是把文章变成图书馆里的实体书。房间对应分类,书架对应合集,书就是文章。你得走进去,找到那一排,把书拿下来,看完再放回去。

不是卡片流,是真的用脚走。

更早的版本不长这样。他说早期走的是赛博世界那一路,发光结构、高速公路、高楼,文章散在一座未来城市里。听着挺酷的。

然后他自己承认:那个环境视觉上有意思,但对他理解"文章之间到底怎么组织"这件事几乎没帮助。

这句我看了三遍。

因为我那个破项目就是这毛病。东西摆得哪都是,看着热闹,但只要问一句"为什么这个放在那边",我答不上来。我一直以为这是审美没调好,是细节还没磨完。原来这根本不是审美问题——是信息该怎么放,我压根没想过。

评论区有人提到赛博城市那版让他想起夜之城,还挺怀念;也有人说新做法让这套引擎变得可复用。炫的那版是靠装饰撑起来的,图书馆这版是靠结构。

真正让我坐起来的是后面那段。

整座图书馆没有关卡编辑器,是拿 Three.js 代码一行行搭出来的。

要摆的东西多到什么程度——墙体、书架、桌椅、地毯、植物、亭子、标识、房间入口、书排、碰撞边界、灯光。还有一项我盯着看了很久:预留但还不存在的书架空间。

给一个还没做出来的东西先在场景里留好位置。这个操作我完全没有概念。我项目里东西少到可以手改,所以从来没被逼到要想这一步。

场景里的东西靠一个叫 placeAsset 的函数摆,克隆一份已经加载好的模型模板,设好坐标、缩放、旋转,丢进场景组。真调位置还是靠改数字、保存、刷新、走进房间看一眼、再回来改。

他自己形容,这几乎就是他的关卡编辑器。

这不就是我的开发流程吗。

我挪东西就是这么挪的,改一下刷一下,来回十几趟。区别是我从来没觉得这里有什么不对,我以为新手就是该这么过日子。要是三周前的我读到这一段,大概直接划过去,觉得这算什么发现。现在我能认出来这是苦力活——但我还在干,一点没变。

他把这件事一句话写出来,我读完有点说不上来的感觉。不是学到了什么,是发现自己天天在忍的那件事,被一个陌生人准确地描述出来了。

但他没去装一个现成的关卡编辑器。

他在 Oniria 里面自己做了个小东西:人走进房间,站到想放的位置,放一个标记。标记里记标签、roomSlot、districtId、x/y/z、yaw。示例标签长这样,R1-P01。这些标记存成 Sanity 文档,刷新之后还在,下次接着用。

他说这套东西慢慢变成了调试工具、测量工具和小型关卡编辑器的混合体。

为什么不用现成的?他给的理由是:他不想让另一个应用成为这座图书馆的唯一事实来源——因为现有架构早就跟 DEV 数据、分区、房间、书架槽位、摆放逻辑缠在一起了。

"唯一事实来源"这几个字我在脑子里转了很久。

然后我发现自己找不到一个能对上它的东西。我项目里唯一配得上"事实来源"这四个字的,是我那份自己都不敢点开看的代码,同一个坐标在三个文件里各抄了一遍。我连"哪个数据该听谁的"这种问题都还没资格遇到。

有个评论说,这套标记等于把环境本身当成了创作界面,没有引入第二个事实来源。这条我看懂了,而且看到的时候有点羡慕。

17 条评论我大概看懂一半。

kyisaiah47 问的是怎么把世界内编辑器的变换持久化回代码拥有的场景图,槽位和碰撞边界共用摆放数据的时候,输出还能不能 diff。前半句我没懂,后半句也没懂。"代码拥有的场景图",这几个字我到现在也没搞明白,但我知道那是个真问题,因为他问得特别具体,具体到像自己踩过。

Brian 那条说先写代码后建编辑器是强产品动作,关键测试是视觉层能不能保持底层场景数据可检查、可导出,避免形成新的锁定。我读的时候点头,点完发现我说不出来自己为什么点头。

反倒是 Giacomo 那条我至少能想象出画面:对 yaw 和位置做网格吸附,放置的时候做一次包围盒检查。这个我能想明白,因为我手动挪东西的时候撞过墙。

写到这我本来想收一句"所以遇到重复劳动就该想着造工具"。

停了一下。我现在要是学他去造工具,八成是在逃避读代码。他造标记工具,是因为他已经有一座图书馆要摆;我连一个房间都没搭完,现在弄工具,只会多一个我半懂不懂的东西要维护。

这个判断我拿不准,过两周说不定又变了,先记在这。

下周打算干一件特别小的事:把我项目里所有写死在代码里的坐标列成一张表。不造工具,就手抄。抄完看看能不能分清哪个数字是"房间"级别的、哪个是"家具"级别的。分不出来的话,那说明我脑子里那两样东西本来就是糊的。

至于 Giacomo 另外问的那个——pin 是运行时从 Sanity 解析,还是构建时烘焙——我连这个问题在问什么都没想明白。先欠着。

评论区蹲一个大佬,谁知道"代码拥有的场景图"到底指什么,教教我。