核心资产类型定义:数据结构设计

聊到资产库搭建,很多人一上来就急着写代码。我见过不少团队,资产存了一大堆,结果用的时候根本找不到,或者格式不统一,程序加载直接崩。说白了,问题都出在数据结构没设计好。

今天我们就来拆解五种核心资产类型:纹理、模型、材质、动画、音频。我会把我在项目中踩过的坑,还有沉淀下来的数据结构模板,一并分享给你。

纹理资产的数据结构

纹理是游戏和3D应用的“皮肤”。它不光是图片,还包含了很多元数据。比如这张图是sRGB还是线性空间?要不要生成Mipmap?

我个人习惯用这样的结构:

{
  "assetType": "texture",
  "assetId": "tex_001",
  "name": "地面砖块_漫反射",
  "filePath": "textures/floor/brick_diffuse.png",
  "format": "png",
  "width": 2048,
  "height": 2048,
  "colorSpace": "sRGB",        // sRGB 或 linear
  "mipmap": true,
  "wrapMode": "repeat",        // repeat, clamp, mirror
  "filterMode": "trilinear",   // point, bilinear, trilinear
  "compression": "BC7",        // 压缩格式
  "tags": ["地面", "砖块", "PBR"]
}

关键点:colorSpace 和 compression 最容易忽略。我曾经有个项目,法线贴图忘了设成 linear,结果光照效果全错了,排查了两天才找到原因。

小技巧:纹理命名建议统一用“用途_类型”的格式,比如“地面砖块_漫反射”。这样在资产浏览器里按名称排序,同类纹理会自动聚在一起。

模型资产的数据结构

模型资产的核心是几何数据。但光有顶点和索引不够,你还需要知道它的包围盒、顶点数、LOD层级等信息。

我建议这样设计:

{
  "assetType": "mesh",
  "assetId": "mesh_001",
  "name": "石柱_01",
  "filePath": "models/props/stone_pillar.fbx",
  "vertexCount": 3420,
  "triangleCount": 6840,
  "hasUV": true,
  "hasNormals": true,
  "hasTangents": true,
  "bounds": {
    "center": [0, 1.5, 0],
    "size": [0.8, 3.0, 0.8]
  },
  "lodLevels": [
    { "level": 0, "vertexCount": 3420, "filePath": "..." },
    { "level": 1, "vertexCount": 1200, "filePath": "..." },
    { "level": 2, "vertexCount": 400, "filePath": "..." }
  ],
  "materialSlots": ["stone_base", "stone_rough"],
  "tags": ["石柱", "建筑", "道具"]
}

嗯,这里要注意。LOD层级的数据最好单独存文件,而不是把所有层级塞进一个文件里。为什么?因为加载时你可以按需加载,内存占用更灵活。

避坑指南:我曾经把LOD0和LOD2的数据混在一个文件里,结果移动端加载时,低配机型被迫加载了高模数据,帧率直接掉到个位数。从那以后,我坚持每个LOD单独文件。

材质资产的数据结构

材质是连接纹理和模型的桥梁。它定义了物体“看起来像什么”。PBR材质是目前的主流,它的数据结构相对固定。

{
  "assetType": "material",
  "assetId": "mat_001",
  "name": "石柱_标准材质",
  "shader": "StandardPBR",
  "properties": {
    "baseColor": [0.8, 0.75, 0.7, 1.0],
    "baseColorMap": "tex_001",
    "normalMap": "tex_002",
    "roughnessMap": "tex_003",
    "metalnessMap": "tex_004",
    "aoMap": "tex_005",
    "roughness": 0.6,
    "metalness": 0.1,
    "tiling": [1, 1],
    "offset": [0, 0]
  },
  "renderQueue": 2000,
  "tags": ["石柱", "PBR", "标准"]
}

你想想看,材质资产里最容易被忽视的是什么?是 renderQueue。透明物体和不透明物体的渲染顺序完全不同。如果不设这个值,透明物体可能被不透明物体挡住,出现穿模效果。

核心原则:材质资产不要直接引用纹理文件路径,而是引用纹理的 assetId。这样当纹理文件移动或重命名时,你只需要更新纹理资产表,材质不用动。

动画资产的数据结构

动画资产分两种:骨骼动画和顶点动画。游戏里99%是骨骼动画。它的数据结构核心是“关键帧”和“曲线”。

{
  "assetType": "animation",
  "assetId": "anim_001",
  "name": "石柱_待机动画",
  "filePath": "animations/props/pillar_idle.fbx",
  "duration": 2.5,
  "frameRate": 30,
  "loop": true,
  "boneCount": 12,
  "curves": [
    {
      "boneName": "root",
      "property": "position",
      "keys": [
        { "time": 0.0, "value": [0, 0, 0] },
        { "time": 1.25, "value": [0, 0.1, 0] },
        { "time": 2.5, "value": [0, 0, 0] }
      ]
    },
    {
      "boneName": "root",
      "property": "rotation",
      "keys": [
        { "time": 0.0, "value": [0, 0, 0, 1] },
        { "time": 2.5, "value": [0, 0, 0, 1] }
      ]
    }
  ],
  "events": [
    { "time": 1.0, "type": "footstep", "params": {"surface": "stone"} }
  ],
  "tags": ["待机", "石柱", "循环"]
}

动画事件是个好东西。比如角色走路时,在脚踩地的瞬间触发脚步声。我习惯把事件直接写在动画资产里,而不是写在代码里。这样换动画时,事件自动跟着走。

经验之谈:关键帧数据建议用二进制格式存储,而不是JSON。一个2分钟的动画,JSON可能有几百KB,二进制能压缩到几十KB。加载速度差很多。

音频资产的数据结构

音频资产看起来简单,不就是个音频文件吗?其实不然。你需要知道它是2D还是3D音效,需不需要流式加载,有没有循环点。

{
  "assetType": "audio",
  "assetId": "audio_001",
  "name": "石柱_碰撞音效",
  "filePath": "audio/sfx/stone_hit.wav",
  "format": "wav",
  "duration": 0.8,
  "sampleRate": 44100,
  "channels": 1,
  "bitDepth": 16,
  "spatial": true,
  "loop": false,
  "streaming": false,
  "volume": 0.8,
  "pitch": 1.0,
  "tags": ["碰撞", "石柱", "SFX"]
}

这里有个坑:streaming 参数。背景音乐通常要流式加载,因为文件大,不能一次性全塞进内存。但短音效比如脚步声,直接加载到内存里更合适。我曾经把一段30秒的背景音乐设成了非流式,结果内存直接爆了。

总结一下:音频资产的核心元数据就三个——空间属性(2D/3D)、加载方式(流式/非流式)、循环方式。这三个定好了,其他都好说。

知识体系总览

下面这张图,我把五种资产的核心字段和关联关系画出来了。你可以把它当作设计时的检查清单。

核心资产类型数据结构总览 纹理资产 assetId colorSpace compression mipmap wrapMode filterMode tags 模型资产 assetId vertexCount triangleCount bounds lodLevels materialSlots tags 材质资产 assetId shader properties baseColorMap normalMap renderQueue tags 动画资产 assetId duration frameRate curves events loop tags 音频资产 assetId spatial streaming loop duration volume tags 材质资产通过 assetId 引用纹理资产,模型资产通过 materialSlots 引用材质资产 所有资产共有的通用字段 assetType: 资产类型标识(texture/mesh/material/animation/audio) assetId: 全局唯一ID,建议用"类型_序号"格式,如 tex_001 name: 人类可读的名称,建议统一命名规范 filePath: 相对于资产库根目录的路径 tags: 标签数组,用于搜索和分类

这张图里,我特意把通用字段单独列出来了。你设计任何资产类型,这五个字段都是标配。有了它们,你的资产库才谈得上“可管理”。

好了,五种核心资产的数据结构就聊到这儿。数据结构定好了,后续的导入、校验、打包、发布才能顺起来。记住一句话:数据结构设计花的时间,会在后面十倍百倍地省回来。


公众号:蓝海资料掘金营,微信deep3321