先确认原图有没有可信深度——再谈 img2threejs 的重建上限

文章导读
img2threejs 这类单图转三维流程,重建上限主要由原图是否含有可信深度线索决定;参数和提示词只能在这个上限内调整。判断顺序建议反过来:先在原图上找遮挡、接触阴影、地面接触点、线性透视这四类线索,能读出前后关系再谈重建;读不出的部分通常交给 Three.js 手工补做,不要指望模型猜对。
📋 目录
  1. 壹 找出图里能直接读出前后关系的线索
  2. 贰 给线索分级:强、弱、无
  3. 叁 对照等级写下预期能重建到什么程度
  4. 肆 列出图里注定要手动补做的部分
  5. 伍 按分级决定直接转、先补图还是换图
A A

img2threejs 这类单图转三维流程,重建上限主要由原图是否含有可信深度线索决定;参数和提示词只能在这个上限内调整。判断顺序建议反过来:先在原图上找遮挡、接触阴影、地面接触点、线性透视这四类线索,能读出前后关系再谈重建;读不出的部分通常交给 Three.js 手工补做,不要指望模型猜对。

适用场景:只有一张图、又想得到能直接进 Three.js 的网格时,先做深度线索判读。操作动作:按遮挡、接触阴影、地面接触点、线性透视逐项判断,综合为强、弱、无三级。验证方式:把生成的模型放进带 OrbitControls 的场景绕一圈,看穿插、地面接触和背面是否穿帮。风险边界:分级只约束可接受的输出形态,不保证几何精度;判为「无」时,结果只能当造型参考。

找出图里能直接读出前后关系的线索

先把「感觉这张图挺立体」换成可指认的画面证据。下面四类线索都能在图上指出来;指不出来,就按缺失处理。

  • 遮挡:前景物体边缘切断背景物体。判读方法是放大到边缘,看轮廓线是干净连续,还是被另一条轮廓截断;截断处就是前后关系成立的位置。遮挡层数越多,可读出的相对深度越可靠。
  • 接触阴影:物体与支撑面贴合处的暗部,通常窄、暗、紧贴轮廓。判读方法是看底部有没有从边缘向外渐变的暗带;只有均匀投影、没有贴合暗部,多半是合成或后期加的假投影。
  • 地面接触点:物体落在平面上的那一条线或那几个点。判读方法是看交界线走向与画面地平线是否一致;交界线漂浮、悬空或根本没有交点,地面就定不下来。
  • 线性透视:桌沿、墙脚、地砖缝这类平行线向消失点收拢。判读方法是沿两条可见平行边延长,看是否交于同一点;能交于一点,相机高度与朝向可反推,地平面就能建。

给线索分级:强、弱、无

分级标准建议按「可判读性」而不是「好不好看」来定,四类线索各自记,再取综合等级:

  • 强:该线索在画面上能直接指出位置,换个人看也能指出同一处,比如明确的截断轮廓、贴合暗部、可延长的透视线。
  • 弱:线索存在但只能定性判断,位置有争议,比如阴影方向不一致、透视线只剩一条、交界线被遮住一半。
  • 无:找不到该线索,或所有边都平行于画面、物体四周亮度一致,常见于纯色背景棚拍和平面插画。

三类以上为强记综合「强」;两强两弱、或一强多弱记「弱」;其余只剩弱和无的记「无」。三张图的判读示例:

  1. 室内实拍:桌面边缘遮住后方椅子腿,遮挡强;杯底与桌面有贴合暗部,接触阴影强;桌沿与地砖缝朝同一侧收拢,线性透视强;接地点清晰。综合判为强。
  2. 白背景产品图:主体轮廓完整但背后没有别的物体,遮挡无;底部只有一圈均匀投影、没有贴合暗部,接触阴影弱;背景无透视线,线性透视无;底边与画面平行、定不出地面,地面接触点弱。综合判为弱。
  3. 平面插画或抠图素材:所有元素挤在同一层,轮廓互不截断,亮度一致没有阴影,也没有可延长的平行线。综合判为无。

对照等级写下预期能重建到什么程度

把等级先翻译成「能接受什么、不能接受什么」,验收就不会跑偏。

等级可接受的结果形态不可接受的结果形态验收动作
强主体前后遮挡关系正确,接地点位置与图中一致,透视线方向一致背面与内部凹槽无中生有,接触处出现明显穿插绕场景一周看轮廓与接地点
弱整体体块与比例对得上,正面主要面片可用侧向厚度、景深层次、多物体相对距离被当成准确结果回到正面视角与原图逐边对比
无单层贴图或轻度挤出的浮雕式表达任何三维位置关系与遮挡推导只以正面视角使用,不做交互旋转

建议把这张表原样写进任务说明或验收单,下游按行对照,不要靠口头描述「差不多立体」。

列出图里注定要手动补做的部分

缺失侧面、地面延伸、材质通道这三块是单图重建后的固定欠账,提前写成清单比事后返工省事。模板可直接放进仓库当 checklist 使用:

{
  "source": "single_image.png",
  "depth_grade": "weak",
  "manual_todo": {
    "missing_sides": ["左侧面", "背面", "底部"],
    "ground_extension": { "need": true, "contact_points": ["主物体底边"], "method": "平面 + 接触阴影补片" },
    "material_channels": {
      "map": "原图裁切后作为颜色贴图",
      "roughnessMap": "原图不含,需人工指定",
      "normalMap": "需重绘,或从高度信息挤出",
      "alphaMap": "抠图残留的边缘需清理"
    }
  },
  "verify": ["OrbitControls 绕场一周无穿插", "接地点与地面贴合", "正面视角与原图对齐"]
}

Three.js 侧的最小骨架,用来补地面延伸和材质通道,执行位置是加载重建模型之后:

import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';

const scene = new THREE.Scene();
const camera = new THREE.PerspectiveCamera(45, innerWidth / innerHeight, 0.1, 100);
const renderer = new THREE.WebGLRenderer({ antialias: true });
document.body.appendChild(renderer.domElement);

// 地面延伸:用一个平面承接接触点,尺寸取包围盒的整数倍,避免物体悬在半空
const box = new THREE.Box3().setFromObject(model);
const size = box.getSize(new THREE.Vector3());
const ground = new THREE.Mesh(
  new THREE.PlaneGeometry(size.x * 4, size.z * 4),
  new THREE.MeshStandardMaterial({ color: 0xcccccc, roughness: 1 })
);
ground.rotation.x = -Math.PI / 2;
ground.position.y = box.min.y; // 与原图接地点对齐
scene.add(ground, model);

// 材质通道:颜色贴图沿用原图,粗糙度和法线单独给,不要指望原图提供
const mat = model.material ?? new THREE.MeshStandardMaterial();
if (mat.map) mat.map.colorSpace = THREE.SRGBColorSpace;
mat.roughness = 0.8;

if (renderer.info.render.triangles === 0) {
  console.warn('模型为空或未加载成功,先排查资源路径再谈补面');
}

清单里每一项都要在场景里能指到对应对象:缺失侧面对应补的几何或背面挤出,地面延伸对应上面这个 Plane,材质通道对应 map、roughnessMap、normalMap 三张贴图的来源说明。指不到对象的条目,就是还没补完。

按分级决定直接转、先补图还是换图

  • 强:直接转。取舍理由是四类线索同时可用,结果能支撑前后关系与接地点;动作是转换完立刻做一次绕场验收,穿插严重的局部拿到建模工具里修,而不是反复重跑参数。
  • 弱:先补图再转。补图指给同一物体补一张侧面或俯视参考,或重拍时加一块地面、加一个光源制造贴合暗部;取舍理由是原图缺约束,补一张辅助参考比在 Three.js 里靠猜补侧面省事。补图后仍缺的部分,按上一节清单转手工补做。
  • 无:换图,或明确降级为平面用法。取舍理由是这张图不含可判读的深度信息,继续调参数只会得到看着立体、实际到处穿帮的模型;如果业务只要正面展示,用平面贴图或轻度挤出即可,不要承诺可旋转的三维交互。

三种动作共用一套验证:加载后开 wireframe 看补面密度,用 OrbitControls 绕到侧后方,检查接地是否贴合、背面是否穿空,再切回正面视角与原图对轮廓。这三步过不去,说明分级给高了一档,应退回上一级重新处理。