手里只有一张图时,先别急着点转换。img2threejs 这类把单图变成 Three.js 场景的处理,本质上是把可见像素反推成少量几何与贴图:没拍到的背面、被挡住的交界、没有纹理起伏的平面,只能由模型补猜。判断顺序建议是:先确认原图的透视是否单一,再标出信息缺失区,然后跑一次最小转换查看交付物结构,最后用自检清单决定直接可用、返工还是换图。
单图能撑起什么程度的 Three.js 场景,取决于四点:透视是否单一、遮挡区是否落在次要位置、纹理是否唯一、阴影方向是否明确。做法是在原图上标地平线、灭点和四类高风险区域,再跑一次最小转换,核对对象树、网格与贴图引用。四项自检不过就补图或换图,别靠手修掩盖几何缺失。
在原图上标出灭点与地平线,判断透视是否单一
准备一张原图的副本,用任意标注工具(Photoshop、Figma、系统截图标注都行)在上面画线,不改动原文件。先找地平线:画面里本应水平的边,比如窗台、桌面边缘、远处海平面,沿这些边画直线;如果这些线在画面上大致重合于一条水平带,就能定出地平线位置。再看可见面数量:只看到正面一类面,说明深度线索不足;能看到正面和侧面两个面,几何大致能由一组相机参数解释;同时看到正面、侧面和顶面三个面,通常还能接受。
判断鱼眼或广角畸变,看三点:本应笔直的边出现弯曲、画幅边缘出现明显拉伸、两条平行边在画面内明显向外扩。出现任意一条,单相机针孔模型的解释力都会下降,转换后的墙面和地面容易歪。
还有一种情况需要单独记录:左侧窗格向右收敛、右侧窗格也向外扩,收敛方向互相矛盾。这类图可能是拼接或经过了非针孔投影,转换结果会同时出现两个方向的倾斜,不能指望靠改相机参数修回来。判断结论记成一句就够:“一点透视/两点透视/透视矛盾”,后面选补图还是换图要用到。
逐块检查遮挡与重复纹理,标出模型必然会猜错的位置
同一张副本上继续标注四类高风险区域,每类用不同颜色,标完大致判断各类区域占画面的面积比例(用眼睛估个区间即可,不需要精确数字)。
| 区域类型 | 标记方式 | 转换后常见后果 |
|---|---|---|
| 遮挡区(家具挡住墙角、前景物体压住地面) | 用半透明色块圈出被挡住的交界,旁注“几何不可见” | 被挡部分被补成平板或直接断开,接缝错位 |
| 镜面高光(玻璃、金属、水面反光) | 圈出高光范围,标注亮度峰值位置 | 高光被烘进颜色贴图,换光源角度仍然亮着,材质通道也分不清 |
| 纯色墙、纯色地面 | 用矩形框住,记录有无渐变和污渍 | 缺少纹理就没有尺度参照,深度估计只能给出单层平板,墙和地容易共面 |
| 重复窗格、瓷砖、栅栏 | 数出重复周期,框出一段完整重复单元 | 周期被误当深度线索,模型猜出多余凹凸或错层 |
如果主要结构几乎都压在遮挡区或纯色区,这张图基本只能当背景板用,转换出来的几何不具备可编辑价值;如果高风险区只占角落,单图转换仍有继续核对的必要。
跑一次最小转换,查看输出的对象树、网格与材质命名
用默认参数、只放这一张原图做一次转换,输出到独立目录,先不要调参。目的不是看效果好不好,而是看 img2threejs 交付到 Three.js 工程里的内容结构。把导出的场景加载进 Three.js 页面后,在控制台遍历一遍对象树:
const stats = { meshes: 0, groups: 0, materials: new Set(), textures: new Set() };
scene.traverse((o) => {
if (o.isMesh) {
stats.meshes++;
const mats = Array.isArray(o.material) ? o.material : [o.material];
mats.forEach((m) => {
stats.materials.add(m.type);
if (m.map) stats.textures.add(m.map.name || m.map.uuid);
});
}
if (o.isGroup) stats.groups++;
});
console.log(stats);
重点看三项。对象层级:Scene 下有几个 Group、嵌套几层,一个物体一个节点的结构后续好定位,嵌套过深会让手修时找不到对应网格。网格数量与命名:如果命名是 wall、floor、window 这类可读词,说明转换时做了语义分组;如果全是 mesh_0、mesh_1 这类序号,就只能整体处理。贴图引用方式:材质里的 map 指向外部图片文件、内嵌 data URI 还是程序化生成的 CanvasTexture,外部文件要确认路径大小写和相对位置,否则加载后是空白灰模。上面代码里贴图 name 为空时退到 uuid,uuid 每次加载都会变,不能用来判断两次输出是否一致,判断一致性要看文件路径和网格命名。
编写场景自检清单,逐项判定可用或需返工
把“看着还行”换成四项可以重复执行的检查,每一项都要留下记录:通过、不通过、不通过的原因。
| 检查项 | 操作方法 | 通过标准 | 不通过时动作 |
|---|---|---|---|
| 相机视角对齐 | 记录初始 camera.position 和 lookAt,渲染一帧后与原图标注的地平线比高度,再轻微旋转看灭点走向 | 地平线落在画面相近高度,灭点随旋转同向移动 | 先调相机,调不动说明几何本身有多个视角 |
| 比例尺 | 找门高、桌面高度这类已知尺寸物体,在场景里量同一物体 | 量级合理,单位统一(米或厘米) | 整体缩放模型,别逐件改 |
| 地面贴合 | 把相机压到接近地面视角,检查物体底部 | 没有穿地、没有悬空,贴地网格 y 值一致 | 按组平移,记录偏移量 |
| 材质通道 | 关掉场景光源,只保留颜色贴图渲染一张 | 颜色贴图里没有明显高光和投影 | 分离出高光与阴影贴图,或换材质类型 |
四项里相机视角和地面贴合属于几何问题,不通过基本要回到前两步找原因;比例尺和材质通道属于装配问题,通常能在 Three.js 里改。
根据检查结果,决定补图、换图或进入 Three.js 手修
把检查结果分成三种情况处理。
补图:触发条件是透视单一成立、失败集中在少数遮挡区或纯色面,同时还能拿到同一场景另外一到两张不同角度的照片。工作量按需要覆盖的缺失面数量估,一个缺失墙角通常对应一次补拍加一次重新转换,不要指望补拍后完全不用手修。
换图:触发条件是原图本身不满足单相机假设,比如地平线找不到、可见面收敛方向互相矛盾、画面大面积为镜面或纯色。换图后要重新走一遍灭点标注和四类区域标注,不进入手修环节。
手修:触发条件是自检四项里只有命名混乱、材质通道或少量接缝不通过,几何与贴图大体对齐。工作量按需要改动的网格数量估,逐个替换材质、重命名、调整 y 值,改动范围控制在已有对象树内。手修不解决几何缺失,被挡住的墙角不会因为改了材质就长出来。