AI生成3D模型技术深度测评与工具推荐
3D模型生成服务 - Tripo AI
说到3D模型生成,Tripo AI 这套 API 最近确实吸引了不少关注。每个月送 300 积分,足够折腾一阵子。下面把实际踩坑和调试细节梳理出来,希望能帮你快速上手。
一、获取 API Key
点击 Tripo AI 的 API 获取页面,申请 API Key,顺便看看使用文档。新用户每个月有 300 免费积分,够跑几次图生模型了。
二、经验分享
实际测试发现,生成 3D 模型时,图片来源有三种方式:第一种是先用 upload 接口(api.tripo3d.ai/v2/openapi/upload/sts)上传图片,拿到 file_token;第二种是用 upload STS 接口(api.tripo3d.ai/v2/openapi/upload/sts)拿到临时凭据,再通过对象存储上传;第三种是直接传一个可访问的图片 URL。如果本地没有对象存储服务,老老实实走三步最稳妥:上传图片 → 创建模型生成任务 → 轮询进度。
三、最终确定方案
没有对象存储的话,标准流程就是:
- 上传图片,拿到
image_token - 把
image_token填入模型生成接口的file_token位置 - 轮询任务直到完成
四、接口解析讲解
上传图片(可选)
上传图片的接口调用如下:
import requests
# 把你申请到的 api-key 填进来
api_key = "tsk_***"
url = "https://api.tripo3d.ai/v2/openapi/upload/sts"
headers = {"Authorization": f"Bearer {api_key}"}
file_path = 'cat.jpeg'
with open(file_path, 'rb') as f:
files = {'file': (file_path, f, 'image/jpeg')}
response = requests.post(url, headers=headers, files=files)
print(response.json())
返回结果:{"code":0,"data":{"image_token":"xxxxxxxxxxx"}} ,这个 image_token 后面要填入模型生成接口的 file_token。
- 特别说明:文件只支持 webp 和 jpeg,图片像素在 20px 到 6000px 之间,建议不低于 256px。
生成模型接口
生成模型有四种类型:图生模型、文字生模型、多文件生成模型、改进模型。这里只讲图生模型。
图生 3D 模型请求参数解析:
{
"type": "image_to_model", // 必填,任务类型
"model_version": "v3.0-20250812", // 非必填,默认 v2.5-20250123
"file": {
"type": "jpg", // 建议填图片类型
"file-token": "xxxxxxxxxxxxxxxxxxxx", // 填入上面得到的 image_token
// file-token、url、object 三者互斥,只会有一个生效
// 选了 file-token,后面的 url 和 object 参数就无效了
"url": "https://img-baofun.zhhainiao.com/fs/a9c93a228f6ffb86e1f70beec553422b.jpg", // 直接可访问的图片地址
"object": {
"bucket": "tripo-data", // 通常为 tripo-data,也可以自定义,但桶内必须有这个目录
"key": "xxxxxxxxxxxxxx" // 填入之前在 upload STS 接口拿到的 session_token
}
},
"model_seed": 84848, // 整数,控制几何生成,相同种子生成相同模型;不填则随机
"enable_image_autofix": false, // 默认为 false,设为 true 效果更好但耗时更长
// 以下参数仅对模型版本大于 v2.0-20240919 生效
"face_limit": 1000, // 面数限制,不填则自适应
"texture": true, // 默认 true,启用纹理
"pbr": true, // 默认 true,物理渲染;开启后 texture 设置失效
"texture_seed": 838383, // 纹理种子,不填则随机;想换纹理但保持模型就调整它
"texture_alignment": "original_image",// 纹理对齐:original_image 优先保证视觉效果;geometry 优先 3D 结构准确性
"texture_quality": "standard", // 纹理质量:standard 默认;detailed 更高清
"auto_size": false, // 是否自动缩放到真实比例(单位米),默认 false
"orientation": "default", // 朝向:default 或 align_image
"quad": false, // 默认 false;开启则面数设置失效,强制输出 FBX 模型
"compress": "meshopt", // 压缩类型:meshopt 网状压缩 或 geometry 几何压缩
"smart_low_poly": false, // 低多边形优化,适合简单模型;复杂模型别开
"generate_parts": false, // 部件生成,与 texture/pbr 互斥;若只生成部件需 texture 和 pbr 都设为 true
// 以下参数仅对版本大于 v3.0-20250812 生效
"geometry_quality": "standard" // detailed 提供最精细模型,standard 平衡速度与细节
}
发起图生模型请求的示例:
import requests
import json
api_key = "tsk_***"
url = "https://api.tripo3d.ai/v2/openapi/task"
data = {
"type": "image_to_model",
"file": {
"type": "jpg",
"file_token": "***"
}
}
headers = {
"Content-Type": "application/json",
"Authorization": f"Bearer {api_key}"
}
response = requests.post(url, headers=headers, json=data)
print(response.json())
返回:{"code":0,"data":{"task_id":"1ec04ced-4b87-44f6-a296-beee80777941"}}
查询任务接口
无论哪种生成任务,都要通过这个接口轮询进度。响应参数解析:
{
"task_id": "xxxxxxxxxxxxxxx", // 任务唯一标识
"type": "image_to_model", // 任务类型,如 text_to_model
"status": "success", // 中间态:queued、running;最终态:success、failed、banned、expired、cancelled、unknown
// 失败/过期/未知状态需要拿 task_id 咨询技术团队
// banned 说明操作违规,也建议咨询
// cancelled 暂时没碰到过
"input": {},
"output": { // 注意!模型和图片下载链接只有5分钟有效期
"model": "xxxxxxxxx", // 模型下载地址
"base_model": "xxxxx", // 基础模型下载地址
"pbr_model": "xxxxxxxx", // PBR 模型下载地址
"generated_image": "xxxxxxxxx", // 生成图像 URL
"rendered_image": "xxx" // 模型预览 URL
},
"progress": 0-100, // 进度,给前端显示用
"create_time": 148894989438 // 创建时间戳
}
查询示例:
import requests
api_key = "tsk_***"
task_id = "xxxxxxxxx"
url = f"https://api.tripo3d.ai/v2/openapi/task/{task_id}"
headers = {"Authorization": f"Bearer {api_key}"}
response = requests.get(url, headers=headers)
print(response.json())
返回示例(任务还在跑):
{
"code": 0,
"data": {
"task_id": "xxxxxxxxxxxxxxx",
"type": "text_to_model",
"status": "running",
"input": {"prompt": "a small cat"},
"output": {},
"progress": 99,
"create_time": 1709048933
}
}
最终 Demo
整合成一个完整的 Python 示例,包含上传、创建任务、轮询到输出结果。注意代码中的参数可根据实际需求调整。
import requests
import time
import random
from typing import Optional, Dict, Any
# ===================== 配置项 =====================
API_KEY = "tsk_xxxxxxxxxxxxxxxxxx" # 替换为你的真实 API Key
IMAGE_FILE_PATH = "doro.webp" # 图片路径
TASK_POLL_INTERVAL = 5 # 轮询间隔(秒)
TIMEOUT_SECONDS = 300 # 任务超时时间(5分钟)
# 模型生成参数配置(根据需求调整)
MODEL_CONFIG = {
"type": "image_to_model",
"model_version": "v3.0-20250812", # 使用 v3 版本
"file": {
"type": "webp", # 图片类型
"file_token": "" # 上传图片后填充
},
"model_seed": 1000, # 随机模型种子
"enable_image_autofix": True, # 开启图片自动修复(效果更好)
# v2.0+ 版本参数
# "face_limit": 2000, # 面数限制
"texture": True, # 启用纹理(pbr 为 false 时生效)
"pbr": False, # 关闭 PBR,使用普通纹理
"texture_seed": 1000, # 纹理种子
"texture_alignment": "original_image", # 优先保证视觉效果
"texture_quality": "detailed", # 高清纹理
"auto_size": False, # 不自动缩放尺寸
"orientation": "default", # 默认朝向
"quad": False, # 不强制 FBX 格式
# "compress": "meshopt", # 网状压缩
"smart_low_poly": False, # 不启用低多边形优化
"generate_parts": False, # 不生成部件
# v3.0+ 版本参数
"geometry_quality": "detailed" # 高精度几何模型
}
# ===================== 核心函数 =====================
class TripoAIClient:
def __init__(self, api_key: str):
self.api_key = api_key
self.headers = {
"Authorization": f"Bearer {self.api_key}",
"Content-Type": "application/json"
}
self.session = requests.Session() # 复用会话,提升性能
def upload_image(self, file_path: str) -> Optional[str]:
"""上传图片并获取 image_token"""
url = "https://api.tripo3d.ai/v2/openapi/upload/sts"
if not os.path.exists(file_path):
print(f"错误:图片文件 {file_path} 不存在")
return None
file_ext = os.path.splitext(file_path)[1].lstrip('.').lower()
content_type = f"image/{file_ext}"
try:
print(f"正在上传图片:{file_path}")
with open(file_path, 'rb') as f:
files = {'file': (os.path.basename(file_path), f, content_type)}
upload_headers = {"Authorization": f"Bearer {self.api_key}"}
response = self.session.post(url, headers=upload_headers, files=files, timeout=30)
response.raise_for_status()
result = response.json()
if result.get("code") == 0 and "image_token" in result.get("data", {}):
image_token = result["data"]["image_token"]
print(f"图片上传成功,image_token:{image_token}")
return image_token
else:
print(f"图片上传失败:{result}")
return None
except requests.exceptions.RequestException as e:
print(f"图片上传请求异常:{str(e)}")
return None
def create_model_task(self, image_token: str) -> Optional[str]:
"""创建 3D 模型生成任务"""
url = "https://api.tripo3d.ai/v2/openapi/task"
MODEL_CONFIG["file"]["file_token"] = image_token
try:
print(f"正在创建 3D 模型生成任务,配置:{MODEL_CONFIG}")
response = self.session.post(url, headers=self.headers, json=MODEL_CONFIG, timeout=30)
response.raise_for_status()
result = response.json()
if result.get("code") == 0 and "task_id" in result.get("data", {}):
task_id = result["data"]["task_id"]
print(f"任务创建成功,task_id:{task_id}")
return task_id
else:
print(f"任务创建失败:{result}")
return None
except requests.exceptions.RequestException as e:
print(f"创建任务请求异常:{str(e)}")
return None
def query_task_status(self, task_id: str) -> Dict[str, Any]:
"""查询任务状态"""
url = f"https://api.tripo3d.ai/v2/openapi/task/{task_id}"
try:
response = self.session.get(url, headers=self.headers, timeout=30)
response.raise_for_status()
return response.json()
except requests.exceptions.RequestException as e:
print(f"查询任务状态异常:{str(e)}")
return {"code": -1, "error": str(e)}
def poll_task_until_complete(self, task_id: str) -> Optional[Dict[str, Any]]:
"""轮询任务直到完成/失败/超时"""
start_time = time.time()
final_status = ["success", "failed", "banned", "expired", "cancelled", "unknown"]
print(f"\n开始轮询任务状态(间隔 {TASK_POLL_INTERVAL} 秒),task_id:{task_id}")
print("-" * 50)
while True:
elapsed = time.time() - start_time
if elapsed > TIMEOUT_SECONDS:
print(f"任务超时({TIMEOUT_SECONDS} 秒),终止轮询")
return None
result = self.query_task_status(task_id)
if result.get("code") != 0:
print(f"查询失败:{result.get('error', '未知错误')}")
time.sleep(TASK_POLL_INTERVAL)
continue
data = result.get("data", {})
status = data.get("status", "unknown")
progress = data.get("progress", 0)
print(f"当前状态:{status} | 进度:{progress}% | 耗时:{int(elapsed)} 秒")
if status in final_status:
print("-" * 50)
if status == "success":
print("任务执行成功!")
print(f"pbr 模型下载地址:{data.get('output', {}).get('pbr_model', '无')}")
print(f"基础模型下载地址:{data.get('output', {}).get('base_model', '无')}")
print(f"模型下载地址:{data.get('output', {}).get('model', '无')}")
print(f"预览图片地址:{data.get('output', {}).get('rendered_image', '无')}")
print("注意:下载链接有效期为 5 分钟,请及时保存!")
else:
print(f"任务结束,状态:{status}")
if status in ["failed", "expired", "unknown"]:
print(f"请联系技术团队,提供 task_id:{task_id} 排查问题")
return data
time.sleep(TASK_POLL_INTERVAL)
# ===================== 主流程 =====================
def main():
# 确保导入 os 模块
import os
client = TripoAIClient(API_KEY)
# 1. 上传图片
image_token = client.upload_image(IMAGE_FILE_PATH)
if not image_token:
print("图片上传失败,终止流程")
return
# 2. 创建生成任务
task_id = client.create_model_task(image_token)
if not task_id:
print("创建任务失败,终止流程")
return
# 3. 轮询任务进度
final_result = client.poll_task_until_complete(task_id)
if final_result and final_result.get("status") == "success":
print("\n3D 模型生成完成!所有结果已展示,请及时下载。")
else:
print("\n3D 模型生成失败或超时。")
if __name__ == "__main__":
main()
运行后会在控制台输出模型下载地址和预览图链接。下面分享一个实际跑出来的成品:
这个桃乐丝模型大概花了 120 积分,单模型文件就有 50 多 MB。
还有一点需要提醒:启动最终程序时,需要开启袋里(梯子),否则可能连不上 API 服务器。