เทคโนโลยีโดย milo อ่าน 9 นาทีเรียบเรียงโดยมี AI ช่วย

สร้างระบบ AI-Generated 3D Assets อัตโนมัติใน Unity ด้วย Stable Diffusion และ Python API

ลองนึกภาพสิ่งของ 100 ชิ้นในเกมที่คุณกำลังทำอยู่ แล้วมี AI คอยเติมเต็มให้โดยที่คุณแทบไม่ต้องเสียเวลาวาดร่างเองเลย บทความนี้จะพาคุณสร้างระบบนั้นขึ้นมาจริง ๆ

สารบัญ

ทำไมเราถึงควรลองสร้าง 3D Assets ด้วย AI

เคยไหมที่นั่งทำโมเดล 3D อยู่คนเดียว แล้วรู้สึกว่างานเข้าเยอะเกินไป บางครั้งแค่อยากได้ขวดน้ำ กล่อง หรือโคมไฟธรรมดา ๆ ก็ต้องเสียเวลาหลายชั่วโมงในการสร้างตั้งแต่ต้น

จริงอยู่ว่าตอนนี้ AI ยังสร้างโมเดล 3D คุณภาพระดับ AAA ไม่ได้ แต่ถ้าเราพูดถึง "เฟอร์นิเจอร์พื้นฐาน" "อุปกรณ์เสริมฉาก" หรือ "ไอเทมเล็ก ๆ" ที่ใช้เติมฉากให้ดูสมบูรณ์ขึ้น AI สามารถช่วยลดเวลาได้มาก

แนวคิดของเราคือ ใช้ Stable Diffusion สร้างภาพ 2D จาก text prompt แล้วส่งต่อให้ pipeline แปลงเป็น 3D mesh พื้นฐาน จากนั้นดึงเข้า Unity ผ่าน Python API แบบอัตโนมัติ

ภาพรวมของระบบที่เราจะสร้าง

ระบบนี้แบ่งเป็น 4 ส่วนหลัก:

  1. Prompt Generator — รับคำสั่งจากผู้ใช้แล้วแปลงเป็น prompt ที่เหมาะกับการสร้าง asset
  2. Stable Diffusion Engine — สร้างภาพ 2D จาก prompt ที่ได้
  3. Image-to-3D Converter — แปลงภาพ 2D เป็น mesh โดยใช้เทคนิค depth estimation และ mesh reconstruction
  4. Unity Importer — ดึงไฟล์ 3D เข้าสู่โปรเจกต์ Unity พร้อมตั้งค่า material และ collision เบื้องต้น

ทั้งหมดนี้จะทำงานผ่าน Python script ที่สื่อสารกับ Unity ผ่าน HTTP API หรือ gRPC ก็ได้ แล้วแต่สถาปัตยกรรมที่คุณเลือก

เตรียมสภาพแวดล้อมก่อนเริ่ม

สิ่งที่ต้องมี

  • Unity 2022.3 LTS ขึ้นไป — แนะนำเวอร์ชัน LTS เพราะเสถียรกว่า
  • Python 3.10+ — รัน Stable Diffusion และ pipeline แปลง 3D
  • GPU ขั้นต่ำ 8GB VRAM — ถ้าใช้ cloud ก็ได้ เช่น RunPod หรือ Colab Pro
  • Stable Diffusion WebUI — เราจะใช้ API ของมัน
  • TripoSR หรือ Stable Fast 3D — โมเดลแปลงภาพเป็น 3D ที่ทำงานเร็วและใช้ทรัพยากรน้อย

ติดตั้งไลบรารีหลัก

pip install torch torchvision
pip install diffusers transformers accelerate
pip install trimesh numpy pillow requests
pip install flask  # สำหรับสร้าง API server

ถ้าใช้ TripoSR ให้ clone repo จาก GitHub แล้วติดตั้งตามคู่มือ:

git clone https://github.com/VAST-AI-Research/TripoSR.git
cd TripoSR
pip install -r requirements.txt

ส่วนที่ 1: สร้าง Stable Diffusion API Server

เราจะใช้ Stable Diffusion WebUI ในโหมด API เพราะสะดวกและมี community คอยสนับสนุน รันด้วยคำสั่ง:

./webui.sh --api --listen

หรือบน Windows:

webui-user.bat

แล้วเพิ่ม --api --listen ในไฟล์ webui-user.bat

เมื่อรันแล้ว API จะอยู่ที่ http://localhost:7860 เราจะเรียก endpoint /sdapi/v1/txt2img เพื่อสร้างภาพ

ส่วนที่ 2: เขียน Python Script สร้างภาพและแปลงเป็น 3D

นี่คือโครงสร้างหลักของ script:

import requests
import base64
from io import BytesIO
from PIL import Image
import torch
from tsr.system import TSR
import trimesh
import os

# ตั้งค่า
SD_API_URL = "http://localhost:7860/sdapi/v1/txt2img"
OUTPUT_DIR = "./generated_assets"
os.makedirs(OUTPUT_DIR, exist_ok=True)

def generate_image(prompt: str, filename: str) -> str:
    """สร้างภาพ 2D จาก prompt ผ่าน Stable Diffusion API"""
    payload = {
        "prompt": f"{prompt}, white background, centered, product photo, high quality",
        "negative_prompt": "blurry, distorted, multiple objects, cluttered background",
        "steps": 30,
        "width": 512,
        "height": 512,
        "cfg_scale": 7.5,
        "sampler_name": "DPM++ 2M Karras"
    }
    
    response = requests.post(SD_API_URL, json=payload)
    response.raise_for_status()
    
    image_data = response.json()["images"][0]
    image = Image.open(BytesIO(base64.b64decode(image_data)))
    
    filepath = os.path.join(OUTPUT_DIR, f"{filename}.png")
    image.save(filepath)
    return filepath

def image_to_3d(image_path: str, output_name: str) -> str:
    """แปลงภาพ 2D เป็น 3D mesh ด้วย TripoSR"""
    device = "cuda" if torch.cuda.is_available() else "cpu"
    model = TSR.from_pretrained(
        "stabilityai/TripoSR",
        config_name="config.yaml",
        weight_name="model.ckpt"
    )
    model.renderer.set_chunk_size(8192)
    model.to(device)
    
    image = Image.open(image_path).convert("RGB")
    
    with torch.no_grad():
        scene_codes = model([image], device=device)
        meshes = model.extract_mesh(scene_codes, resolution=256, threshold=0.1)
    
    mesh = meshes[0]
    output_path = os.path.join(OUTPUT_DIR, f"{output_name}.glb")
    mesh.export(output_path)
    return output_path

def generate_3d_asset(prompt: str, name: str) -> dict:
    """Pipeline หลัก: prompt → image → 3D mesh"""
    print(f"[1/3] กำลังสร้างภาพจาก prompt: {prompt}")
    img_path = generate_image(prompt, name)
    
    print(f"[2/3] กำลังแปลงภาพเป็น 3D mesh...")
    mesh_path = image_to_3d(img_path, name)
    
    print(f"[3/3] เสร็จเรียบร้อย! ไฟล์อยู่ที่: {mesh_path}")
    return {
        "name": name,
        "prompt": prompt,
        "image_path": img_path,
        "mesh_path": mesh_path
    }

ทดสอบรัน

result = generate_3d_asset(
    prompt="a vintage wooden chair",
    name="vintage_chair"
)
print(result)

ผลลัพธ์จะได้ไฟล์ vintage_chair.glb ที่สามารถเปิดใน Blender หรือ Unity ได้ทันที

ส่วนที่ 3: สร้าง Flask API รับคำสั่งจาก Unity

ตอนนี้เรามี pipeline ที่ทำงานได้แล้ว ขั้นต่อไปคือทำให้ Unity เรียกใช้ได้ผ่าน HTTP:

from flask import Flask, request, jsonify
import threading

app = Flask(__name__)

@app.route("/generate", methods=["POST"])
def generate():
    data = request.json
    prompt = data.get("prompt", "")
    name = data.get("name", "asset")
    
    if not prompt:
        return jsonify({"error": "prompt is required"}), 400
    
    # รันใน background thread เพื่อไม่บล็อก API
    def run_task():
        result = generate_3d_asset(prompt, name)
        # ส่งไฟล์ไปยัง Unity ผ่าน webhook หรือ file watcher
        notify_unity(result)
    
    threading.Thread(target=run_task, daemon=True).start()
    return jsonify({"status": "generating", "name": name})

def notify_unity(result):
    """แจ้ง Unity ว่า asset พร้อมแล้ว"""
    unity_webhook = "http://localhost:8080/asset-ready"
    requests.post(unity_webhook, json=result)

if __name__ == "__main__":
    app.run(host="0.0.0.0", port=5000)

ส่วนที่ 4: ฝั่ง Unity — รับ Asset อัตโนมัติ

ใน Unity ให้สร้าง C# script ชื่อ AssetGeneratorReceiver.cs:

using UnityEngine;
using UnityEngine.Networking;
using System.Collections;
using System.IO;

public class AssetGeneratorReceiver : MonoBehaviour
{
    [Header("Settings")]
    public string pythonApiUrl = "http://localhost:5000/generate";
    public string assetSaveFolder = "Assets/AI_Generated";

    void Start()
    {
        // สร้างโฟลเดอร์ถ้ายังไม่มี
        if (!Directory.Exists(assetSaveFolder))
        {
            Directory.CreateDirectory(assetSaveFolder);
        }
    }

    public void RequestAsset(string prompt, string name)
    {
        StartCoroutine(SendGenerationRequest(prompt, name));
    }

    IEnumerator SendGenerationRequest(string prompt, string name)
    {
        var requestData = new GenerationRequest
        {
            prompt = prompt,
            name = name
        };

        string json = JsonUtility.ToJson(requestData);
        using (UnityWebRequest req = new UnityWebRequest(pythonApiUrl, "POST"))
        {
            byte[] bodyRaw = System.Text.Encoding.UTF8.GetBytes(json);
            req.uploadHandler = new UploadHandlerRaw(bodyRaw);
            req.downloadHandler = new DownloadHandlerBuffer();
            req.SetRequestHeader("Content-Type", "application/json");

            yield return req.SendWebRequest();

            if (req.result == UnityWebRequest.Result.Success)
            {
                Debug.Log($"[AI Asset] กำลังสร้าง: {name}");
            }
            else
            {
                Debug.LogError($"[AI Asset] Error: {req.error}");
            }
        }
    }

    [System.Serializable]
    public class GenerationRequest
    {
        public string prompt;
        public string name;
    }
}

รองรับ Webhook จาก Python

เพิ่ม HTTP listener ใน Unity เพื่อรับ notification ว่า asset พร้อมแล้ว วิธีง่าย ๆ คือใช้ HttpListener:

using System.Net;
using System.Threading;

public class WebhookListener : MonoBehaviour
{
    private HttpListener listener;
    private Thread listenerThread;

    void Start()
    {
        listener = new HttpListener();
        listener.Prefixes.Add("http://localhost:8080/");
        listener.Start();

        listenerThread = new Thread(ListenLoop);
        listenerThread.Start();
    }

    void ListenLoop()
    {
        while (listener.IsListening)
        {
            var context = listener.GetContext();
            if (context.Request.Url.AbsolutePath == "/asset-ready")
            {
                using (var reader = new StreamReader(context.Request.InputStream))
                {
                    string body = reader.ReadToEnd();
                    Debug.Log($"[Webhook] Asset พร้อม: {body}");
                    // ดึงไฟล์ .glb เข้า Unity ที่นี่
                }
            }
            context.Response.Close();
        }
    }

    void OnDestroy()
    {
        listener?.Stop();
    }
}

เคล็ดลับที่ทำให้ผลลัพธ์ดีขึ้น

1. เขียน Prompt ให้เหมาะกับ 3D

Prompt ที่ดีสำหรับการสร้าง 3D asset ควรมีลักษณะเฉพาะ:

  • ใช้คำว่า white background เสมอ เพราะโมเดลแปลง 3D ต้องการภาพที่แยกวัตถุออกจากพื้นหลังชัดเจน
  • เพิ่ม centered, single object, product photo เพื่อให้วัตถุอยู่กลางเฟรม
  • หลีกเลี่ยง prompt ที่มีหลายวัตถุ เช่น "a table with food on it" เพราะจะทำให้ mesh ออกมาสับสน

2. ปรับ Resolution ตามความซับซ้อน

วัตถุเรียบง่าย เช่น กล่อง ถ้วย ใช้ resolution=128 ใน TripoSR ก็พอ แต่ถ้าเป็นวัตถุที่มีรายละเอียด เช่น รูปปั้น เฟอร์นิเจอร์ ให้เพิ่มเป็น 256 หรือ 512 แต่จะกิน VRAM มากขึ้น

3. ทำ Batch Generation

ถ้าต้องการสร้าง asset เป็นชุด แก้ script ให้รับ list ของ prompt แล้วประมวลผลเป็น batch:

batch_prompts = [
    ("wooden barrel", "barrel_01"),
    ("metal lantern", "lantern_01"),
    ("clay pot", "pot_01"),
    ("wooden crate", "crate_01")
]

for prompt, name in batch_prompts:
    generate_3d_asset(prompt, name)
    print(f"เสร็จ: {name}")

4. ใช้ LoRA เฉพาะทาง

ถ้าเกมของคุณมีสไตล์เฉพาะ เช่น low-poly หรือ cel-shaded ให้ฝึก LoRA บน Stable Diffusion ด้วยภาพตัวอย่างสไตล์ของคุณ แล้วโหลดเข้า API:

payload = {
    "prompt": "a wooden chair, low-poly style",
    "scripts": {
        "lora": {
            "model": "my_lowpoly_style.safetensors",
            "weight": 0.8
        }
    }
}

ข้อจำกัดที่ต้องรู้

ระบบนี้มีข้อจำกัดที่ต้องยอมรับตอนนี้:

  • คุณภาพ mesh ยังไม่เทียบมือนักออกแบบ — เหมาะกับ background props มากกว่า hero asset
  • Texture อาจไม่ตรงกับ UV 100% — ต้องเข้า Blender ปรับบ้างในบางครั้ง
  • ใช้เวลาประมวลผล 30–60 วินาทีต่อชิ้น — ขึ้นกับ GPU และ resolution
  • บางครั้ง mesh มี artifacts — เช่น ส่วนที่หัก หรือผิวที่ไม่สม่ำเสมอ

แต่ถ้ามองในมุมของ prototyping และการเติมฉากให้ดูสมบูรณ์ในเวลาอันสั้น ระบบนี้คุ้มค่ามาก

กรณีศึกษา: ใช้จริงในโปรเจกต์เกมเล็ก

ทีมพัฒนาเกม indie ทีม 2 คน ใช้ระบบนี้สร้าง props ให้ฉาก RPG เกมของตน พวกเขาต้องการเฟอร์นิเจอร์และอุปกรณ์ประมาณ 50 ชิ้นเพื่อเติมในหมู่บ้านเริ่มต้น

ผลคือ ใช้เวลาประมาณ 2 ชั่วโมงในการสร้างทั้ง 50 ชิ้น (รวมเวลาแก้ไขบางชิ้นใน Blender) เทียบกับการทำด้วยมือที่คาดว่าจะใช้ 3–5 วัน

สิ่งที่พวกเขาทำเพิ่มคือ หลังจากได้ mesh จาก AI แล้ว จะเข้า Blender รัน script ลด poly count แล้ว bake texture ใหม่ เพื่อให้เหมาะกับ mobile game

สรุปและก้าวต่อไป

ระบบ AI-Generated 3D Assets ที่เราสร้างวันนี้เป็นจุดเริ่มต้นที่ดี คุณสามารถขยายไปได้อีก เช่น:

  • เชื่อมต่อกับ Blender Python API เพื่อ optimize mesh อัตโนมัติ
  • เพิ่มระบบ auto-UV และ texture baking
  • สร้าง UI ใน Unity ให้นักออกแบบพิมพ์ prompt แล้วกดสร้างได้โดยตรง
  • ใช้โมเดลใหม่ ๆ เช่น Stable Fast 3D ที่เร็วและคุณภาพดีขึ้น

ลองนำโค้ดในบทความนี้ไปรันดู ปรับแต่งให้เข้ากับ workflow ของทีมคุณ แล้วอย่าลืมแชร์ผลลัพธ์ที่ได้ในคอมเมนต์ ถ้าเจอปัญหาหรือมีไอเดียพัฒนาเพิ่ม โพสต์ถามได้เลย เราอยู่ตรงนี้ครับ

เนื้อหาที่จัดทำโดยมี AI ช่วยจะมีป้ายกำกับ "เรียบเรียงโดยมี AI ช่วย" เพื่อให้คุณทราบอย่างชัดเจน เราถือว่าความโปร่งใสเรื่องการใช้ AI เป็นสิ่งสำคัญต่อความไว้วางใจของผู้อ่าน

พบข้อมูลที่ไม่ถูกต้องหรือคลาดเคลื่อน?เข้าสู่ระบบเพื่อทักท้วง
บทความนี้เป็นอย่างไร?

ยังไม่มีความคิดเห็น — มาเป็นคนแรกกันเถอะ!