今日开源[第40期]img2threejs

img2threejs 项目解读

仓库地址:https://github.com/img2threejs/img2threejs
当前版本:v1.5.0 | 许可证:Apache License 2.0 | 主要语言:Python(stdlib)+ TypeScript
文档生成时间:2026-07-28


1. 项目概览

1.1 项目名称

img2threejs —— 字面含义即「image to three.js」,把一张参考图转成 Three.js 3D 模型。

1.2 作者与简介

  • 作者:GitHub 用户 hoainho(仓库 img2threejs 的主维护者,最新提交与版本发布均由其完成)。
  • 开源资助:项目免费开源,作者通过 Buy Me A Coffee(以及 VietQR / MoMo / PayPal)接受捐赠,说明这是一个个人/小团队主导、以社区驱动演进的开源项目。
  • 项目规模:约 41 次提交,已被 TrendShift 收录并进入日/周榜单(Python 类目),在「image→3D」「AI 生成游戏资产」这一细分方向有一定关注度。
  • 许可演变:早期为 MIT,后于 #16 提交改为 Apache-2.0(更强调专利授权与合规性,适合企业/商业场景二次开发)。

1.3 项目作用(What it does)

一句话:给一张物体的参考图,它产出一段用 TypeScript 编写的 THREE.Group 工厂函数,用「图元 + 程序化着色器 + 生成几何体」在代码层面重建该物体,并附带运行期层级(pivot 枢轴、socket 插槽、collider 碰撞体),使结果「可被动画驱动」,而不是一个死板的静态网格。

能力要点:

  • 输入单张参考图 → 输出纯代码模型,核心范式是 reconstruction-by-code(以代码重建),明确区别于摄影测量(photogrammetry)、网格提取(mesh extraction)、或下载素材包(downloaded art packs)。
  • 代理无关(Agent-agnostic):可在 Claude Code、Codex、OpenCode 等 AI 编码代理下运行,利用宿主提供的视觉/浏览器工具(原生读图、Browser MCP、项目预览、用户截图皆可)。
  • 主体分类与细节分析:物体分为 object / character / hybrid;角色走解剖感知轨道;detailInventory 细节清单(光泽、倒角、螺丝、雕刻线、磨损等)受严格质量门控约束,未列全不得生成。
  • 分阶段雕刻流水线blockout → structural → form → material → surface → lighting → interaction → optimization,自纠正至每个身份特征达标。
  • 确定性 Python 脚本:只负责「验证与门控」,视觉判断与代码编写才消耗模型 token。
  • 实时演示画廊:所有模型均为生成代码、在浏览器中运行,无网格文件。

官方自带 10 个示例:Glock-18、Classic Knife、BMX 自行车、M9 刺刀、索尼耳机、Gerber 刀、哆啦A梦屋、War-Hauler、宝箱。

1.4 背景与定位

该项目诞生于「text-to-3D / image-to-3D」赛道,但刻意走了一条反主流路线:

  • 主流方案(如 photogrammetry、NeRF、或下载/微调网格模型)要么需要多视角与重算力,要么产出二进制网格文件、难以版本化与二次编辑。
  • img2threejs 选择「让 LLM 用 Three.js 原语在代码里把东西搭出来」——输出是可 diff、可版本控制、可动画、可阅读的 TypeScript,而不是几 MB 的 .glb
  • 其工程动机是把「昂贵的模型上下文」只留给真正需要判断力的环节(看侧视对比图、决定通过/打回),把一切机械工作(校验 JSON、算色差、比对像素、跑流程状态机)推给零依赖的确定性 Python 脚本,从而做到 token 高效。

背景里还包含对「单图局限」的诚实声明:单张图无法揭示隐藏面、角色为风格化重建而非照片级,项目明确把「本图达不到所要求保真度」视为一个合法的预期结果


2. 部署过程与运行条件

2.1 部署过程

img2threejs 不是一个独立服务,而是一个技能(Skill)/ 代码工具包,部署方式即「放进 AI 编码代理的 skills 目录并克隆仓库」:

# 1. 克隆到 Claude Code 的技能目录(其他代理类似,放入对应 skills 路径)
git clone https://github.com/img2threejs/img2threejs.git ~/.claude/skills/img2threejs

随后在 Claude Code 中附上/指向一张物体图片,运行斜杠命令即可:

/img2threejs Rebuild this object as a Three.js model, keep the proportions, angles, and colours.

若希望直接走命令行脚本(不经过对话代理),可从技能根目录直接运行各阶段脚本:

python3 forge/stage1_intake/probe_image.py <image>
python3 forge/stage2_spec/new_pre_spec_assessment.py "Name" --image <image> --out assessment.json
python3 forge/stage2_spec/new_sculpt_spec.py "Name" --image <image> --assessment assessment.json --out spec.json
python3 forge/stage2_spec/validate_sculpt_spec.py spec.json --strict-quality
python3 forge/stage3_build/generate_threejs_factory.py spec.json --out src/createObjectModel.ts

2.2 部署 / 运行条件

项目 条件
语言运行时 Python 3.10+(仅用标准库,无需 pip 安装任何依赖
宿主环境 一个支持「视觉输入 + 浏览器/预览截图」的 AI 编码代理(Claude Code / Codex / OpenCode);若纯命令行使用,则仅需 Python 与人工看截图
网络 首次克隆需联网;运行阶段脚本本身不联网(无外部依赖、无 API 调用)
产物运行环境 生成的 .ts 需 Three.js 运行环境(浏览器 + three);评估渲染需在能跑 WebGL 的浏览器中截图
磁盘/系统 普通桌面/开发机即可,无 GPU 硬性要求(生成是代码,不是训练)

关键亮点:「零依赖、零安装折腾」——所有脚本是纯 Python 3.10+ 标准库实现,PNG 读写用 struct + zlib 手写,没有 PIL / numpy / Playwright,因此上下文里没有任何需要调试的第三方包

2.3 运行条件与调用方式

  • 最简调用(对话代理):附图 + 一句 /img2threejs ...
  • 进阶参数(映射到真实门控):可在提示里写 Fidelity / Materials / Runtime / Gates 四段,分别对应保真度约束、材质推导、运行期插槽/动画、严格质量门(--strict-quality)。
  • 领域特化
    • 特定人或角色 → Maximize likeness(投影优先路径);
    • 动物/生物 → 走四足/鸟/龙/蛇四种身体蓝图;
    • CS2 武器 → 必须带 --cs2,且初始家族边界仅限刀(knife),手枪/步枪等若误判会被 unsupported-family 拦截;
    • 饱和阳极氧化/糖果漆面 → 明确「candy-coat 而非 gem-metal」,防止环境把色相偷走。

3. 代码框架与技术栈

3.1 技术栈

维度 选型
渲染/产物 Three.js(TypeScript 编写的 Group 工厂,使用 MeshPhysicalMaterial、PBR、RoomEnvironment、EffectComposer 等)
生成语言 TypeScript(模型代码);Python 3.10+(验证/门控脚本,纯标准库
核心算法 程序化几何(Shape 拉伸、Lathe、Tube、曲线扫掠、实例网格)、CIEDE2000 色差、PBR 通道提取(推理而非逆渲染)、确定性噪声(周期化 value noise)
门控/评估 Python 确定性集成评估(IoU / 尺度 / 对称奇偶 / pHash / SSIM / 边缘 / 过曝 / 平坦 / 色调奇偶);VLM 作为「被门控的最后一层」
运行宿主 AI 编码代理(Claude Code / Codex / OpenCode),利用其视觉与浏览器工具
质量保障 严格质量门、细节清单、CS2 专属组件契约、Divine Eye 评估框架、有界纠正循环(防无限 token 燃烧)

3.2 代码模块 / 目录结构

img2threejs/
├── SKILL.md                 # 技能定义(frontmatter name/license/version=1.5.0)+ 完整流水线指令
├── README.md                # 项目介绍、演示画廊、快速开始、路线图
├── CHANGELOG.md            # v1.0 → v1.5.0 变更记录
├── ROADMAP.md              # 版本路线图(v1.4→v2.0 四阶段长视图)
├── LICENSE                 # Apache-2.0
├── forge/                  # ★ 核心:分阶段确定性脚本(纯 Python stdlib)
│   ├── next.py                     # 报告当前已解锁 pass、下一步命令、未满足的验收条件
│   ├── stage1_intake/             #  intake:图像探测、细节清单、地标、相机求解、去光照
│   │   ├── probe_image.py         # 纯 stdlib 读 PNG/JPEG/GIF/WEBP/BMP/TIFF 尺寸与适配性
│   │   ├── build_detail_inventory.py
│   │   ├── extract_landmarks.py
│   │   ├── solve_camera_pose.py
│   │   ├── delight_albedo.py
│   │   ├── extract_pbr_evidence.py
│   │   └── check_reference_admission.py / check_intake_correctness.py / search_specs.py ...
│   ├── stage2_spec/              # spec:分类、复杂度、质量契约、ObjectSculptSpec 编写与校验
│   │   ├── new_pre_spec_assessment.py
│   │   ├── new_sculpt_spec.py
│   │   └── validate_sculpt_spec.py   # --strict-quality 拦截浅层 spec
│   ├── stage3_build/             # build:pass 状态机 + Three.js 工厂代码生成
│   │   ├── orchestrate_passes.py # status / check / sync
│   │   └── generate_threejs_factory.py  # ★ 把 spec 编译成 .ts 工厂(核心代码生成器)
│   ├── stage4_review/           # review:对比图打包、Divine Eye、CS2 审查、纠正循环
│   │   ├── make_comparison_sheet.py
│   │   ├── append_review.py
│   │   ├── divine_eye.py        # 确定性多信号集成(硬门 + 软门 + 自不确定性)
│   │   ├── vlm_gate.py          # 经门控、校准、交叉验证的 VLM 最后层
│   │   ├── cs2_review.py
│   │   ├── diagnose_render.py / diagnose_render_multi_angle.py
│   │   ├── correction_loop.py
│   │   └── check_part_coverage.py
│   └── _shared/                # 内部公共 helper(如 feature_acceptance_policy.py)
├── grimoire/               # 「魔法书」:各门控应用的详细评分标准(rubric)
│   ├── intake/   (validation_rubric, detail_inventory, quality_contract, surface_topology, image_analysis, cs2_texture_acquisition)
│   ├── build/    (geometry_patterns, threejs_texture_reference, cs2_finishes)
│   ├── character/ (reconstruction, likeness_maximization)
│   ├── readiness/ (action_rigging, joint_attachment)
│   ├── feedback/ (render_capture, shading_realism)
│   ├── review/    (self_correction)
│   └── glossary/ (3d_vocabulary)
├── docs/                   # ARCHITECTURE.md / TOKEN_COST.md / UPGRADE_PLAN.md / cs2/review-gates.md
├── scripts/                # 顶层辅助脚本
├── skills/                 # CS2 等子技能
└── assets/                # logo 等

最关键的两个文件

  1. forge/stage3_build/generate_threejs_factory.py —— 真正的「代码生成器」,把 ObjectSculptSpec(JSON)编译成可运行的 Three.js .ts 工厂。
  2. forge/stage1_intake/probe_image.py —— 展示「零依赖」哲学的范例,仅用 struct/zlib 解析多种图像格式。

3.3 流水线(Pipeline)

分阶段「雕刻」:脚本给每个阶段设门,代理的「视觉」是唯一能批准一个 pass 的东西。

flowchart TD A[参考图] --> B[探测 + 适配性门] B --> C[Pre-Spec 评估:分类 / 复杂度 / 质量契约] C --> D[编写 ObjectSculptSpec:组件 / 材质 / 插槽] D --> E{校验 + 严格质量} E -- 太浅 --> D E -- 通过 --> F[锁定的构建 pass] F --> G[仅生成当前 pass 的 Three.js 工厂] G --> H[浏览器渲染并截图] H --> I[打包一张「参考 vs 渲染」对比图] I --> J{代理视觉评审} J -- 低于阈值 --> K[自纠正:refine-spec / refine-code] K --> F J -- 通过 --> L{还有 pass?} L -- 是 --> F L -- 否 --> M[可动画的 Three.js 模型]

构建顺序固定,后一个 pass 只有在前一个被评审接受后才解锁:

blockout → structural-pass → form-refinement → material-pass → surface-pass → lighting-pass → interaction-pass → optimization-pass

每个 pass 有独立验收标准,必须同时满足「真实渲染 + 对比图 + 代理视觉分 ≥ 阈值 + 每个身份特征 ≥ 其自身阈值」才能标为 continue

3.4 核心代码

下面给出最具代表性的片段(完整源码见仓库,已逐字核对)。

(a) 流水线状态机与「几何分发」——generate_threejs_factory.py

VALID_PRIMITIVES = {
    "box", "sphere", "ellipsoid", "cylinder", "cone", "capsule",
    "torus", "tube", "lathe", "extrude", "ground-blade",
    "curve-sweep", "plane-card", "instanced-cluster",
}

def geometry_for(primitive, component=None):
    """把 spec 里的基元名映射成 Three.js 几何体构造调用。"""
    if primitive == "box":
        return "new THREE.BoxGeometry(1, 1, 1, 12, 12, 12)"
    if primitive in {"sphere", "ellipsoid"}:
        return "new THREE.SphereGeometry(0.5, 64, 40)"
    if primitive == "cylinder":
        return "new THREE.CylinderGeometry(0.5, 0.5, 1, 48, 16)"
    # ... lathe / tube / curve-sweep / instanced-cluster 等分支
    if primitive == "ground-blade":
        spec = descriptor.get("bladeSpec") or _DEFAULT_BLADE_SPEC
        return f"buildGroundBladeGeometry({json_literal(spec)})"
    raise GeometryNotImplementedError(primitive)   # 绝不静默退化为 box!

设计要点:早先「未知基元静默退化为 box」曾导致刀刃被渲染成方块却毫无提示,因此引入 GeometryNotImplementedError,强制在生成前报错。

(b) 工厂生成核心 generate() 的骨架

generate(spec, pass_id) 做三件事:① 按当前 pass 过滤组件(filter_components_for_pass,只生成已解锁层级,避免每轮重读整模型);② 仅 emit 本 pass 实际用到的几何 helper 函数(防止 noUnusedLocals 构建失败);③ 拼出 create<Name>Model(options) 工厂,并附带 create<Name>LookDevLights / create<Name>Environment / frame<Name>Camera / create<Name>PresentationComposer / configure<Name>Renderer / create<Name>InspectControls 等配套函数。

输出的工厂关键结构(节选):

export function createObjectNameModel(options: ProceduralModelOptions = {}): THREE.Group {
  const root = new THREE.Group();
  root.name = "ObjectName";
  root.userData.reconstructionEvidence = { itemFamily, subtype, route, exactnessTier, ... };

  const materialMap: Record<string, THREE.Material> = {};
  // ... 由 spec.materials 生成 MeshPhysicalMaterial(含 clearcoat/iridescence/
  //     transmission/anisotropy 等 PBR 通道 + 程序化贴图集)...

  const nodes: Record<string, THREE.Object3D> = { root };
  const meshes: Record<string, THREE.Mesh> = {};
  const sockets: Record<string, THREE.Object3D> = {};
  const colliders: Record<string, unknown> = {};
  const destructionGroups: Record<string, THREE.Object3D[]> = {};

  // ... 按 componentTree 递归建立 pivot→mesh,attachment 用 Cylinder 连接
  //     (endpoint 由 localStart/localEnd 决定,杜绝悬空部件)...

  // 重复系统(辐条/螺钉/齿)用单个 InstancedMesh 实现,一次 draw call
  // ...

  root.userData.sculptRuntime = { nodes, meshes, sockets, colliders, destructionGroups };
  return root;
}

(c) 「零依赖」图像探测——probe_image.py

不依赖任何第三方库,用 struct 直接解析文件头字节:

def png_size(data: bytes) -> tuple[int, int] | None:
    if data.startswith(b"\x89PNG\r\n\x1a\n") and len(data) >= 24:
        return struct.unpack(">II", data[16:24])   # PNG: IHDR 宽高在大端 8 字节
    return None

def jpeg_size(data: bytes) -> tuple[int, int] | None:
    if not data.startswith(b"\xff\xd8"):
        return None
    # 遍历 JPEG 标记段,找 SOF0/SOF2... 读取宽高
    ...

def probe(path: Path) -> dict:
    data = path.read_bytes()
    image_type = detect_image_type(data)
    size = detect_size(data)        # png/jpeg/gif/webp/bmp/tiff 全部自制解析
    warnings = []
    if size and (size[0] < 512 or size[1] < 512):
        warnings.append("low resolution; small geometry/material details may be unreliable")
    return {"path":..., "type":..., "width":..., "height":...,
            "technicalSuitability": "conditional" if warnings else "pass",
            "warnings": warnings,
            "note": "This is only technical image probing. Semantic object suitability still requires visual inspection."}

4. 优势、不足、创新点

4.1 优势

  1. 产物是代码而非资产:输出可 diff、可版本化、可动画、可二次编辑的 TypeScript,而非二进制网格文件——天然契合软件工程工作流。
  2. Token 高效(核心工程价值)
    • 脚本做「强制」,模型只做「判断」——视觉评分、JSON 校验、像素比对全推给确定性脚本;
    • 纯 Python stdlib,零安装零依赖,上下文没有要调试的包;
    • pass-gated 生成:每次只产出当前解锁的 pass,不重读/重生成整模型;
    • 失败前置--strict-quality 在生成一行 Three.js 之前就拦住浅层 spec;
    • 每次评审只看「一张对比图」,而非一堆散落截图;
    • 文本产物(TS + JSON spec)体积小、可评审。
  3. 质量门控体系严密:适配性门、Pre-Spec/严格质量门、截图反馈门、可动性门、装配(结构)门、附件正确性门、材质/光照真实门、细节清单门、CS2 专属契约门、有界纠正循环。
  4. 诚实与透明:明确声明单图局限、风格化而非照片级,并要求每轮列出「改了什么 / 证据 / 仍不匹配什么」,防止过度承诺、便于人工调试流程。
  5. 动画/交互就绪:输出带 pivot / socket / collider / destruction group,可直接做可动道具、可破坏物体、可拾取部件(还提供 explode/part-picking 统一「部件」定义)。
  6. 领域纵深:CS2 武器(刀类)有家族专属组件契约与投影优先路径;角色有解剖感知轨道与最大相似度路径;生物有四种身体蓝图。

4.2 不足与局限

  1. 单图先天局限:隐藏面不可见,几何无法保证精确;角色是风格化重建而非照片级,「100% 相似」不被承诺。
  2. 高度依赖 AI 代理生态:最佳体验需要 Claude Code / Codex / OpenCode 这类「能看截图、能跑浏览器」的宿主;纯命令行使用则需人工介入看对比图,自动化程度下降。
  3. CS2 家族边界窄:初始只支持「刀(knife)」,手枪/步枪/SMG 等若被误判会直接 unsupported-family 拒绝——覆盖面有限。
  4. 视觉评估仍非完全确定性:Divine Eye 是确定性优先,但 VLM 作为「最后一层」仍会引入概率性判断;作者自己也指出「2D 门过了但 3/4 视角下仍像玩具」这类盲区。
  5. 生成质量是「程序化的近似」:复杂有机体、布料、毛发等仍偏风格化;糖果漆/阳极氧化等若用程序化材质(而非投影参考像素)会与实物产生明显色差。
  6. 学习/使用成本:SKILL.md 与 grimoire 体系庞大(数十个 rubric 文件),新手上手门槛不低;要严格达标需理解其门控语义。

4.3 创新点与亮点

  1. 「以代码重建」范式(reconstruction-by-code):不去下载或拟合网格,而是让 LLM 用 Three.js 原语「搭」出物体——把 3D 重建问题转化为「代码生成 + 视觉自纠正」问题。
  2. 确定性脚本 + 概率模型的分层架构:把「token 昂贵」的环节和「机械可验证」的环节彻底分离,并用零依赖 Python 实现,是该项目的灵魂设计。
  3. Divine Eye 评估框架:确定性优先、VLM 最后的「多信号集成」评估器——硬门(IoU/尺度)失败绝不让 VLM 救场,软门近阈值才允许 VLM 多样本投票救援,并带自不确定性探针(probe),避免盲目信任视觉模型。
  4. 有界纠正循环(token-burn safety):纠正循环保证终止(成功/重复缺陷/振荡/平台期/硬上限),必要时升级为 request-input绝不让代理无限烧 token
  5. 结构级门控(唯一评结构的门)check_part_coverage.py 是整套体系里唯一对「结构」打分的门——它能抓出「spec 写了但没建」「两个组件熔到一个网格」;作者明确说它的局限(只证明你建了 spec 里的东西,不证明 spec 本身足够)也要如实声明。
  6. 投影优先保真策略:对图案化表面(Doppler/Fade/Gamma/Marble 皮肤、贴花、彩绘),直接把照片自己的去光照像素投影到网格并烘焙进 UV,而非用程序化材质近似——这是单图达到参考保真度的「最大杠杆」。
  7. 透明可调试的流程契约:从 Bowie Knife 重建中总结出的「不夸大、给证据、点名仍不匹配」原则,使迭代改进可行;跨层的 cs2-intake.json 交接契约(含 6 种状态、原子写入、保留未知字段)把「证据可追溯」落到数据格式。

5. 总结

img2threejs 是一个定位精准、工程取向鲜明的开源项目:它不追求「一张图变出照片级网格」,而是用「代码即资产」的思路,把单张参考图变成可版本化、可动画、可评审的 Three.js 程序化模型。其最大价值不在某个炫技算法,而在架构哲学——把昂贵的模型判断力与廉价的确定性脚本严格分层,并用零依赖 Python 把一切机械工作挡在 token 上下文之外。配合严密的质量门控、Divine Eye 评估、有界纠正循环与「透明可调试」原则,它特别适合「硬表面道具 / 游戏资产 / 可动可破坏物体」这类场景,并已向角色、生物、CS2 武器、环境、乃至 v2.0「程序化世界」路线演进。

局限同样清晰:单图先天信息不足、强依赖 AI 代理生态、CS2 家族覆盖窄、复杂有机体仍偏风格化。理解这些边界,是使用该项目前必须建立的预期。


附录:参考链接与文件

注:本文档内容基于对该仓库 README、ARCHITECTURE、SKILL.md 及两份核心源码的逐字核对整理而成(核对时间 2026-07-28,仓库版本 v1.5.0)。

posted @ 2026-07-28 20:33  zhang-yd  阅读(20)  评论(0)    收藏  举报