mcpField
W
wireframe-to-3d

wireframe-to-3d

github.com/roble3创意与媒体128838 次安装2 周前更新
代码仓库

关于 wireframe-to-3d

wireframe-to-3d 是将正交线框图转换为 Blender 参数化模型并导出 GLB 的技能,适用于从线稿创建 3D 资产。它通过图像分析、曲线建模和导出验证构成处理流程。

主要功能

  1. 01线框图轮廓分析
  2. 02生成参数化 Bezier 曲线
  3. 03通过 Blender 执行建模代码
  4. 04转换网格并赋予 PBR 材质
  5. 05验证并导出 GLB 文件

适用场景

  1. 01将眼镜等线框图转为模型
  2. 02按预览或生产细节等级生成模型
  3. 03检查模型拓扑与导出文件大小

MCP 相关

该技能通过 Blender MCP 检查场景、执行 Blender Python 代码并获取对象信息。它使用 MCP 与 Blender 协作完成建模和验证。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/roble3/cc-blender-skill --skill wireframe-to-3d

安装后在 Claude Code 中输入/wireframe-to-3d确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

evals/
evals.json
references/
algorithms.md
best-practices.md
blender-patterns.md
scripts/
wireframe_analyzer.py

详细介绍

线框图转 3D 模型

将 2D 正交线框图转换为参数化的 3D Blender 模型,并导出为 glTF 2.0 二进制文件(.glb)。

概述

此技能通过四个阶段的流水线完成转换:

  1. 分析:使用 scripts/wireframe_analyzer.py 在本地分析线框图(OpenCV → JSON 格式的贝塞尔控制点)。
  2. 生成:生成 Blender Python 代码,将轮廓还原为参数化贝塞尔曲线。
  3. 执行:通过 mcp__blender__execute_blender_code 在 Blender 中执行代码,将曲线转换为带有 PBR 材质的网格。
  4. 导出:导出经过优化的 GLB(≤ 15 MB),并验证文件大小和拓扑。

你(Claude)负责协调流程。scripts/ 目录包含唯一的独立代码(wireframe_analyzer.py);其他内容都是你生成并通过 MCP 运行的模式。

前置条件 — 请先检查

在处理任何线框图之前,请确认环境满足以下条件:

  1. Blender MCP 可访问。调用 mcp__blender__get_scene_info。如果报错“Could not connect to Blender”,请停止并告知用户:

    “Blender 的 MCP 插件未运行。请启动 Blender,启用 BlenderMCP 插件(端口 9876),然后重新运行。”

  2. 分析器所需的 Python 依赖。运行:

    python3 -c "import cv2, numpy, scipy" 2>&1
    

    如果报错,请运行 pip install opencv-python numpy scipy Pillow(或指导用户运行)。

  3. 图像输入。确认用户至少提供了一张 PNG。建议尺寸:≥ 400×400 px,黑底白线或白底黑线的线稿。

决策流程

Q1:有多少个视图?
  • 单视图 → 仅进行平面 2D 挤出(提醒用户;必须提供或假设深度)。
  • 正视图 + 侧视图 → 完整的 3D 重建(轮廓 × 深度剖面)。
  • 正视图 + 侧视图 + 后视图 → 使用后视图验证对称性。
Q2:细节级别?
  • preview — RDP epsilon = 4.0,目标约为 1–2k 个三角形,GLB < 1 MB。
  • production — RDP epsilon = 2.0,目标约为 5–8k 个三角形,GLB 为 2–4 MB。默认值。
  • high — RDP epsilon = 1.0,目标约为 10–20k 个三角形,可能需要使用 Decimate 才能将文件控制在 15 MB 以下。
Q3:几何体类型?
  • wires — 框架、镜腿、铰链。对曲线使用 bevel_depth。
  • surfaces — 镜片、穹顶。使用放样剖面或填充端盖。
  • hybrid — 两者兼有。类似眼镜的物体默认使用此类型。
Q4:实际尺寸?
  • 如果用户提供了尺寸(例如“眼镜宽 140 mm”),请使用该尺寸。
  • 否则,根据线框图的宽高比推断,并假设合理的默认值(眼镜宽 140 mm、头盔宽 180 mm 等)。如果不明显,请与用户确认。

参考图/纹理驱动主体的强制修正循环

当用户反馈模型与参考图/纹理不匹配时,请停止常规的“从基本几何体生成”循环,改用参考图锁定建模:

  1. 先根据提供的纹理/线框图统计可见设计部件的数量,并在建模前将数量写入 stdout/备注。不要根据对称性推断径向或重复部件的数量;源清单中的视觉设计数量才是验收依据。
  2. 以前视图为基准。 在用于验证的同一前视正交相机中创建一个不含图像的平面/参考图叠加层。添加深度前,先对齐比例、中心线和边界圆。
  3. 先在前视图的 X/Z 平面上描摹或定义二维轮廓。 根据这些轮廓构建网格表面;不要先放置通用椭圆,再尝试给它们贴图。
  4. 锁定前向投影。 只有当前轮廓匹配后,才能沿视轴添加深度。侧视/后视图用于调整厚度和叠放关系,但不得改变前向轮廓。
  5. 对于需要匹配正面图稿的纹理,请使用 Project-from-View 风格的 UV。一个朝前的表面应与对应的纹理裁剪区域按 1:1 映射。
  6. 渲染叠加验证图:将参考图/线框置于模型后方或叠加在模型上,并打印检查清单:预期数量、实际对象数量、面的位置、外轮廓边界,以及侧面/背面的深度。
  7. 如果连续两次迭代都重复同一错误,请查阅 references/best-practices.md,并在再次尝试前添加一条简短的长期备注。

对于重复图案主体,请严格按照源清单声明的数量创建主要结构组件。根据源图中可见的位置或语义角色为它们命名,并在导出前验证数量。

阶段 1 — 运行分析器

每个视图运行一次捆绑的分析器:

python3 ${CLAUDE_SKILL_DIR}/scripts/wireframe_analyzer.py <input.png> <output.json>

该脚本会输出以下结构的 JSON:

{
  "metadata": {"image_size": [W, H], "num_contours": N, "parameters": {...}},
  "contours": [[[x, y], ...], ...],
  "bezier_curves": [[[[P0], [P1], [P2], [P3]], ...], ...]
}

调整 RDP epsilon(仅在默认值无效时):

  • 输出的轮廓过少/过于锯齿 → 将 epsilon 降至 1.0–1.5。
  • 输出的噪声点过多 → 将 epsilon 提高至 3.0–4.0。
  • 通过 --rdp-epsilon 传入(或编辑脚本中的调用)。

使用 Read 读取 JSON。不要将大量 JSON 直接传给 Blender——请先提取所需内容。

阶段 2 — 生成 Blender 代码

将代码拆分为小型、自包含的代码块(每次调用 execute_blender_code 都会获得一个全新的 Python 命名空间;只有 bpy.data 会在调用之间保留)。始终重新导入所需内容。

模式:根据控制点创建 Bezier 曲线
import bpy

# Identify by stable name; bpy.data persists between calls.
name = 'GEO-lens-right'

curve_data = bpy.data.curves.new(name=name, type='CURVE')
curve_data.dimensions = '3D'
curve_data.resolution_u = 16    # tessellation resolution
curve_data.bevel_depth = 0.001  # 1 mm wire thickness (adjust for surfaces)
curve_data.use_fill_caps = True

obj = bpy.data.objects.new(name, curve_data)
bpy.context.collection.objects.link(obj)

# Control points come from the analyzer JSON (px → mm scaling done client-side).
control_points = [(0.0, 0.0, 0.0), (0.5, 1.0, 0.0), (1.5, 1.0, 0.0), (2.0, 0.0, 0.0)]

spline = curve_data.splines.new(type='BEZIER')
spline.bezier_points.add(len(control_points) - 1)
for i, (x, y, z) in enumerate(control_points):
    pt = spline.bezier_points[i]
    pt.co = (x, y, z)
    pt.handle_left_type = 'ALIGNED'   # C¹ smooth
    pt.handle_right_type = 'ALIGNED'

print(f"created:{name}")  # signal back via stdout

像素 → 世界坐标转换(在生成的代码中执行,然后再发送给 Blender):

norm_x = px_x / img_width
norm_y = 1.0 - (px_y / img_height)   # flip Y; image origin is top-left
x_world = (norm_x - 0.5) * world_width_mm / 1000.0   # to metres
y_world = (norm_y - 0.5) * world_height_mm / 1000.0
模式:将曲线转换为网格 + 清理
import bpy

name = 'GEO-lens-right'
obj = bpy.data.objects[name]

bpy.context.view_layer.objects.active = obj
bpy.ops.object.convert(target='MESH')

bpy.ops.object.mode_set(mode='EDIT')
bpy.ops.mesh.remove_doubles(threshold=0.0001)
bpy.ops.mesh.normals_make_consistent(inside=False)
bpy.ops.object.mode_set(mode='OBJECT')
bpy.ops.object.shade_smooth()

mesh = obj.data
print(f"mesh:{name} verts:{len(mesh.vertices)} polys:{len(mesh.polygons)}")
模式:PBR 材质(Principled BSDF — 唯一可由 glTF 正确导出的着色器)
import bpy

mat = bpy.data.materials.get('MAT-frame-metal') or bpy.data.materials.new('MAT-frame-metal')
mat.use_nodes = True
bsdf = mat.node_tree.nodes['Principled BSDF']
bsdf.inputs['Base Color'].default_value = (0.08, 0.08, 0.10, 1.0)
bsdf.inputs['Metallic'].default_value = 1.0
bsdf.inputs['Roughness'].default_value = 0.25

obj = bpy.data.objects['GEO-frame']
if obj.data.materials:
    obj.data.materials[0] = mat
else:
    obj.data.materials.append(mat)
print('material:assigned')

材质预设(除非用户另有指定,否则使用以下预设):

  • MAT-frame-metal — 基色 (0.08, 0.08, 0.10),metallic=1.0,roughness=0.25(拉丝钢)
  • MAT-lens-mirror — 基色 (0.05, 0.08, 0.15),metallic=0.8,roughness=0.05,IOR=1.5(镜面玻璃)
  • MAT-pad-silicone — 基色 (0.65, 0.63, 0.60),metallic=0.0,roughness=0.7(哑光硅胶)
模式:导出为 GLB
import bpy, os

filepath = '/tmp/wireframe_output.glb'
bpy.ops.export_scene.gltf(
    filepath=filepath,
    export_format='GLB',
    export_materials='EXPORT',
    export_uv=True,
    export_normals=True,
    export_animations=False,
    export_yup=True,
)
size_mb = os.path.getsize(filepath) / (1024 * 1024)
print(f"export:{filepath} size_mb:{size_mb:.2f}")

如果 size_mb > 15:应用 Decimate 并重新导出(参见错误恢复)。

阶段 3 — 验证

完成整个流程后,请先验证,再宣布成功:

  1. mcp__blender__get_scene_info — 确认预期对象存在。
  2. 对于成对部件(左/右镜片),分别调用 mcp__blender__get_object_info 并比较边界框宽度。容差:1 mm。
  3. 三角形数量:通过 get_object_info 获取。如果某个部件超出预算,请规划 Decimate。
  4. 文件大小:不得超过 15 MB 的硬性上限,最好不超过 8 MB。

错误恢复

症状可能原因修复方法
MCP 返回 Code execution error: ...生成的代码存在 Python 错误将代码拆分为更小的片段重新输出;根据错误消息追踪出错行
Could not connect to Blender插件未运行提示用户启动 Blender 和插件
Timeout waiting for Blender response代码片段过大或执行过慢将代码拆分为多个较小的 execute_blender_code 调用
多次调用之间变量未定义每次调用都会获得一个全新的命名空间重新导入模块;通过 bpy.data.objects['name'] 引用对象
分析器输出 0 条轮廓图像对比度过低使用 --gaussian-kernel 7 --canny-t1 30 重新运行
镜片不对称原始绘图不对称,或轮廓检测结果不一致提醒用户;除非用户提出要求,否则不要自动镜像
GLB 过大面数过多或嵌入式纹理过多使用比例为 0.6–0.8 的 DECIMATE 修改器;重新导出
网格存在孔洞曲线分辨率过低将 curve_data.resolution_u 提高到 24 或 32;重新转换
GLB 中缺少材质使用了非 Principled BSDF 节点仅使用 Principled BSDF 重建材质
精简代码模式(GLB > 15 MB 时)
import bpy

obj = bpy.data.objects['GEO-frame']
bpy.context.view_layer.objects.active = obj

mod = obj.modifiers.new(name='Decimate', type='DECIMATE')
mod.ratio = 0.7
mod.use_collapse_degenerate = True
bpy.ops.object.modifier_apply(modifier=mod.name)
print(f"decimated:{obj.name} verts:{len(obj.data.vertices)}")

输出给用户

完成后,请报告:

  • GLB 文件的输出路径
  • 文件大小(MB,与 15 MB 上限对比)
  • 每个部件的三角形数量(与 30 000 上限对比)
  • 已分配的材质槽
  • 任何警告(不对称、已应用精简、使用了回退方案)

示例:

✓ 已导出 /tmp/wireframe_output.glb(2.4 MB)
三角形:5 200(3 个部件:GEO-frame、GEO-lens-right、GEO-lens-left)
材质:MAT-frame-metal、MAT-lens-mirror
警告:无

何时加载更深入的参考资料

上文涵盖了 80% 的常见情况。对于少数特殊情况,请按需加载以下资料:

  • references/algorithms.md — 图像处理流程理论(Canny、RDP、最小二乘贝塞尔拟合)、二维到三维重建原理、ISO 128 正投影标准。当分析器输出看起来不正确且需要调整参数时加载。
  • references/blender-patterns.md — 全面的 Blender Python 模式(放样、曲面旋转、自定义修改器堆栈)。当用户要求非标准几何体(曲面、复杂鼻梁、可活动部件)时加载。
  • references/best-practices.md — 性能优化(foreach_set、批量操作、上下文缓存)、命名约定(Blender Studio 标准)、修改器堆栈排序。当构建速度较慢或输出拓扑不佳时加载。

约束

  • Blender ≥ 4.0(优先使用 5.x)。Principled BSDF 节点和 glTF 导出器在这些版本中均稳定。
  • 仅嵌入式 glTF(不使用 .bin 和纹理旁置文件;不使用 KTX2/Draco 压缩——Three.js 需要额外加载器,而我们尚未随附这些加载器)。
  • 仅使用 PNG 纹理(最大 1024×1024)。优先使用平涂 PBR 颜色;仅在必要时使用纹理。
  • GLB 中不包含骨骼动画。空闲动作由使用方网站通过 JS 驱动。

提示

如果用户只说“转换此线框”,默认使用:view_type=auto-detect、detail_level=production、geometry_type=hybrid、world_width_mm=auto。只有在存在多种合理解释时才询问用户澄清。

范围界定 — wireframe-to-3d 的产出与不产出的内容

此技能会将 2D 轮廓描摹并挤出为细曲线,生成输入图形的 Y 轴扁平线框表示。它不会生成:

  • 填充表面(例如镜框轮廓之间的镜片玻璃)
  • 单视图下真实的 3D 深度(输出在 Y 轴上是扁平的)
  • 多视图 3D 重建(将正面和侧面视图合并为体积)
  • 输入线条中未包含的子特征(鼻托、可活动的铰链等)
  • 可用于生产的材质(仅提供占位材质——实际材质由 blender-materials 提供)

如果要制作“完整渲染并带纹理的 X”(例如,根据线框制作 Ray-Ban Aviator),请将此技能与其他技能串联使用:

步骤技能添加的内容
1wireframe-to-3d镜框轮廓作为 3D 曲线——基础,而非最终交付物
2blender-modeling填充镜片圆盘(按镜片尺寸缩放的 UV 球体);镜腿(沿 Y 轴向后延伸的 Bezier 曲线);线框中未包含的任何 3D 细节
3blender-materials金色/银色金属镜框;使用 Metallic=0.9, Roughness=0.04 的镜面镜片材质;等等
4blender-lighting为产品拍摄布光设置 subject_class='metal'
5blender-cameras使用 85-100mm 焦距和浅景深拍摄主视觉产品图
6blender-rendering使用 Cycles 256+ 采样、降噪和 AgX 视图变换

请参阅 text-to-blender/assets/v0.9.0-validation/03_aviator_wireframe_to_3d.webp,了解 wireframe-to-3d 单独生成的效果(扁平轮廓描摹);并参阅 04_aviator_chained_upgrade.webp,了解串联编排生成的效果(Ray-Ban 风格的主视觉渲染图)。

如果用户要求根据线框制作“X 的模型”,编排器(text-to-blender)应始终规划技能串联流程。

评论

支持 Markdown