Axıs
技能目录

02 · 资产管理与管线自动化

02 · 资产管理与管线自动化

管线不是"流程文档",是能自动拒绝脏数据的机器。 独立游戏没有 QA,校验器就是你的 QA。

1. 目录结构(一次定死,永不改动)

Project/
├── Art/
│   ├── _Source/            # 源文件(Blender/PS/Substance)—— 不进引擎
│   │   ├── Characters/
│   │   ├── Environment/
│   │   └── Props/
│   ├── _Working/           # WIP,允许脏,不进构建
│   ├── Characters/
│   │   ├── Hero/
│   │   │   ├── Mesh/  Textures/  Material/  Anim/  Rig/
│   │   └── Enemy_01/
│   ├── Environment/
│   │   ├── Modular_Kit_A/     # 模块化套件
│   │   ├── Props/
│   │   └── Tileables/         # 可平铺纹理
│   ├── VFX/
│   │   ├── Textures/  Flipbooks/  Meshes/  Systems/
│   ├── UI/
│   └── Shared/              # 跨项目共享:母材质、噪声、LUT、预设
├── Scenes/
│   ├── _Template/           # 光照模板场景(所有场景从此复制)
│   ├── _Test/               # 测试场景
│   └── Act1/
└── Tools/                   # TA 工具与脚本

规则

  • _ 前缀目录 = 不参与构建
  • _Source 不进引擎(避免引擎生成 .meta 污染源文件)
  • 同类资产只在一个位置(禁止"这个石头在三个文件夹里各有一份")

2. 命名规范(写进校验器强制执行)

通用格式

<类型>_<类别>_<对象>_<变体>_<后缀>

前缀表

前缀 类型 示例
SM_ Static Mesh 静态网格 SM_Env_Rock_Cliff_01
SK_ Skeletal Mesh 骨骼网格 SK_Chr_Hero_Body
T_ Texture 纹理 T_Env_Rock_Cliff_01_BC
M_ Material 材质 M_Env_Standard
MI_ Material Instance 实例 MI_Env_Rock_Cliff_01
SMI_ 共享实例 SMI_Env_Wood_All
VFX_ 特效 VFX_Combat_Hit_Slash
FB_ Flipbook FB_Fire_Explosion_8x8
BP_/Prefab_ 预制体 BP_Prop_Barrel_01
UI_ UI UI_Icon_Sword_01
SKEL_ 骨架 SKEL_Hero
PHYS_ 物理资产 PHYS_Hero
ANIM_ 动画 ANIM_Hero_Run_Fwd
DA_ 数据资产 DA_HitFeedbackConfig

纹理后缀

后缀 含义 色彩空间
_BC Base Color sRGB
_N Normal Linear
_ORM AO/Roughness/Metallic 打包 Linear
_M Mask(自定义遮罩) Linear
_E Emissive sRGB
_H Height Linear
_D Detail / Noise Linear
_LUT Lookup Table Linear

动画命名

ANIM_<角色>_<动作>_<方向?>_<变体?>
ANIM_Hero_Run_Fwd
ANIM_Hero_Attack_Combo01
ANIM_Enemy_Goblin_Death_A

命名规范的唯一目的是让脚本能自动处理。 任何无法被脚本解析的命名都是失败。

3. 导入预设自动化(省人天的第一大户)

目标:美术把文件拖进引擎,一切设置自动正确。

Unity:AssetPostprocessor

public class ArtImportSettings : AssetPostprocessor
{
    void OnPreprocessTexture()
    {
        var importer = (TextureImporter)assetImporter;
        string name = System.IO.Path.GetFileNameWithoutExtension(assetPath);

        // 按后缀判定用途
        if (name.EndsWith("_BC")) importer.sRGBTexture = true;
        else importer.sRGBTexture = false;

        if (name.EndsWith("_N")) importer.textureType = TextureImporterType.NormalMap;

        // 尺寸封顶
        importer.maxTextureSize = name.Contains("Hero") ? 2048 : 1024;

        // 平台压缩
        var pc = importer.GetPlatformTextureSettings("Standalone");
        pc.overridden = true; pc.format = TextureImporterFormat.BC7;
        importer.SetPlatformTextureSettings(pc);

        var mob = importer.GetPlatformTextureSettings("Android");
        mob.overridden = true; mob.format = TextureImporterFormat.ASTC_6x6;
        importer.SetPlatformTextureSettings(mob);

        importer.mipmapEnabled = !name.Contains("_UI");
        importer.textureCompression = TextureImporterCompression.Compressed;
    }

    void OnPreprocessModel()
    {
        var importer = (ModelImporter)assetImporter;
        importer.globalScale = 1.0f;         // 统一单位
        importer.importBlendShapes = false;  // 默认关,按需开
        importer.meshCompression = ModelImporterMeshCompression.Medium;
        importer.generateSecondaryUV = false;
        importer.materialImportMode = ModelImporterMaterialImportMode.None; // 用母材质
    }
}

UE5:Editor Utility / Python + DataAsset

import unreal
# 批量设置纹理
for asset in selected_textures:
    asset.set_editor_property("srgb", name.endswith("_BC"))
    asset.set_editor_property("compression_settings", unreal.TextureCompressionSettings.TC_DEFAULT)
    asset.set_editor_property("lod_group", unreal.TextureGroup.TEXTUREGROUP_World)
    asset.set_editor_property("max_texture_size", 1024)

Godot:.import 预设 + 导入脚本

在 project.godot 或导入脚本中按路径规则批量设 compress_mode / filter / mipmaps。

4. 资产校验器(你的 QA)

必检项目

类别 检查项 严重度
命名 符合 类型_类别_对象_变体 P1
纹理 尺寸是 2 的幂;≤ 规格上限;压缩格式正确;sRGB 正确;有 Mip P0
网格 三角面 ≤ 上限;材质槽 ≤ 上限;UV 存在且无重叠;无退化三角形 P1
网格 Pivot 在合理位置(底部/中心,不是世界原点) P1
网格 缩放为 1,旋转归零(无负缩放) P1
网格 法线朝外;无翻转面 P2
材质 使用的是母材质实例,不是独立材质 P0
材质 纹理引用完整,无丢失 P0
角色 骨骼数 ≤ 上限;命名符合规范;根骨骼存在 P1
角色 蒙皮权重 ≤ 4 骨骼/顶点;无零权重顶点 P1
动画 帧率一致;无冗余关键帧;根运动设置正确 P2
场景 无重叠物件;无漏光;无缝隙 P2

校验器实现要点

  • 入库前跑(Git pre-commit hook / 编辑器保存时 / 手动一键)
  • 输出可操作的报告:文件 / 问题 / 严重度 / 一键修复按钮
  • P0 阻止提交,P1 警告,P2 记录
  • 能自动修的就自动修(如压缩格式、尺寸封顶),不能修的才报错

最低可用版本(1 天能写完)

def validate_asset(path):
    issues = []
    if not NAME_RE.match(basename(path)): issues.append(("命名不规范", "P1"))
    if is_texture(path):
        if not is_pot(size): issues.append(("非2的幂", "P0"))
        if size > LIMIT: issues.append(("超出尺寸上限", "P0"))
        if compression != EXPECTED: issues.append(("压缩格式错误", "P0"))
        if srgb != EXPECTED: issues.append(("色彩空间错误", "P0"))
    if is_mesh(path):
        if tris > LIMIT: issues.append(("面数超标", "P1"))
        if material_slots > LIMIT: issues.append(("材质槽过多", "P1"))
        if pivot_is_world_origin: issues.append(("Pivot 在世界原点", "P1"))
        if uses_standalone_material: issues.append(("非母材质实例", "P0"))
    return issues

5. 单位与坐标系统(一次定死)

项 标准
单位 1 unit = 1 meter
轴向 Y-up 右手 / 或引擎默认(UE: Z-up 左手)——全项目统一
角色高度 1.8m(人类)—— 所有比例以此为基准
网格模数 例如 0.25m(环境模块),所有模块按此对齐
门高 2.2m · 台阶 0.15–0.2m · 栏杆 1.1m
导出缩放 Blender 导出 FBX 时 scale = 1.0(或用统一导出预设)
轴向转换 在 DCC 端修正,不要在引擎里靠旋转补丁修

最常见的坑:Blender 导出到 Unity/UE 出现 -90° X 旋转 + 100 倍缩放。 解法:写一个统一的导出预设/脚本,所有人用同一个,而不是每人手动改。

6. 版本控制与二进制

项 方案
代码/文本 Git
二进制资产 Git LFS 或 Perforce / Plastic SCM
源文件(_Source) 单独仓库或云盘,不进主仓库(太占空间)
锁机制 Perforce 有文件锁;Git 靠命名分区 + 沟通
分支 美术不要开长分支,直接主干 + 频繁提交
提交前 跑校验器(pre-commit hook)

LFS 配置示例

git lfs track "*.fbx" "*.psd" "*.png" "*.tga" "*.blend" "*.wav" "*.mp4"
git lfs track "*.unity" "*.prefab" "*.asset"   # 视情况

红线:二进制文件没进 LFS → 仓库膨胀到几十 GB → 团队崩溃。这是独立游戏最容易犯的致命错误之一。

7. 批量处理脚本库(按 ROI 排序)

脚本 省多少 人天
批量导出 FBX(Blender,应用统一导出预设) 每个资产 3 分钟 0.5
批量重命名(符合规范) 导入后整理时间 0.5
批量生成 LOD 手做 LOD 的时间 × 资产数 1
批量生成材质实例(按贴图自动匹配) 大量 0.5
批量 ORM 通道打包(PS/脚本) 大量 1
批量纹理压缩/尺寸调整 大量 0.5
场景资产清单导出(统计面数/材质/内存) 每周审计 0.5
查重(内容重复的资产) 防止仓库膨胀 0.5
未使用资产扫描 减小包体 0.5
批量贴图色板重映射(素材包统一) 素材包统一 1

8. 模块化套件(Modular Kit)—— 环境量产的核心

设计原则

原则 说明
模数统一 所有模块基于同一网格(如 0.25m / 1m / 4m)
接缝可预测 模块边缘保持一致轮廓,任意组合都不漏
材质共用 整个套件用 1–2 个母材质
UV 策略 可平铺 UV + 少量独特 UV;用三平面解决不规则面
变体靠参数 同一个墙模块,改 _Wear/_Wetness 变出不同年代
数量控制 一套套件 20–40 个模块足够撑起一个章节

检查:套件够不够用?

拿套件去搭 3 个完全不同的场景。搭不出来 → 缺模块,补;搭出来很多废模块 → 砍。

9. 资产台账(Asset Ledger)

必须有一张表,记录所有资产的来源与状态。独立游戏常因为缺这张表而在上架时踩法律雷。

字段 说明
资产名
来源 自制 / 外包 / 素材包 / AI 生成
授权类型 商用授权 / CC0 / 编辑器专属 / 需署名
许可证文件位置 路径
是否可商用 ✅/❌
是否需署名 是(署名内容)/ 否
已做风格统一 ✅/❌
使用的母材质

红线:免费版/教育版素材不得用于商业发行;AI 生成素材需确认平台条款与版权状态;任何授权不明的资产在发货前必须替换。

10. 管线成熟度自查

级别 特征
L0 混乱 靠人肉纪律;命名随意;经常丢材质;不知道哪个是最新版
L1 有文档 有命名规范和文档,但靠人执行
L2 有工具 导入预设 + 校验器 + 批量脚本,大部分自动
L3 有门禁 校验器接入提交流程,不合规无法入库;有 CI 性能回归
独立游戏目标:L2~L3(最少投入:1–3 人天)

11. 自检清单

  1. 目录结构定了吗?_Source 和引擎资产分开了吗?
  2. 命名规范能被脚本解析吗?校验器在跑吗?
  3. 导入预设生效了吗?美术还需要手动改设置吗?
  4. 单位/轴向统一了吗?导出预设是同一个吗?
  5. 二进制进 LFS 了吗?仓库多大?
  6. 母材质覆盖率 ≥ 70% 吗?有没有资产用了独立材质?
  7. 资产台账有吗?所有素材包的授权都确认了吗?
  8. 有未使用资产堆积吗?
  9. 模块化套件能搭出 3 个不同场景吗?
  10. 新成员能在 30 分钟内完成"建模→导出→导入→可用"全流程吗?不能 → 管线还不够成熟。