# 资产介绍 ## 概述 资产指的是**Dagor 引擎工具**中使用的所有资源类型。 您可以在 [`application.blk`](../all-about-blk/application_blk.md)文件中找到项目中支持的资产类型列表。该文件是配置工具与项目交互方式的关键资源。 ```text assets{ types{} } ``` 在 `application.blk` 文件中,资产目录的基本路径指定为 `base:t=`。 资产主要分为三类: 1. **编辑器专用资产**: 这些是编辑器专用的资源,例如用于导出关卡。例如材质、预制件、样条类等。 2. **游戏导出资产**: 这些资源被导出到游戏中(由 `application.blk` 中的 `export{}` 块指示)。它们存储在游戏中的 `.grp` 文件中。通常情况下,出于性能考虑,关卡编辑器会使用导出的游戏资源。 3. **纹理**: 虽然这些纹理通常会导出到游戏中,但它们存储在`.dxp.bin`文件中。编辑器使用纹理缓存而不是导出纹理,这样就可以实时修改纹理。 ## 资产格式和管理 游戏和工具的资产都存储在`.blk`文件中,有两种格式: - **现代格式**: `..blk`(例如,`my_house.rendinst.blk`)。 - **传统格式**: `.blk`,其中资产类型必须在`.blk`文件中指定。 每个资产的`.blk`文件都包含该特定资源的导出程序所需的所有参数。每种类型的资源在游戏中都有自己的构建工具插件和专用代码。 在某些情况下,`.blk`文件中的说明非常少。例如,纹理资产可能只需要纹理名称(如果是 `.dds` 格式)。在其他情况下,例如特效,整个资产都定义在`.blk`文件中,而[*Asset Viewer*](../../dagor-tools/asset-viewer/asset-viewer/asset_viewer.md)则充当其编辑器。 大多数资产都没有专门的编辑工具。创建这些资产的主要方法是使用工具手动编辑和热加载。 然而,为了避免为每种简单的资产类型(如纹理、骨骼、动态模型)手动创建`.blk`文件,**Dagor** 支持一种高度灵活的虚拟资产创建系统--通过放置在资产目录中的 [`.folder.blk`](../all-about-blk/folder_blk.md) 文件来创建。 实际上,在 99.99% 的情况下,只需将纹理和模型放入相应的目录即可。许多规则,如 LOD(细节级别)切换距离和纹理转换规则,都将自动生成。 ```{note} 所有资源名称必须**唯一**。如果资源在其类型内是唯一的,系统一般就能正常运行,但最好还是确保全局唯一的名称。 ``` ## 资产类型及其规则 ### 纹理资产 纹理资产参数概述(所有参数均为可选参数,对于标准漫反射纹理 `.dds`,可能无需指定任何参数。对于 `.tga` 文件,通常需要两个参数: `convert:b=yes`, `fmt:="DXT1|DXT5"`): ```text contents{ convert:b=yes; fmt:t="DXT1|DXT5" mipmapType:t=mipmapGenerate mipFilter:t="filterKaiser"; mipFilterAlpha:r=40; mipFilterStretch:r=2 addrU:t="wrap"; addrV:t="wrap"; swizzleARGB:t="RAG0" hqMip:i=3; mqMip:i=3; lqMip:i=4 PC{ hqMip:i=2; mqMip:i=2; lqMip:i=3; } gamma:r=1 colorPadding:b=no // alphaCoverageThresMip9:i=200 // alphaCoverage:b=no // rtMipGen:b=no // aniFunc:t="abs"; // anisotropy:i=8 addrU:t="wrap"; addrV:t="wrap"; } ``` - `convert`:转换纹理(对于所有 `.tga` 或 `.psd` 纹理必须使用)。 - `fmt:t`: 指定要转换的格式(选项包括 `DXT1`、`DXT5`、`ARGB`、`L8`、`A8L8`、`L16`)。 - `mipmapType:t`: 生成 mipmap 的方法(`mipmapGenerate`、`mipmapUseExisting`、`mipmapNone`)。 - `mipFilter`: 指定用于生成 mipmap 的过滤器(`filterKaiser`, `filterBox`, `filterCubic`)。 - `hqMip`、`mqMip`、`lqMip`: 指定在高、中、低质量设置下使用的 mip 级别。 - `swizzleARGB`: 指定如何旋转纹理通道。通常不需要。 - `gamma`: 伽玛校正值(“1 ”用于法线贴图和遮罩,默认为 “2.2”)。 - `addrU`, `addrV`: 纹理寻址模式(`wrap`、`clamp`、`border`)。 ### 动态模型和渲染实例 ```text lod{ range:r=70; fname:t="$1.lod00.dag"; } lod{ range:r=200; fname:t="$1.lod01.dag"; } lod{ range:r=550; fname:t="$1.lod02.dag"; } lod{ range:r=4000; fname:t="$1.lod03.dag"; } ref_skeleton:t="$1_skeleton" texref_prefix:t="low_" all_animated:b=yes ``` - `lod`: LOD 参数。 - `range:r`: LOD 距离。 - `fname:t`: 可选文件名,默认为 `$1.lod.dag`。 - `texref_prefix:t`: 添加到模型中所有纹理引用的前缀。 - `ref_skeleton:t`: 动态模型的引用骨架,是 [*Asset Viewer*](../../dagor-tools/asset-viewer/asset-viewer/asset_viewer.md) 中正确预览所必需的。 - `all_animated:b`: 表示模型中的所有对象都应被视为动画对象,即拥有自己的矩阵。 #### 复合动态模型 复合动态模型是由共享一个共同骨架的多个动态模型组成的结构。 下面是为复合模型创建 [`.skeleton.blk`](../all-about-blk/skeleton_blk.md)文件的规则,以一辆有多个炮塔和火炮选项的坦克为例: ```text name:t="tank_body.lod00.dag" attachSubSkel{ attach_to:t="bone_turret" skel_file:t="turret_a.lod00.dag" skel_node:t="bone_turret" attachSubSkel{ attach_to:t="bone_gun_a" skel_file:t="gun_a.lod00.dag" skel_node:t="bone_gun_a" } attachSubSkel{ attach_to:t="bone_gun_b" skel_file:t="gun_b.lod00.dag" skel_node:t="bone_gun_b" add_prefix:t="G1:" } attachSubSkel{ attach_to:t="bone_gun_c" skel_file:t="gun_b.lod00.dag" skel_node:t="bone_gun_b" add_prefix:t="G2:" } } attachSubSkel{ attach_to:t="bone_turret" skel_file:t="turret_b.lod00.dag" skel_node:t="bone_turret" add_prefix:t="T1:" } ``` - `name:t`: 父模型名称。 - `attachSubSkel{}`: 用于添加动态模型的模块。 - `attach_to:t`: 父骨架中用于链接附加动态模型的节点。 - `skel_file:t`: 子模型文件名。 - `skel_node:t`: 子模型骨架中要与父模型链接的节点。 - `add_prefix:t`: 所有子模型节点的前缀。 在上面的`.skeleton.blk`文件中,由`tank_body`模型生成的骨架被扩展为`turret_a`和`turret_b`炮塔,它们连接到`bone_turret`上。在`turret_a`上,`bone_gun_a`、`bone_gun_b`和`bone_gun_c`分别连接着两门独特的火炮`gun_a`和`gun_b`。但是,`gun_b` 被两次附加到不同的骨骼上。 由于我们创建的是一个共享骨架,因此避免节点名称重复至关重要。为了解决这个问题,我们为每个重复的节点添加了一个唯一的前缀。`bone_gun_b` 的两个副本在层次结构中形成了不同的分支,它们的前缀分别为 `G1` 和 `G2`。同样,`turret_b`中的节点也有`T1`前缀。 ```{important} - 指定附加节点时,不要包含自动添加的前缀。 - 如果一个子模型附加到一个与其骨骼名称相同的节点上,前一个节点就会从层次结构中移除。不会有重复的--不用担心。 ``` 虽然从理论上讲,您可以创建非常深的依赖关系层次结构,但简单的结构更易于管理。在添加新层次之前,一定要评估其必要性。 一个多级层次结构可能是这样的 ```text name:t="papa.lod00.dag" attachSubSkel{ attach_to:t="bone_papa" skel_file:t="child.lod00.dag" skel_node:t="bone_child" add_prefix:t="layer01:" attachSubSkel{ attach_to:t="bone_child" skel_file:t="child.lod00.dag" skel_node:t="bone_child" add_prefix:t="layer02:" attachSubSkel{ attach_to:t="bone_child" skel_file:t="child.lod00.dag" skel_node:t="bone_child" add_prefix:t="layer03:" attachSubSkel{ attach_to:t="bone_child" skel_file:t="child.lod00.dag" skel_node:t="bone_child" add_prefix:t="layer04:" } } } } ``` 该层次结构展示了一个父模型(`papa.lod00.dag`),并附加了多层子模型,每个子模型都有自己的前缀,以确保唯一性和正确的层次结构管理。