How to Generate 3D Models with Python - Hunyuan 3D API Tutorial

March 4, 2026
11 min read
Jan Hammer

Generate 3D Models with Python

This tutorial walks you through generating 3D models programmatically using the 3D AI Studio API and Python. By the end, you'll have working scripts for text-to-3D generation, image-to-3D conversion, and post-processing - repair, format conversion, and optimization.

The API uses a standard REST pattern: submit a request, get a task ID, poll for results. If you've used any async API before, you'll feel right at home.

Prerequisites

You need three things:

  1. A 3D AI Studio account - sign up at 3daistudio.com
  2. An API key - create one in the API Dashboard
  3. Python 3.7+ with the requests library (pip install requests)

Setup

Every request goes to https://api.3daistudio.com with your API key as a Bearer token:

import requests
import time

BASE_URL = "https://api.3daistudio.com"
API_KEY = "YOUR_API_KEY"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

Text to 3D with Hunyuan 3D Rapid

The simplest way to generate a 3D model. Describe what you want, get a GLB file back.

Hunyuan 3D Rapid costs 35 credits (base) and generates in 2-3 minutes. Add 20 credits for PBR textures.

def generate_text_to_3d(prompt, enable_pbr=False):
    """Generate a 3D model from a text description."""
    response = requests.post(
        f"{BASE_URL}/v1/3d-models/tencent/generate/rapid/",
        headers=headers,
        json={
            "prompt": prompt,
            "enable_pbr": enable_pbr,
        }
    )
    response.raise_for_status()
    return response.json()["task_id"]

Polling for Results

All generation is async. You submit a request, get a task_id, then poll until the status is FINISHED:

def poll_until_done(task_id, interval=10):
    """Poll a generation task until it completes."""
    while True:
        response = requests.get(
            f"{BASE_URL}/v1/generation-request/{task_id}/status/",
            headers=headers
        )
        response.raise_for_status()
        data = response.json()

        status = data["status"]
        progress = data.get("progress", 0)
        print(f"  Status: {status} ({progress}%)")

        if status == "FINISHED":
            return data["results"]
        elif status == "FAILED":
            raise Exception(f"Generation failed: {data}")

        time.sleep(interval)

Downloading the Model

Results include download URLs that expire after 24 hours:

def download_model(results, output_path="model.glb"):
    """Download the generated 3D model."""
    model_url = results[0]["asset"]
    response = requests.get(model_url)
    response.raise_for_status()

    with open(output_path, "wb") as f:
        f.write(response.content)

    print(f"  Saved to {output_path}")
    return output_path

Putting It Together

# Generate a 3D model from text
task_id = generate_text_to_3d("a medieval sword with ornate handle", enable_pbr=True)
print(f"Task ID: {task_id}")

# Wait for completion
results = poll_until_done(task_id)

# Download
download_model(results, "sword.glb")

This will cost 55 credits (35 base + 20 PBR) and take about 2-3 minutes.

Image to 3D with TRELLIS.2

If you have a reference image, TRELLIS.2 converts it into a 3D model with PBR materials. It's faster and cheaper than Hunyuan for image-based generation.

import base64

def image_to_3d_trellis(image_path, resolution="1024", textures=True):
    """Convert an image to a 3D model using TRELLIS.2."""
    with open(image_path, "rb") as f:
        image_b64 = base64.b64encode(f.read()).decode("utf-8")

    # Detect format from extension
    ext = image_path.rsplit(".", 1)[-1].lower()
    mime = {"png": "image/png", "jpg": "image/jpeg", "jpeg": "image/jpeg", "webp": "image/webp"}.get(ext, "image/png")

    response = requests.post(
        f"{BASE_URL}/v1/3d-models/trellis2/generate/",
        headers=headers,
        json={
            "image": f"data:{mime};base64,{image_b64}",
            "resolution": resolution,
            "textures": textures,
            "texture_size": 2048,
        }
    )
    response.raise_for_status()
    return response.json()["task_id"]

TRELLIS.2 at 1024 resolution with textures costs 30 credits and generates in about 1-2 minutes. Use it when you have a clear photo of what you want.

task_id = image_to_3d_trellis("reference_photo.png")
results = poll_until_done(task_id)
download_model(results, "from_photo.glb")

Image to 3D with Hunyuan 3D Pro

For more control, Hunyuan 3D Pro supports multi-view input, configurable polygon count, and four generation modes:

def image_to_3d_hunyuan_pro(image_path, model="3.1", enable_pbr=True, face_count=500000):
    """Convert an image to 3D using Hunyuan 3D Pro."""
    with open(image_path, "rb") as f:
        image_b64 = base64.b64encode(f.read()).decode("utf-8")

    response = requests.post(
        f"{BASE_URL}/v1/3d-models/tencent/generate/pro/",
        headers=headers,
        json={
            "model": model,
            "image": f"data:image/png;base64,{image_b64}",
            "enable_pbr": enable_pbr,
            "face_count": face_count,
        }
    )
    response.raise_for_status()
    return response.json()["task_id"]

Pro edition costs 60-100 credits and takes 3-6 minutes, but gives you polygon control (40K to 1.5M faces), generation modes (Normal, LowPoly, Geometry, Sketch), and multi-view input.

Post-Processing: Repair and Convert

Generated models often need cleanup before production use. The mesh tools API handles this:

Repair and Prepare for 3D Printing

def repair_model(model_url, output_format="stl", hollow=True, target_height=50, unit="mm"):
    """Repair a 3D model - fix geometry, hollow, and scale."""
    response = requests.post(
        f"{BASE_URL}/v1/tools/repair/",
        headers=headers,
        json={
            "model_url": model_url,
            "output_format": output_format,
            "hollow": hollow,
            "wall_thickness": 2.0,
            "target_height": target_height,
            "unit": unit,
        }
    )
    response.raise_for_status()
    return response.json()["task_id"]

Repair costs 60 credits (90 with hollowing) and takes 35-80 seconds.

Convert Between Formats

def convert_model(model_url, output_format="obj"):
    """Convert a 3D model to a different format."""
    response = requests.post(
        f"{BASE_URL}/v1/tools/convert/",
        headers=headers,
        json={
            "model_url": model_url,
            "output_format": output_format,
        }
    )
    response.raise_for_status()
    return response.json()["task_id"]

Supports GLB, OBJ, FBX, STL, and PLY in both directions. 10 credits per conversion.

Complete Pipeline Script

Here's a full end-to-end script that generates a model, repairs it, and converts it to STL:

import requests
import base64
import time

BASE_URL = "https://api.3daistudio.com"
API_KEY = "YOUR_API_KEY"
headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

def submit(endpoint, payload):
    r = requests.post(f"{BASE_URL}{endpoint}", headers=headers, json=payload)
    r.raise_for_status()
    return r.json()["task_id"]

def poll(task_id, interval=10):
    while True:
        r = requests.get(f"{BASE_URL}/v1/generation-request/{task_id}/status/", headers=headers)
        r.raise_for_status()
        data = r.json()
        print(f"  [{data['status']}] {data.get('progress', 0)}%")
        if data["status"] == "FINISHED":
            return data["results"]
        if data["status"] == "FAILED":
            raise Exception(f"Failed: {data}")
        time.sleep(interval)

def download(url, path):
    with open(path, "wb") as f:
        f.write(requests.get(url).content)
    print(f"  Saved: {path}")

# Step 1: Generate a 3D model
print("Generating 3D model...")
task_id = submit("/v1/3d-models/tencent/generate/rapid/", {
    "prompt": "a chess knight piece, detailed",
    "enable_pbr": True,
})
results = poll(task_id)
model_url = results[0]["asset"]
print(f"  Model URL: {model_url}")

# Step 2: Repair, hollow, and scale for printing
print("Repairing model...")
task_id = submit("/v1/tools/repair/", {
    "model_url": model_url,
    "output_format": "glb",
    "hollow": True,
    "wall_thickness": 2.0,
    "target_height": 50,
    "unit": "mm",
})
results = poll(task_id, interval=5)
repaired_url = results[0]["asset"]

# Step 3: Convert to STL
print("Converting to STL...")
task_id = submit("/v1/tools/convert/", {
    "model_url": repaired_url,
    "output_format": "stl",
})
results = poll(task_id, interval=5)
download(results[0]["asset"], "chess_knight.stl")

print("Done! Total cost: ~105 credits (55 + 90 + 10 = ~155 credits)")

Error Handling

The API returns standard HTTP error codes. Handle the common ones:

def safe_submit(endpoint, payload):
    r = requests.post(f"{BASE_URL}{endpoint}", headers=headers, json=payload)

    if r.status_code == 402:
        raise Exception("Insufficient credits. Top up at https://www.3daistudio.com/Platform/API")
    elif r.status_code == 429:
        print("Rate limited. Waiting 60 seconds...")
        time.sleep(60)
        return safe_submit(endpoint, payload)  # retry
    elif r.status_code == 401:
        raise Exception("Invalid API key. Check your key at https://www.3daistudio.com/Platform/API")

    r.raise_for_status()
    return r.json()["task_id"]

The default rate limit is 3 requests per minute. For higher throughput, contact the team for custom limits.

Credit Costs Reference

OperationCredits
Hunyuan Rapid (text or image to 3D)35
Hunyuan Rapid + PBR55
Hunyuan Pro (text or image to 3D)60
Hunyuan Pro + PBR + Multi-view100
TRELLIS.2 1024 with textures30
Mesh Repair60
Mesh Repair + Hollowing90
Format Conversion10
Optimize & Compress10
3D Render (image)5
3D Render (video)20
Texture Baking5

Credits are pay-as-you-go, last 365 days, and failed generations are not charged.

Next Steps

3DAI Studio

Generate 3D models with AI

Easily generate custom 3d models in seconds. Try it now and see your creativity come to life effortlessly!

Text to 3D
Image to 3D
Image Studio
Texture Generation
Quad-Remesh
4.5-Rated Excellent-1 Million+ users

Continue reading

View all