meshy-3d-printing
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseMeshy 3D Printing
Meshy 3D打印
Prepare and send Meshy-generated 3D models to a slicer for 3D printing. Supports white model (single-color) and multicolor printing workflows with automatic slicer detection.
Prerequisite: This skill reuses the utility functions (, , , , etc.) and environment setup from . However, when the user wants to 3D print, this skill controls the entire workflow — including generation, format selection, downloading, and slicer integration. Do NOT run 's workflow first and then hand off here — this skill must control parameters from the start (e.g. with for multicolor).
create_taskpoll_taskdownloadget_project_dirmeshy-3d-generationmeshy-3d-generationtarget_formats"3mf"将Meshy生成的3D模型准备并发送到切片软件进行3D打印。支持白模(单色)和多色打印工作流,可自动检测切片软件。
前提条件:本技能复用中的工具函数(、、、等)和环境配置。不过,当用户需要3D打印时,本技能会控制整个工作流——包括生成、格式选择、下载和切片软件集成。请勿先运行的工作流再转交至本技能,本技能必须从一开始就控制参数(例如多色打印时需包含)。
meshy-3d-generationcreate_taskpoll_taskdownloadget_project_dirmeshy-3d-generationtarget_formats"3mf"Intent Detection
意图检测
Proactively suggest 3D printing when these keywords appear in the user's request:
- Direct: print, 3d print, slicer, slice, bambu, orca, prusa, cura, multicolor, multi-color, 3mf
- Implied: figurine, miniature, statue, physical model, desk toy, phone stand
When detected, guide the user through the appropriate print pipeline below.
当用户请求中出现以下关键词时,主动推荐3D打印功能:
- 直接关键词:print, 3d print, slicer, slice, bambu, orca, prusa, cura, multicolor, multi-color, 3mf
- 隐含关键词:figurine, miniature, statue, 实体模型, 桌面摆件, 手机支架
检测到相关需求后,引导用户使用下方对应的打印流程。
Decision Tree: White Model vs Multicolor
决策树:白模 vs 多色打印
IMPORTANT: When the user wants to 3D print, follow this flow:
- Detect installed slicers first (see Slicer Detection Script below)
- Ask the user: "Do you want a single-color (white) print or multicolor?"
- If white model → follow White Model Pipeline
- If multicolor: a. Check if a multicolor-capable slicer is installed b. Supported multicolor slicers: OrcaSlicer, Bambu Studio, Creality Print, Elegoo Slicer, Anycubic Slicer Next c. If no multicolor slicer detected, warn the user and suggest installing one d. Ask: "How many colors? (default: 4, max: 16)" and "Segmentation depth? (3=coarse, 6=fine, default: 4)" e. Confirm cost: generation (20) + texture (10) + multicolor (10) = 40 credits total f. Follow Multicolor Pipeline
重要提示:当用户需要3D打印时,遵循以下流程:
- 首先检测已安装的切片软件(参考下方切片软件检测脚本)
- 询问用户:"您需要单色(白模)打印还是多色打印?"
- 如果选择白模 → 遵循白模打印流程
- 如果选择多色: a. 检查是否安装了支持多色打印的切片软件 b. 支持的多色切片软件:OrcaSlicer、Bambu Studio、Creality Print、Elegoo Slicer、Anycubic Slicer Next c. 如果未检测到多色切片软件,向用户发出警告并建议安装对应软件 d. 询问:"需要多少种颜色?(默认4种,最多16种)"以及"分割精度?(3=粗糙,6=精细,默认4)" e. 确认成本:生成(20积分)+ 纹理(10积分)+ 多色处理(10积分)= 总计40积分 f. 遵循多色打印流程
Slicer Detection Script
切片软件检测脚本
Append this to the reusable script template from :
meshy-3d-generationpython
import subprocess, shutil, platform, os, glob as glob_mod
SLICER_MAP = {
"OrcaSlicer": {"mac_app": "OrcaSlicer", "win_exe": "orca-slicer.exe", "win_dir": "OrcaSlicer", "linux_exe": "orca-slicer"},
"Bambu Studio": {"mac_app": "BambuStudio", "win_exe": "bambu-studio.exe", "win_dir": "BambuStudio", "linux_exe": "bambu-studio"},
"Creality Print": {"mac_app": "Creality Print", "win_exe": "CrealityPrint.exe", "win_dir": "Creality Print*", "linux_exe": None},
"Elegoo Slicer": {"mac_app": "ElegooSlicer", "win_exe": "elegoo-slicer.exe", "win_dir": "ElegooSlicer", "linux_exe": None},
"Anycubic Slicer Next": {"mac_app": "AnycubicSlicerNext", "win_exe": "AnycubicSlicerNext.exe", "win_dir": "AnycubicSlicerNext", "linux_exe": None},
"PrusaSlicer": {"mac_app": "PrusaSlicer", "win_exe": "prusa-slicer.exe", "win_dir": "PrusaSlicer", "linux_exe": "prusa-slicer"},
"UltiMaker Cura": {"mac_app": "UltiMaker Cura", "win_exe": "UltiMaker-Cura.exe", "win_dir": "UltiMaker Cura*", "linux_exe": None},
}
MULTICOLOR_SLICERS = {"OrcaSlicer", "Bambu Studio", "Creality Print", "Elegoo Slicer", "Anycubic Slicer Next"}
def detect_slicers():
"""Detect installed slicer software. Returns list of {name, path, multicolor}."""
found = []
system = platform.system()
for name, info in SLICER_MAP.items():
path = None
if system == "Darwin":
app = info.get("mac_app")
if app and os.path.exists(f"/Applications/{app}.app"):
path = f"/Applications/{app}.app"
elif system == "Windows":
win_dir = info.get("win_dir", "")
win_exe = info.get("win_exe", "")
for base in [os.environ.get("ProgramFiles", r"C:\Program Files"),
os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)")]:
if "*" in win_dir:
matches = glob_mod.glob(os.path.join(base, win_dir, win_exe))
if matches:
path = matches[0]
break
else:
candidate = os.path.join(base, win_dir, win_exe)
if os.path.exists(candidate):
path = candidate
break
else: # Linux
exe = info.get("linux_exe")
if exe:
path = shutil.which(exe)
if path:
found.append({"name": name, "path": path, "multicolor": name in MULTICOLOR_SLICERS})
return found
def open_in_slicer(file_path, slicer_name):
"""Open a model file in the specified slicer."""
info = SLICER_MAP.get(slicer_name, {})
system = platform.system()
abs_path = os.path.abspath(file_path)
if system == "Darwin":
app = info.get("mac_app", slicer_name)
subprocess.run(["open", "-a", app, abs_path])
elif system == "Windows":
exe = info.get("win_exe")
exe_path = shutil.which(exe) if exe else None
if exe_path:
subprocess.Popen([exe_path, abs_path])
else:
os.startfile(abs_path)
else:
exe = info.get("linux_exe")
exe_path = shutil.which(exe) if exe else None
if exe_path:
subprocess.Popen([exe_path, abs_path])
else:
subprocess.run(["xdg-open", abs_path])
print(f"Opened {abs_path} in {slicer_name}")将以下代码追加到的可复用脚本模板中:
meshy-3d-generationpython
import subprocess, shutil, platform, os, glob as glob_mod
SLICER_MAP = {
"OrcaSlicer": {"mac_app": "OrcaSlicer", "win_exe": "orca-slicer.exe", "win_dir": "OrcaSlicer", "linux_exe": "orca-slicer"},
"Bambu Studio": {"mac_app": "BambuStudio", "win_exe": "bambu-studio.exe", "win_dir": "BambuStudio", "linux_exe": "bambu-studio"},
"Creality Print": {"mac_app": "Creality Print", "win_exe": "CrealityPrint.exe", "win_dir": "Creality Print*", "linux_exe": None},
"Elegoo Slicer": {"mac_app": "ElegooSlicer", "win_exe": "elegoo-slicer.exe", "win_dir": "ElegooSlicer", "linux_exe": None},
"Anycubic Slicer Next": {"mac_app": "AnycubicSlicerNext", "win_exe": "AnycubicSlicerNext.exe", "win_dir": "AnycubicSlicerNext", "linux_exe": None},
"PrusaSlicer": {"mac_app": "PrusaSlicer", "win_exe": "prusa-slicer.exe", "win_dir": "PrusaSlicer", "linux_exe": "prusa-slicer"},
"UltiMaker Cura": {"mac_app": "UltiMaker Cura", "win_exe": "UltiMaker-Cura.exe", "win_dir": "UltiMaker Cura*", "linux_exe": None},
}
MULTICOLOR_SLICERS = {"OrcaSlicer", "Bambu Studio", "Creality Print", "Elegoo Slicer", "Anycubic Slicer Next"}
def detect_slicers():
"""Detect installed slicer software. Returns list of {name, path, multicolor}."""
found = []
system = platform.system()
for name, info in SLICER_MAP.items():
path = None
if system == "Darwin":
app = info.get("mac_app")
if app and os.path.exists(f"/Applications/{app}.app"):
path = f"/Applications/{app}.app"
elif system == "Windows":
win_dir = info.get("win_dir", "")
win_exe = info.get("win_exe", "")
for base in [os.environ.get("ProgramFiles", r"C:\Program Files"),
os.environ.get("ProgramFiles(x86)", r"C:\Program Files (x86)")]:
if "*" in win_dir:
matches = glob_mod.glob(os.path.join(base, win_dir, win_exe))
if matches:
path = matches[0]
break
else:
candidate = os.path.join(base, win_dir, win_exe)
if os.path.exists(candidate):
path = candidate
break
else: # Linux
exe = info.get("linux_exe")
if exe:
path = shutil.which(exe)
if path:
found.append({"name": name, "path": path, "multicolor": name in MULTICOLOR_SLICERS})
return found
def open_in_slicer(file_path, slicer_name):
"""Open a model file in the specified slicer."""
info = SLICER_MAP.get(slicer_name, {})
system = platform.system()
abs_path = os.path.abspath(file_path)
if system == "Darwin":
app = info.get("mac_app", slicer_name)
subprocess.run(["open", "-a", app, abs_path])
elif system == "Windows":
exe = info.get("win_exe")
exe_path = shutil.which(exe) if exe else None
if exe_path:
subprocess.Popen([exe_path, abs_path])
else:
os.startfile(abs_path)
else:
exe = info.get("linux_exe")
exe_path = shutil.which(exe) if exe else None
if exe_path:
subprocess.Popen([exe_path, abs_path])
else:
subprocess.run(["xdg-open", abs_path])
print(f"Opened {abs_path} in {slicer_name}")--- Detect slicers ---
--- Detect slicers ---
slicers = detect_slicers()
if slicers:
print("Installed slicers:")
for s in slicers:
mc = " [multicolor]" if s["multicolor"] else ""
print(f" - {s['name']}{mc}: {s['path']}")
else:
print("No slicer software detected. Install one of: OrcaSlicer, Bambu Studio, PrusaSlicer, etc.")
---slicers = detect_slicers()
if slicers:
print("Installed slicers:")
for s in slicers:
mc = " [multicolor]" if s["multicolor"] else ""
print(f" - {s['name']}{mc}: {s['path']}")
else:
print("No slicer software detected. Install one of: OrcaSlicer, Bambu Studio, PrusaSlicer, etc.")
---White Model Print Pipeline
白模打印流程
| Step | Action | Credits | Notes |
|---|---|---|---|
| 1 | Detect installed slicers | 0 | Run slicer detection script |
| 2 | Generate untextured model | 5–20 | Text to 3D or Image to 3D ( |
| 3 | Download OBJ | 0 | OBJ format for slicer compatibility |
| 4 | Fix OBJ for printing | 0 | Coordinate conversion (see below) |
| 5 | Open in slicer | 0 | |
| 步骤 | 操作 | 积分 | 备注 |
|---|---|---|---|
| 1 | 检测已安装的切片软件 | 0 | 运行切片软件检测脚本 |
| 2 | 生成无纹理模型 | 5–20 | 文生3D或图生3D( |
| 3 | 下载OBJ格式模型 | 0 | OBJ格式适配切片软件 |
| 4 | 修复OBJ模型适配打印 | 0 | 坐标转换(参考下方代码) |
| 5 | 在切片软件中打开 | 0 | 调用 |
White Model Generation + Print Script
白模生成+打印脚本
Use the /// helpers from , then:
create_taskpoll_taskdownloadget_project_dirmeshy-3d-generationpython
undefined使用提供的///辅助函数,然后执行以下代码:
meshy-3d-generationcreate_taskpoll_taskdownloadget_project_dirpython
undefined--- Step 2: Generate untextured model for printing ---
--- Step 2: Generate untextured model for printing ---
Text to 3D:
Text to 3D:
task_id = create_task("/openapi/v2/text-to-3d", {
"mode": "preview",
"prompt": "USER_PROMPT",
"ai_model": "latest",
"target_formats": ["obj"], # Only OBJ for white model printing
})
task_id = create_task("/openapi/v2/text-to-3d", {
"mode": "preview",
"prompt": "USER_PROMPT",
"ai_model": "latest",
"target_formats": ["obj"], # Only OBJ for white model printing
})
OR Image to 3D:
OR Image to 3D:
task_id = create_task("/openapi/v1/image-to-3d", {
task_id = create_task("/openapi/v1/image-to-3d", {
"image_url": "IMAGE_URL",
"image_url": "IMAGE_URL",
"should_texture": False, # White model — no texture
"should_texture": False, # White model — no texture
"target_formats": ["glb", "obj"], # OBJ needed for slicer
"target_formats": ["glb", "obj"], # OBJ needed for slicer
})
})
task = poll_task("/openapi/v2/text-to-3d", task_id) # adjust endpoint for image-to-3d
project_dir = get_project_dir(task_id, task.get("prompt", "print"))
task = poll_task("/openapi/v2/text-to-3d", task_id) # adjust endpoint for image-to-3d
project_dir = get_project_dir(task_id, task.get("prompt", "print"))
--- Step 3-4: Download OBJ + fix for printing ---
--- Step 3-4: Download OBJ + fix for printing ---
obj_url = task["model_urls"].get("obj")
if not obj_url:
print("OBJ format not available. Available:", list(task["model_urls"].keys()))
print("Download GLB and import manually into your slicer.")
obj_url = task["model_urls"].get("glb")
obj_path = os.path.join(project_dir, "model.obj")
download(obj_url, obj_path)
obj_url = task["model_urls"].get("obj")
if not obj_url:
print("OBJ format not available. Available:", list(task["model_urls"].keys()))
print("Download GLB and import manually into your slicer.")
obj_url = task["model_urls"].get("glb")
obj_path = os.path.join(project_dir, "model.obj")
download(obj_url, obj_path)
--- Post-process OBJ for slicer compatibility ---
--- Post-process OBJ for slicer compatibility ---
def fix_obj_for_printing(input_path, output_path=None, target_height_mm=75.0):
"""
Fix OBJ coordinate system, scale, and position for 3D printing slicers.
- Rotates from glTF Y-up to slicer Z-up: (x, y, z) -> (x, -z, y)
- Scales model to target_height_mm (default 75mm)
- Centers model on XY plane
- Aligns model bottom to Z=0
"""
if output_path is None:
output_path = input_path
lines = open(input_path, "r").readlines()
rotated = []
min_x, max_x = float("inf"), float("-inf")
min_y, max_y = float("inf"), float("-inf")
min_z, max_z = float("inf"), float("-inf")
for line in lines:
if line.startswith("v "):
parts = line.split()
x, y, z = float(parts[1]), float(parts[2]), float(parts[3])
rx, ry, rz = x, -z, y
min_x, max_x = min(min_x, rx), max(max_x, rx)
min_y, max_y = min(min_y, ry), max(max_y, ry)
min_z, max_z = min(min_z, rz), max(max_z, rz)
rotated.append(("v", rx, ry, rz, parts[4:]))
elif line.startswith("vn "):
parts = line.split()
nx, ny, nz = float(parts[1]), float(parts[2]), float(parts[3])
rotated.append(("vn", nx, -nz, ny, []))
else:
rotated.append(("line", line))
model_height = max_z - min_z
scale = target_height_mm / model_height if model_height > 1e-6 else 1.0
x_offset = -(min_x + max_x) / 2.0 * scale
y_offset = -(min_y + max_y) / 2.0 * scale
z_offset = -(min_z * scale)
with open(output_path, "w") as f:
for item in rotated:
if item[0] == "v":
_, rx, ry, rz, extra = item
tx = rx * scale + x_offset
ty = ry * scale + y_offset
tz = rz * scale + z_offset
extra_str = " " + " ".join(extra) if extra else ""
f.write(f"v {tx:.6f} {ty:.6f} {tz:.6f}{extra_str}\n")
elif item[0] == "vn":
_, nx, ny, nz, _ = item
f.write(f"vn {nx:.6f} {ny:.6f} {nz:.6f}\n")
else:
f.write(item[1])
print(f"OBJ fixed: rotated Y-up→Z-up, scaled to {target_height_mm:.0f}mm, centered, bottom at Z=0")
print(f"Output: {os.path.abspath(output_path)}")fix_obj_for_printing(obj_path, target_height_mm=75.0)
def fix_obj_for_printing(input_path, output_path=None, target_height_mm=75.0):
"""
Fix OBJ coordinate system, scale, and position for 3D printing slicers.
- Rotates from glTF Y-up to slicer Z-up: (x, y, z) -> (x, -z, y)
- Scales model to target_height_mm (default 75mm)
- Centers model on XY plane
- Aligns model bottom to Z=0
"""
if output_path is None:
output_path = input_path
lines = open(input_path, "r").readlines()
rotated = []
min_x, max_x = float("inf"), float("-inf")
min_y, max_y = float("inf"), float("-inf")
min_z, max_z = float("inf"), float("-inf")
for line in lines:
if line.startswith("v "):
parts = line.split()
x, y, z = float(parts[1]), float(parts[2]), float(parts[3])
rx, ry, rz = x, -z, y
min_x, max_x = min(min_x, rx), max(max_x, rx)
min_y, max_y = min(min_y, ry), max(max_y, ry)
min_z, max_z = min(min_z, rz), max(max_z, rz)
rotated.append(("v", rx, ry, rz, parts[4:]))
elif line.startswith("vn "):
parts = line.split()
nx, ny, nz = float(parts[1]), float(parts[2]), float(parts[3])
rotated.append(("vn", nx, -nz, ny, []))
else:
rotated.append(("line", line))
model_height = max_z - min_z
scale = target_height_mm / model_height if model_height > 1e-6 else 1.0
x_offset = -(min_x + max_x) / 2.0 * scale
y_offset = -(min_y + max_y) / 2.0 * scale
z_offset = -(min_z * scale)
with open(output_path, "w") as f:
for item in rotated:
if item[0] == "v":
_, rx, ry, rz, extra = item
tx = rx * scale + x_offset
ty = ry * scale + y_offset
tz = rz * scale + z_offset
extra_str = " " + " ".join(extra) if extra else ""
f.write(f"v {tx:.6f} {ty:.6f} {tz:.6f}{extra_str}\n")
elif item[0] == "vn":
_, nx, ny, nz, _ = item
f.write(f"vn {nx:.6f} {ny:.6f} {nz:.6f}\n")
else:
f.write(item[1])
print(f"OBJ fixed: rotated Y-up→Z-up, scaled to {target_height_mm:.0f}mm, centered, bottom at Z=0")
print(f"Output: {os.path.abspath(output_path)}")fix_obj_for_printing(obj_path, target_height_mm=75.0)
--- Open in slicer ---
--- Open in slicer ---
if slicers:
open_in_slicer(obj_path, slicers[0]["name"])
else:
print(f"\nModel ready: {os.path.abspath(obj_path)}")
print("Open this file in your preferred slicer: File → Import / Open")
> **Parameters:**
> - `target_height_mm`: Default 75mm. Adjust based on user's request (e.g. "print at 15cm" → `150.0`).
---if slicers:
open_in_slicer(obj_path, slicers[0]["name"])
else:
print(f"\nModel ready: {os.path.abspath(obj_path)}")
print("Open this file in your preferred slicer: File → Import / Open")
> **参数说明**:
> - `target_height_mm`:默认75mm,可根据用户需求调整(例如用户要求"打印15厘米高"则设置为`150.0`)。
---Multicolor Print Pipeline
多色打印流程
| Step | Action | Credits | Notes |
|---|---|---|---|
| 1 | Detect slicers + check multicolor | 0 | Warn if no multicolor slicer |
| 2 | Generate 3D model | 20 | Text to 3D or Image to 3D |
| 3 | Add textures | 10 | Refine or Retexture (REQUIRED) |
| 4 | Multi-color processing | 10 | POST /openapi/v1/print/multi-color |
| 5 | Poll until SUCCEEDED | 0 | GET /openapi/v1/print/multi-color/{id} |
| 6 | Download 3MF | 0 | From model_urls["3mf"] |
| 7 | Open in multicolor slicer | 0 | |
| Total | 40 |
| 步骤 | 操作 | 积分 | 备注 |
|---|---|---|---|
| 1 | 检测切片软件+验证多色支持 | 0 | 无多色切片软件时发出警告 |
| 2 | 生成3D模型 | 20 | 文生3D或图生3D |
| 3 | 添加纹理 | 10 | 精修或重绘纹理(必填) |
| 4 | 多色处理 | 10 | 调用POST /openapi/v1/print/multi-color接口 |
| 5 | 轮询任务直到完成 | 0 | 调用GET /openapi/v1/print/multi-color/{id}接口 |
| 6 | 下载3MF格式模型 | 0 | 从 |
| 7 | 在多色切片软件中打开 | 0 | 调用 |
| 总计 | 40 |
Multi-Color Full Script
多色打印完整脚本
Use the /// helpers from :
create_taskpoll_taskdownloadget_project_dirmeshy-3d-generationpython
undefined使用提供的///辅助函数:
meshy-3d-generationcreate_taskpoll_taskdownloadget_project_dirpython
undefined--- Step 1: Check for multicolor slicer (already done above) ---
--- Step 1: Check for multicolor slicer (already done above) ---
mc_slicers = [s for s in slicers if s["multicolor"]]
if not mc_slicers:
print("WARNING: No multicolor-capable slicer detected.")
print("Supported: OrcaSlicer, Bambu Studio, Creality Print, Elegoo Slicer, Anycubic Slicer Next")
print("Install one before proceeding.")
else:
print(f"Multicolor slicer(s): {', '.join(s['name'] for s in mc_slicers)}")
mc_slicers = [s for s in slicers if s["multicolor"]]
if not mc_slicers:
print("WARNING: No multicolor-capable slicer detected.")
print("Supported: OrcaSlicer, Bambu Studio, Creality Print, Elegoo Slicer, Anycubic Slicer Next")
print("Install one before proceeding.")
else:
print(f"Multicolor slicer(s): {', '.join(s['name'] for s in mc_slicers)}")
--- Step 2-3: Generate + texture (with 3mf in target_formats!) ---
--- Step 2-3: Generate + texture (with 3mf in target_formats!) ---
Text to 3D preview:
Text to 3D preview:
preview_id = create_task("/openapi/v2/text-to-3d", {
"mode": "preview",
"prompt": "USER_PROMPT",
"ai_model": "latest",
# No target_formats needed — 3MF comes from the multi-color API, not from generate/refine
})
poll_task("/openapi/v2/text-to-3d", preview_id)
preview_id = create_task("/openapi/v2/text-to-3d", {
"mode": "preview",
"prompt": "USER_PROMPT",
"ai_model": "latest",
# No target_formats needed — 3MF comes from the multi-color API, not from generate/refine
})
poll_task("/openapi/v2/text-to-3d", preview_id)
Refine (add textures — REQUIRED for multicolor):
Refine (add textures — REQUIRED for multicolor):
refine_id = create_task("/openapi/v2/text-to-3d", {
"mode": "refine",
"preview_task_id": preview_id,
"enable_pbr": True,
})
refine_task = poll_task("/openapi/v2/text-to-3d", refine_id)
project_dir = get_project_dir(preview_id, "multicolor-print")
refine_id = create_task("/openapi/v2/text-to-3d", {
"mode": "refine",
"preview_task_id": preview_id,
"enable_pbr": True,
})
refine_task = poll_task("/openapi/v2/text-to-3d", refine_id)
project_dir = get_project_dir(preview_id, "multicolor-print")
OR for Image to 3D with texture:
OR for Image to 3D with texture:
task_id = create_task("/openapi/v1/image-to-3d", {
task_id = create_task("/openapi/v1/image-to-3d", {
"image_url": "IMAGE_URL",
"image_url": "IMAGE_URL",
"should_texture": True,
"should_texture": True,
# No target_formats needed — 3MF comes from multi-color API
# No target_formats needed — 3MF comes from multi-color API
})
})
refine_task = poll_task("/openapi/v1/image-to-3d", task_id)
refine_task = poll_task("/openapi/v1/image-to-3d", task_id)
INPUT_TASK_ID = refine_id # Use the textured task
MAX_COLORS = 4 # 1-16, ask user
MAX_DEPTH = 4 # 3-6, ask user
mc_task_id = create_task("/openapi/v1/print/multi-color", {
"input_task_id": INPUT_TASK_ID,
"max_colors": MAX_COLORS,
"max_depth": MAX_DEPTH,
})
print(f"Multi-color task created: {mc_task_id} (10 credits)")
task = poll_task("/openapi/v1/print/multi-color", mc_task_id)
INPUT_TASK_ID = refine_id # Use the textured task
MAX_COLORS = 4 # 1-16, ask user
MAX_DEPTH = 4 # 3-6, ask user
mc_task_id = create_task("/openapi/v1/print/multi-color", {
"input_task_id": INPUT_TASK_ID,
"max_colors": MAX_COLORS,
"max_depth": MAX_DEPTH,
})
print(f"Multi-color task created: {mc_task_id} (10 credits)")
task = poll_task("/openapi/v1/print/multi-color", mc_task_id)
--- Download 3MF ---
--- Download 3MF ---
threemf_url = task["model_urls"]["3mf"]
threemf_path = os.path.join(project_dir, "multicolor.3mf")
download(threemf_url, threemf_path)
print(f"3MF ready: {os.path.abspath(threemf_path)}")
threemf_url = task["model_urls"]["3mf"]
threemf_path = os.path.join(project_dir, "multicolor.3mf")
download(threemf_url, threemf_path)
print(f"3MF ready: {os.path.abspath(threemf_path)}")
--- Open in multicolor slicer ---
--- Open in multicolor slicer ---
if mc_slicers:
open_in_slicer(threemf_path, mc_slicers[0]["name"])
else:
print(f"Open {threemf_path} in a multicolor-capable slicer manually.")
---if mc_slicers:
open_in_slicer(threemf_path, mc_slicers[0]["name"])
else:
print(f"Open {threemf_path} in a multicolor-capable slicer manually.")
---Printability Checklist (Manual Review)
可打印性检查清单(人工审核)
Note: Automated printability analysis API is coming soon. For now, manually review the checklist below before printing.
| Check | Recommendation |
|---|---|
| Wall thickness | Minimum 1.2mm for FDM, 0.8mm for resin |
| Overhangs | Keep below 45° or add supports |
| Manifold mesh | Ensure watertight with no holes |
| Minimum detail | At least 0.4mm for FDM, 0.05mm for resin |
| Base stability | Flat base or add brim/raft in slicer |
| Floating parts | All parts connected or printed separately |
Recommendations: Import into your slicer to check for mesh errors. Use the slicer's built-in repair tool if needed. Consider hollowing figurines to save material.
注意:自动可打印性分析API即将上线,目前需要在打印前手动检查以下清单。
| 检查项 | 建议 |
|---|---|
| 壁厚 | FDM打印最低1.2mm,树脂打印最低0.8mm |
| 悬垂角度 | 保持在45°以下,否则添加支撑 |
| 流形网格 | 确保模型防水无孔洞 |
| 最小细节 | FDM打印至少0.4mm,树脂打印至少0.05mm |
| 底座稳定性 | 底座平整,或在切片软件中添加裙边/raft |
| 浮动部件 | 所有部件相连,或分开打印 |
建议:导入切片软件检查网格错误,如有需要可使用切片软件内置的修复工具。手办类模型建议做掏空处理节省耗材。
Key Rules for Print Workflow
打印工作流核心规则
- White model: Download OBJ format, apply for coordinate conversion
fix_obj_for_printing() - Multicolor: The multi-color API outputs 3MF directly — no coordinate conversion needed (3MF uses Z-up natively)
- 3MF for multicolor: The Multi-Color Print API outputs 3MF directly — no need to request 3MF from generate/refine via . For non-print use cases that need 3MF, pass
target_formatsin"3mf"at generation time.target_formats - Always detect slicer first and report results to the user before proceeding
- For multicolor, verify slicer supports it before proceeding with the (costly) pipeline
- After opening in slicer, remind user to check print settings (layer height, infill, supports)
- If OBJ is not available: Download GLB and guide user to import manually
- 白模打印:下载OBJ格式,调用进行坐标转换
fix_obj_for_printing() - 多色打印:多色API直接输出3MF格式,无需坐标转换(3MF原生使用Z-up坐标系)
- 多色打印用3MF:多色打印API直接输出3MF,无需在生成/精修阶段通过请求3MF。非打印场景需要3MF时,可在生成阶段传入
target_formats到"3mf"参数target_formats - 始终优先检测切片软件,在推进流程前将结果告知用户
- 多色打印前需验证切片软件支持,再推进消耗积分的流程
- 在切片软件中打开模型后,提醒用户检查打印设置(层厚、填充、支撑)
- 如果OBJ格式不可用:下载GLB格式,引导用户手动导入切片软件
Coming Soon
即将上线功能
- Printability Analysis & Fix API — Automated mesh analysis and repair (non-manifold edges, thin walls, floating parts)
- 可打印性分析与修复API——自动网格分析与修复(非流形边、薄壁、浮动部件)
Additional Resources
更多资源
For the complete API endpoint reference, read reference.md.
完整的API端点参考请查看reference.md。