AI生成3D模型技术深度测评与工具推荐

2026-06-18阅读 0热度 0
技术分享

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 服务器。

免责声明

本网站新闻资讯均来自公开渠道,力求准确但不保证绝对无误,内容观点仅代表作者本人,与本站无关。若涉及侵权,请联系我们处理。本站保留对声明的修改权,最终解释权归本站所有。

相关阅读

更多
欢迎回来 登录或注册后,可保存提示词和历史记录
登录后可同步收藏、历史记录和常用模板
注册即表示同意服务条款与隐私政策