模型

模型

模型是决定方块或物品外观形状及纹理的 JSON 文件。模型由多个尺寸各异的长方体元素构成,每个面都可指定纹理。

物品使用客户端物品中定义的模型,方块使用方块状态文件中关联的模型。模型位置相对于 models 目录,例如 examplemod:item/example_model 对应 assets/examplemod/models/item/example_model.json。

格式规范

另见 Minecraft Wiki 的模型页面。

模型 JSON 根对象支持以下可选属性:

  • loader:NeoForge 新增,指定自定义模型加载器,详见模型加载器。
  • parent:以相对于 models 文件夹的资源位置指定父模型。先应用父模型的全部属性,再由当前模型中指定的属性覆盖。常见父模型有:
    • minecraft:block/block:所有方块模型的通用父模型。
    • minecraft:block/cube:所有使用 1×1×1 立方体的模型的父模型。
    • minecraft:block/cube_all:六面使用相同纹理的立方体变体,例如圆石、木板。
    • minecraft:block/cube_bottom_top:四个水平侧面共用纹理,顶面和底面各有单独纹理,例如砂岩、錾制石英块。
    • minecraft:block/cube_column:有侧面纹理和上下端纹理的立方体变体,例如原木、石英柱、紫珀柱。
    • minecraft:block/cross:两个平面使用同一纹理,分别顺时针和逆时针旋转 45°,从上方看形成 X。多数植物使用它,例如草、树苗和花。
    • minecraft:item/generated:传统二维平面物品模型的父模型,游戏中多数物品使用它。由于四边形由纹理生成,elements 段会被忽略。
    • minecraft:item/handheld:适合玩家手持显示的二维物品模型,主要用于工具。它继承 item/generated,因此也忽略 elements。
    • 方块物品经常直接使用对应的方块模型作为物品模型,但并非总是如此。例如圆石客户端物品使用 minecraft:block/cobblestone。
  • ambientocclusion:是否启用环境光遮蔽,仅对方块模型生效,默认 true。自定义方块模型出现奇怪阴影时,可尝试设为 false。
  • gui_light:取 "front" 或 "side"。前者让光从正面照射,适合二维平面;后者从侧面照射,适合三维模型,尤其是方块模型。默认 "side",只对物品模型生效。
  • textures:将名称(材质变量)映射到 Material 的子对象。材质变量可在元素中引用,也可以先在元素中引用而不在当前模型定义,由子模型提供。
    • sprite:纹理位置。
    • force_translucent:为 true 时,强制将使用此纹理的面放入 translucent 半透明层。为 false 时:
      • 若所有像素均不透明(alpha 为 255),使用 solid 层。
      • 若像素只有完全不透明或完全透明(alpha 为 0 或 255),使用 cutout 层。
      • 其他情况使用 translucent 层。

建议 方块模型还应指定 particle 纹理,用于落到方块上、在上面奔跑或破坏方块时的粒子。

物品模型还可使用 layer0、layer1 等分层纹理,较高序号绘制在较低序号上方,例如 layer1 在 layer0 上方。仅当父模型为 item/generated 时有效,且最多支持五层,即 layer0 至 layer4。

  • elements:长方体元素列表。
  • display:保存不同显示视角选项的子对象,具体键见链接页面。仅影响物品模型,但经常定义在方块模型中供物品继承。各视角都是可选子对象,含以下选项,并按此顺序应用:
    • translation:平移,以 [x, y, z] 表示。
    • rotation:旋转,以 [x, y, z] 表示。
    • scale:缩放,以 [x, y, z] 表示。
    • right_rotation:NeoForge 新增,缩放后再应用的第二次旋转,以 [x, y, z] 表示。
  • transform:见根变换。

建议 不确定某项该如何设置时,可以查看实现类似效果的原版模型。

元素

元素是长方体的 JSON 表示,支持以下属性:

  • from:起始角坐标,格式 [x, y, z],单位为 1/16 方块。例如 [0, 0, 0] 表示“左下”角,[8, 8, 8] 是中心,[16, 16, 16] 是“右上”角。
  • to:结束角坐标,格式及单位同 from。

建议 Minecraft 将 from 和 to 限制在 [-16, 32] 范围内,但强烈不建议超出 [0, 16],否则可能出现光照或剔除问题。

  • neoforge_data:见额外面数据。
  • faces:最多六个面的数据,名称分别是 north、south、east、west、up 和 down。每个面包含:
    • uv:格式 [u1, v1, u2, v2],前两个值是纹理左上角 UV,后两个是右下角。
    • texture:该面使用的纹理,必须是带 # 前缀的纹理变量。例如名为 wood 的纹理用 #wood 引用。技术上可以省略,但会使用缺失纹理。
    • rotation:可选,将纹理顺时针旋转 90、180 或 270 度。
    • cullface:可选,指定方向上有完整方块贴住此面时,跳过渲染。方向可以是 north、south、east、west、up 或 down。
    • tintindex:可选,指定颜色处理器使用的着色索引,详见着色。默认 -1,表示不着色。
    • neoforge_data:见额外面数据。

此外,还可指定以下可选属性:

  • shade:仅用于方块模型,决定元素各面是否使用依赖方向的明暗效果,默认 true。
  • rotation:元素旋转,子对象包含:
    • angle:旋转角度,单位为度。
    • axis:旋转轴,目前不能同时绕多个轴旋转。
    • origin:可选,旋转中心,格式 [x, y, z],是绝对坐标而不是相对于长方体的位置,省略时为 [0, 0, 0]。

额外面数据

neoforge_data 可以应用于整个元素或单独的面,在所有位置都可省略。同时存在元素级与面级设置时,面级设置覆盖元素级。支持:

  • color:用 ARGB 颜色给面着色,可为字符串或十进制整数,JSON 不支持十六进制字面量。默认 0xFFFFFFFF。颜色不变时,可以用它代替动态着色。
  • block_light:覆盖该面的方块光照,默认 0。
  • sky_light:覆盖该面的天空光照,默认 0。
  • ambient_occlusion:启用或禁用该面的环境光遮蔽,默认沿用模型设置。

根变换

在模型顶层添加 NeoForge 提供的 transform 属性,会在应用方块状态文件中的旋转(方块模型)或 display 中的变换(物品模型)之前,对全部几何体应用变换。

根变换有两种指定方式。第一种是在 matrix 属性中放入嵌套 JSON 数组表示的 3×4 变换矩阵,使用行主序,省略最后一行。该矩阵依次组合平移、左旋转、缩放、右旋转及变换原点。示例如下:

{
    // ...
    "transform": {
        "matrix": [
            [0, 0, 0, 0],
            [0, 0, 0, 0],
            [0, 0, 0, 0]
        ]
    }
}

第二种是用 JSON 对象任意组合以下条目,并按此顺序应用:

  • translation:相对平移,三维向量 [x, y, z],默认 [0, 0, 0]。
  • rotation 或 left_rotation:缩放之前、绕平移后的原点旋转,默认不旋转,可用以下形式:
    • 单个轴到角度的映射,例如 {"x": 90}。
    • 一组单轴映射,按列出顺序应用,例如 [{"x": 90}, {"y": 45}, {"x": -22.5}]。
    • 三个值分别表示绕各轴旋转,例如 [90, 45, -22.5]。
    • 四个值直接表示四元数,例如 [0.38268346, 0, 0, 0.9238795],表示绕 X 轴 45 度。
  • scale:相对于平移后原点的缩放,格式 [x, y, z],默认 [1, 1, 1]。
  • post_rotation 或 right_rotation:缩放后绕平移后的原点旋转,默认不旋转,格式与 rotation 相同。
  • origin:旋转和缩放的原点,变换最后也会移动到这里。可以使用三维向量 [x, y, z],或内置值 "corner"([0, 0, 0])、"center"([0.5, 0.5, 0.5])、"opposing-corner"([1, 1, 1],默认)。

方块状态文件

另见 Minecraft Wiki 的方块状态文件页面。

游戏通过方块状态文件为不同方块状态分配模型。每个已注册方块必须恰好有一个文件。指定模型有三种互斥方式:variants、multipart,以及 NeoForge 添加的定义类型。

variants 段为每种状态提供一个条目,是最常见的关联方式,绝大多数方块使用它。

  • 键为不含方块名的状态字符串。例如,不含水的上半台阶使用 "type=top,waterlogged=false",无属性方块使用 ""。未参与模型选择的属性可以省略:若 waterlogged 不影响模型,type=top,waterlogged=false 和 type=top,waterlogged=true 可合并为一个 type=top 条目。因此空字符串对任意方块也都是有效键。
  • 值是单个模型对象或模型对象数组。数组会随机选择一个模型。模型对象包含:
    • type:NeoForge 新增,设置自定义方块状态模型加载器,详见对应文档。
    • model:相对于命名空间 models 文件夹的模型路径,例如 minecraft:block/cobblestone。
    • x 和 y:绕对应轴的旋转,只能以 90 度为步长,均可省略,默认 0。
    • uvlock:旋转时是否锁定 UV,可选,默认 false。
    • weight:仅对数组有效,随机选择时的权重,可选,默认 1。

multipart 则根据状态属性组合多个元素,主要用于栅栏和墙,根据布尔属性启用四个方向的部分。每个元素由 when 和 apply 两段组成。

  • when 指定状态的字符串表示,或需要满足的属性列表。列表可命名为 "OR" 或 "AND",对内容执行对应逻辑运算。单状态或列表中的属性都可以用 | 分隔多个实际取值,例如 facing=east|facing=west。
  • apply 指定使用的模型对象或模型对象数组,工作方式与 variants 完全相同。

最后,还可通过 neoforge:definition_type 指定用于注册方块状态文件的自定义加载器,见方块状态定义加载器。

客户端物品

游戏通过客户端物品,为 ItemStack 的不同状态指定一个或多个模型。虽然模型 JSON 仍有物品专用字段,但客户端物品会根据上下文选择模型,因此多数信息已移到独立章节。

着色

草、树叶等方块会根据位置或属性改变纹理颜色。模型元素可在面上指定着色索引,由颜色处理器处理。代码提供三个事件,分别用于方块着色来源、基于生物群系的方块颜色(配合来源使用),以及物品着色来源。先看方块着色来源:

@SubscribeEvent // on the mod event bus only on the physical client
public static void registerBlockColorHandlers(RegisterColorHandlersEvent.BlockTintSources event) {
    // Parameters are the block's state, the level the block is in, the block's position, and the tint index.
    // The level and position may be null.
    event.register(
        // A list of tint sources to apply to the block. The 'tintindex' defined in
        // the model indexes into the list.
        List.of(
            // For 'tintindex: 0'.
            // Takes in the block's state.
            state -> {
                // Replace with your own calculation. See the BlockColors class for vanilla references.
                // Colors are in ARGB format.
                return 0xFFFFFFFF;
            },
            // For 'tintindex: 1',
            new BlockTintSource() {

                @Override
                public int color(BlockState state) {
                    // The default tint to apply.
                    return 0xFFFFFFFF;
                }

                @Override
                public int colorInWorld(BlockState state, BlockAndTintGetter level, BlockPos pos) {
                    // The tint to apply when the block is in the world.
                    // Defaults to `color` if not overridden.
                    return 0xFFFFFFFF;
                }

                @Override
                public int colorAsTerrainParticle(BlockState state, BlockAndTintGetter level, BlockPos pos) {
                    // The tint to apply when a `TerrainParticle` is spawned.
                    // Defaults to `colorInWorld` if not overridden.
                    return 0xFFFFFFFF;
                }
            }
        ),
        // A varargs of blocks to apply the tinting to
        EXAMPLE_BLOCK.get(), ...
    );
}

下面是颜色解析器的示例:

@SubscribeEvent // on the mod event bus only on the physical client
public static void registerColorResolvers(RegisterColorHandlersEvent.ColorResolvers event) {
    // Parameters are the current biome, the block's X position, and the block's Z position.
    event.register((biome, x, z) -> {
        // Replace with your own calculation. See the BiomeColors class for vanilla references.
        // Colors are in ARGB format.
        return 0xFFFFFFFF;
    });
}

物品着色见客户端物品文档的相关小节。

注册独立模型

没有以任何方式关联方块或物品、但其他上下文仍需使用的模型,例如方块实体渲染器中的模型,可通过 ModelEvent.RegisterStandalone 注册:

// This can be any type as long as it can be obtained from the ResolvedModel and the ModelBaker
// The generic type should be whatever is the generic type of the UnbakedStandaloneModel<T>
public static final StandaloneModelKey<QuadCollection> EXAMPLE_KEY = new StandaloneModelKey<>(
    new ModelDebugName() {
        @Override
        public String debugName() {
            // A name for the standalone model
            // Can be any string, but it should contain the mod id
            return "examplemod: Example Model";
        }
    }
);

@SubscribeEvent // on the mod event bus only on the physical client
public static void registerAdditional(ModelEvent.RegisterStandalone event) {
    event.register(
        // The model to get
        EXAMPLE_KEY,
        // An UnbakedStandaloneModel<T> we care about, in this case one that returns a QuadCollection
        // Can use the static methods from SimpleUnbakedStandaloneModel<T> for simplicity
        SimpleUnbakedStandaloneModel.quadCollection(
            // The model id, relative to `assets/<namespace>/models/<path>.json`
            Identifier.fromNamespaceAndPath("examplemod", "block/example_unused_model")
        )
    );
}

来源: NeoForged/Documentation(26.1)。中文翻译依据提交 4a680cdd4d15。