Skip to content

资源管线

从 AI 生成到游戏渲染的完整流程。

流程概览

Agnes API (AI 生成)

下载 & 裁剪

去背景处理

按类别存入文件夹

TexturePacker 打图集

上传 R2 (Cloudflare)

PixiJS 加载渲染

1. AI 生成阶段

使用 Agnes Image 2.0 Flash 生成建筑素材。

ts
// scripts/generate-building.ts
const response = await fetch('https://apihub.agnes-ai.com/v1/images/generations', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${AGNES_API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'agnes-image-2.0-flash',
    prompt: buildingPrompt,  // 基于 ai-prompt-guide.md 模板
    size: '1024x1024',
    extra_body: { response_format: 'url' },
  }),
});

2. 后处理阶段

ts
// scripts/process-building.ts
// 1. 下载图片
const image = await downloadImage(imageUrl);

// 2. 裁剪到目标尺寸
const cropped = cropToSize(image, targetWidth, targetHeight);

// 3. 去背景(如果非透明)
const cleaned = removeBackground(cropped, { threshold: 0.1 });

// 4. 保存到对应文件夹
await saveToFile(`public/assets/tiles/buildings/${category}/${name}.png`, cleaned);

3. 目录结构

public/
├── assets/
│   └── tiles/
│       └── buildings/
│           ├── residential/    # 住宅类
│           │   ├── house_a.png
│           │   ├── house_b.png
│           │   ├── inn.png
│           │   └── home.png
│           ├── commercial/     # 商业类
│           │   ├── shop.png
│           │   ├── tavern.png
│           │   ├── herb_shop.png
│           │   ├── tailor.png
│           │   └── market.png
│           ├── public/         # 公共类
│           │   ├── plaza.png
│           │   ├── temple.png
│           │   ├── library.png
│           │   ├── watchtower.png
│           │   └── cemetery.png
│           ├── industrial/     # 工业类
│           │   └── workshop.png
│           └── nature/         # 自然类
│               ├── forest.png
│               ├── farm.png
│               └── dock.png
├── sprites/
│   ├── tileset.png             # 主图集(地形/装饰)
│   └── tileset_grid.png        # 带编号的参考图
└── effects/
    ├── rain.png
    ├── snow.png
    └── petals.png

4. 图集打包

使用 TexturePacker 将每个类别的单独图片打成图集:

输入:residential/*.png
输出:residential.png + residential.json

TexturePacker 设置

json
{
  "format": "pixijs",
  "textureFormat": "png",
  "maxWidth": 1024,
  "maxHeight": 1024,
  "padding": 2,
  "extrude": 1,
  "allowRotation": false,
  "detectIdentical": true,
  "trimMode": "trim"
}

5. R2 上传

ts
// scripts/upload-to-r2.ts
import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3';

const r2 = new S3Client({
  region: 'auto',
  endpoint: `https://${ACCOUNT_ID}.r2.cloudflarestorage.com`,
  credentials: { accessKeyId: KEY_ID, secretAccessKey: SECRET },
});

async function uploadAtlas(category: string) {
  const png = await readFile(`build/${category}.png`);
  const json = await readFile(`build/${category}.json`);

  await r2.send(new PutObjectCommand({
    Bucket: 'ai-world-sim-assets',
    Key: `buildings/${category}.png`,
    Body: png,
    ContentType: 'image/png',
    CacheControl: 'public, max-age=31536000', // 1年缓存
  }));

  await r2.send(new PutObjectCommand({
    Bucket: 'ai-world-sim-assets',
    Key: `buildings/${category}.json`,
    Body: json,
    ContentType: 'application/json',
    CacheControl: 'public, max-age=31536000',
  }));
}

6. 前端加载

ts
// src/utils/textureAtlas.ts
const R2_BASE = 'https://assets.openserve.cloud';

export async function loadBuildingAtlases() {
  const categories = ['residential', 'commercial', 'public', 'industrial', 'nature'];

  await Promise.all(
    categories.map(cat =>
      Assets.load(`${R2_BASE}/buildings/${cat}.json`)
    )
  );
}

// 使用
const texture = Assets.get('residential').textures['tavern'];
const sprite = new Sprite(texture);

命名规范

类型命名格式示例
Tile{类别}_{变体}grass_1, stone_crack
建筑{类别}/{名称}commercial/tavern
角色{名字}_{动作}_{方向}_{帧号}alice_walk_south_01
特效{效果}_{帧号}rain_01
图集{类别}.pngresidential.png

季节化素材

自然类素材有4套季节变体:

public/assets/tiles/
├── terrain/
│   ├── spring_grass.png
│   ├── summer_grass.png
│   ├── autumn_grass.png
│   └── winter_grass.png
├── nature/
│   ├── spring_trees.png
│   ├── summer_trees.png
│   ├── autumn_trees.png
│   └── winter_trees.png
└── water/
    ├── spring_water.png
    ├── summer_water.png
    ├── autumn_water.png
    └── winter_water.png

建筑不需要4套,通过 PixiJS ColorMatrixFilter 做色调偏移。

完整构建脚本

json
// package.json
{
  "scripts": {
    "generate": "ts-node scripts/generate-buildings.ts",
    "process": "ts-node scripts/process-buildings.ts",
    "pack": "texturepacker --project tp-config.json",
    "upload": "ts-node scripts/upload-to-r2.ts",
    "build:assets": "npm run generate && npm run process && npm run pack && npm run upload"
  }
}

📐 建筑精灵规范见 建筑精灵规范 📐 AI Prompt 模板见 AI 出图 Prompt 指南 📐 TileSet 规范见 TileSet

Released under the MIT License.