跳到正文
Pian

把一张教堂照片变成雾中尖塔

图生 3D 第一版给我生了对双塔,贴图是一张糊掉的 2K atlas。记录从参考图裁切、Blender 减面补 AO、三平面石材 shader 到 950KB Draco 落地的全过程。

4 分钟读完#3D #Lux3D #Blender #Three.js

首页原来是一座科幻方尖碑,220 块碎片,炸开再聚成门。技术上行得通,但看久了像一堆会发光的碎玻璃。

我想换一座真正的建筑:中世纪哥特尖塔,红砂岩,塔身有窗火,雾从塔基漫上来。

问题是,纯程序化几何做不出这种细节。之前那版「学院 / 平原 / 法阵」就是死在这里:树是锥体、书是平面、牛羊是方块拼的,放大看全是塑料。这次换一条路——用图生 3D 出主体,再在 Blender 里做脏活。

第一版:AI 给我生了对双塔

参考图用的是弗莱堡大教堂塔楼,红砂岩、八角塔身、镂空尖顶,品相很好。

第一次裁图时,我把塔身和两侧的屋顶一起留了进去。生成结果打开一看:两座一模一样的塔,中间还连着一个屋顶。

原因不复杂。参考图底部左右各有一截屋顶,模型判断「这是一座对称的教堂」,于是把另一半补了出来。图生 3D 不会只生成你框住的东西,它会替你补全语义。

第二次把屋顶全部裁掉,只留单塔,底部在塔身中间直接切断——反正塔基最后要埋进雾里。这次生成的是单塔。

结论:参考图里不要留任何暗示「另一边还有东西」的对称元素。裁到只剩主体,比留全貌更安全。

体检:16k 个碎片,200k 条边界

生成文件 24MB,283k 面。用 Blender 的 inspect_mesh.py 一查:

islands = 16245
boundary_edges = 200242
nonmanifold_edges = 0

这不是模型碎了,是顶点没焊接。Lux3D 的输出是单层开放壳,每块面各写各的顶点。先 remove_doubles,碎片降到 81 个,边界还在——因为建筑本来就有窗洞和镂空。

开放壳能不能用?能,但要接受两件事:

  1. 背面必须双面渲染,否则从窗洞看进去直接穿帮。
  2. 近看能看出「里面是空的」。所以塔基埋进地形,镜头不钻到塔里。

贴图不能用

生成模型带一张 2048×2048 的 PBR 贴图。打开一看,整张图都是涂抹状的砖纹和黑色矩形,UV 拆得乱七八糟。直接贴上去,塔身会像被泥巴糊过。

这张贴图我直接扔了。改用 object-space 三平面噪声:

  • 用世界/物体坐标采样 3D 噪声,不需要 UV,所以没有接缝。
  • 三个轴向按法线权重混合,正面、侧面、顶面各自连续。
  • 低频噪声做风化色差,高频噪声做颗粒,再叠一层「越靠近地面越潮」的冷绿苔。
  • 粗糙度也跟着噪声走,石面不会整块一样亮。

顶点色单独烘一层 AO:对每个顶点在法线半球打 10 条射线,命中越多越暗,存进 COLOR_0。这层 AO 在 Three.js 里和噪声相乘,窗洞、卷叶、柱头这些凹处自然压暗。

好处是:没有贴图请求,没有 UV 缝,模型压到 950KB。

减面与基座

原始 283k 面,减到 72k。再减,镂空的卷叶会断。

底部原来是一圈乱七八糟的屋顶碎片,直接在 z = -5.4 切平,接一个两级八边形基座。基座和塔身一起做 AO、一起导出,不然基座会是一块没有细节的黑饼。

导出开 Draco,位置量化 14 位、法线 10 位,24MB 变 950KB。Draco decoder 放在 public/draco/,不走 gstatic CDN——国内访问那个地址经常转圈。

相机:塔在右,字在左

3D 是整页 fixed 背景,文章列表直接压在塔上。第一版相机把塔放在正中间,滚到文章区时标题和塔身撞在一起,字能看,但很吵。

改法不是给文字加背景块,而是改构图:

  • 首屏塔放在画面右侧 2/3 处,左侧留给标题。
  • 滚动到文章区时,lookAt 往左偏,塔被推到画面右边,文字回到干净的左栏。
  • 雾的 near 从 12 拉到 20,塔身中段开始吃雾,底部自然消失。

塔基还是露了一点。加了两级台阶,反而成了画面里唯一像「人工建造」的细节。

最后

现在首页是:冻雾盆地、右侧一座红砂岩尖塔、塔内两盏暖光、塔尖一点守望灯,月亮在云后面。

它不是照片级写实。开放壳的近看仍然偏软,卷叶是模型生成的,不是手工雕的。但在这个观看距离、这层雾和这点光里,它成立了。

比上一版好的地方不是「更精细」,是它有一个真实的参照物。程序化几何可以造出很酷的抽象结构,但造不出一座让人相信有人住过的塔。