模型(Models)
模型(Model)是用于决定方块或物品外观形状和纹理的 JSON 文件。一个模型由若干立方体元素(cuboid elements)组成,每个元素有各自的尺寸,并且每个面的纹理可以单独指定。
物品(item)会使用它的 客户端物品 中定义的模型,而方块(block)则使用 方块状态文件 中关联的模型。这些路径都是相对于 models 目录的,因此名为 examplemod:item/example_model 的模型,会对应 assets/examplemod/models/item/example_model.json 这个 JSON 文件。
规范(Specification)
另见:模型(Model)在 Minecraft Wiki 上的相关内容
一个模型(model)是一个 JSON 文件,其根标签下包含如下可选属性:
loader:NeoForge 新增。设置一个自定义模型加载器(custom model loader)。详细信息请参阅 自定义模型加载器。parent:设置父模型,格式为相对于models文件夹的 资源位置。所有父模型的属性会被应用,然后被当前模型中设置的属性覆盖。常见的父模型包括:minecraft:block/block:所有方块模型(block model)的通用父模型。minecraft:block/cube:所有使用 1x1x1 立方体模型的模型的父模型。minecraft:block/cube_all:立方体模型的一个变体,在所有六个面上使用同一个纹理,例如鹅卵石或木板。minecraft:block/cube_bottom_top:立方体模型的一个变体,四个水平面使用相同的纹理,顶部和底部分别使用不同的纹理。常见例子有砂岩或雕纹石英。minecraft:block/cube_column:立方体模型的一个变体,侧面使用一种纹理,顶部和底部使用另一种纹理。例如木头原木、石英柱和紫珀柱。minecraft:block/cross:使用两个平面和同一个纹理的 模型,一个顺时针旋转 45°,另一个逆时针旋转 45°,从上方看形成一个 X 形(因此得名)。常见于大多数植物,例如草、树苗和花。minecraft:item/generated:经典 2D 扁平物品模型的父模型。游戏中大多数物品都使用它。会忽略elements块,因为其四边形(quad)是从纹理生成的。minecraft:item/handheld:玩家实际持有时显示为 2D 扁平物品模型的父模型。主要被工具类物品使用。它是item/generated的子模型,因此同样会忽略elements块。- 方块物品(block item)通常(但不总是)使用对应的方块模型作为它们的 [物品模型][itemmodels]。例如,鹅卵石的客户端物品使用
minecraft:block/cobblestone模型。
ambientocclusion:是否启用 环境光遮蔽。仅对方块模型有效。默认为true。如果你的自定义方块模型出现奇怪的阴影,请尝试将其设为false。render_type:NeoForge 新增。设置要使用的渲染类型。详细信息请参阅 渲染类型。gui_light:可以为"front"或"side"。如果为"front",光源来自正面,适用于 2D 扁平模型。如果为"side",光源来自侧面,适用于 3D 模型(尤其是方块模型)。默认为"side"。仅对物品模型有效。textures:一个子对象,用于将名称(称为纹理变量,texture variables)映射到 纹理位置。纹理变量随后可以在 元素 中使用。你也可以在元素中指定纹理 变量,但可以留空,这样子模型就可以指定它们。- 方块模型(block models)通常还应指定一个
particle纹理。这个纹理会在踩踏、奔跑或破坏方块时被使用。 - 物品模型(item models)也可以使用图层纹理(layer textures),命名为
layer0、layer1等,其中索引更高的图层会渲染在索引较低的图层之上(例如,layer1会渲染在layer0之上)。这只在父模型为item/generated时有效,并且最多只支持 5 个图层(layer0到layer4)。
- 方块模型(block models)通常还应指定一个
elements:一个立方体 元素 的列表。display:一个子对象,包含不同 视角 下的显示选项。具体可用的键请参阅链接文章。该属性仅对物品模型生效,但通常也会在方块模型中指定,以便物品模型可以继承这些显示选项。每个视角都是可选的子对象,可能包含以下选项,按此顺序应用:translation:模型的平移,格式为[x, y, z]。rotation:模型的旋转,格式为[x, y, z]。scale:模型的缩放,格式为[x, y, z]。right_rotation:NeoForge 新增。缩放之后应用的第二次旋转,格式为[x, y, z]。
transform:参见 根变换。
如果你不知道某个属性具体应该如何指定,可以参考一个实现了类似功能的原版模型(vanilla model)。
渲染类型(Render Types)
你可以使用可选的 NeoForge 新增字段 render_type,为你的模型设置渲染类型。如果没有设置(所有原版模型均未设置),游戏会回退到 ItemBlockRenderTypes 中硬编码的渲染类型。如果 ItemBlockRenderTypes 也没有为该方块指定渲染类型,则会回退到 minecraft:solid。原版提供了以下默认渲染类型:
minecraft:solid:用于完全实心的方块,例如石头。minecraft:cutout:用于像玻璃这类方块,其任意像素要么完全不透明,要么完全透明(即没有半透明效果)。minecraft:cutout_mipped:minecraft:cutout的一个变体,在远距离时会缩小纹理以避免视觉伪影(mipmapping)。此类型不会对物品渲染应用 mipmapping,因为通常不希望在物品上使用,且可能导致伪影。例如树叶会用到此类型。minecraft:cutout_mipped_all:minecraft:cutout_mipped的变体,也会对物品模型应用 mipmapping。minecraft:translucent:用于像染色玻璃这类方块,其任意像素都可能是部分透明的。minecraft:tripwire:用于需要特殊渲染到天气目标的方块,例如绊线。neoforge:item_unlit:NeoForge 新增。应当用于那些以物品形式渲染时不考虑光照方向的方块。
选择正确的渲染类型(render type)在一定程度上关系到性能。实心(solid)渲染比 cutout 渲染更快,而 cutout 渲染又比 translucent 渲染更快。因此,你应当为你的用例指定“最严格”的渲染类型,因为这通常也是最快的。
如果需要,你也可以添加自定义渲染类型。为此,需要订阅 mod bus 事件 RegisterNamedRenderTypesEvent,并通过 #register 方法注册你的渲染类型。#register 方法有三个参数:
- 渲染类型的名称。应为以你的模组 id 作为前缀的
ResourceLocation。 - 区块渲染类型。可以使用
RenderType.chunkBufferLayers()返回列表中的任意类型。 - 实体渲染类型。必须是顶点格式为
DefaultVertexFormat.NEW_ENTITY的渲染类型。
元素(Elements)
元素(element)是立方体对象的 JSON 表示。它具有以下属性:
from:立方体起始角的坐标,格式为[x, y, z]。单位为方块的 1/16。例如,[0, 0, 0]是“左下角”,[8, 8, 8]是中心,[16, 16, 16]是方块的“右上角”。to:立方体结束角的坐标,格式为[x, y, z]。同样以方块 的 1/16 为单位。
from 和 to 的数值在 Minecraft 中被限制在 [-16, 32] 范围内。但强烈建议不要超过 [0, 16],否则会导致光照和/或剔除问题。
neoforge_data: 详见 额外面数据。faces:这是一个包含最多 6 个面的对象,分别命名为north、south、east、west、up和down。每个面都包含以下数据:uv:面的 uv 坐标,格式为[u1, v1, u2, v2],其中u1, v1是左上角的 uv 坐标,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:旋转角度,单位为度。可以是 -45 到 45 之间,以 22.5 度为步进。axis:旋转所围绕的轴。目前无法围绕多个轴同时旋转。origin:可选。旋转所围绕的原点,格式为[x, y, z]。注意这些是绝对值,即不是相对于立方体的位置。如果未指定,则默认为[0, 0, 0]。
额外面数据(Extra Face Data)
额外面数据(neoforge_data)既可以应用于一个元素,也可以应用于元素的单个面。在所有可用的上下文中,该数据都是可选的。如果同时指定了元素级和面级的额外面数据,则面级数据会覆盖元素级数据。额外数据可以包含以下内容:
color:用指定颜色对该面进行染色。必须是 ARGB 值。可以用字符串或十进制整数表示(JSON 不支持十六进制字面量)。默认为0xFFFFFFFF。如果颜色值是常量,可以用它来替代染色索引。block_light:覆盖该面使用的方块光照值。默认为 0。sky_light:覆盖该面使用的天空光照值。默认为 0。ambient_occlusion:禁用或启用该面的环境光遮蔽。默认为模型中设置的值。
根变换(Root Transforms)
在模型的顶层添加 transform 属性,会告诉加载器在 方块状态文件(针对方块模型)中的旋转操作,或者在物品模型的 display 块中的变换操作应用之前,先对所有几何体应用一次变换。这个特性是 NeoForge 新增的。
根变换(root transforms)可以通过两种方式指定。第一种方式是作为一个名为 matrix 的单独属性,内容是一个 3x4 的变换矩阵(行主序,省略最后一行),以嵌套 JSON 数组的形式表示。该矩阵依次组合了平移、左旋转、缩放、右旋转和变换原点。例如:
{
// ...
"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:绕平移后原点旋转,在缩放之前应用。默认为无旋转。可以通过以下任意一种方式指定:- 一个 JSON 对象,键为轴,值为旋转角度,例如
{"x": 90} - 一个 JSON 对象数组,每个对象指定一个轴及其旋转角度,按数组顺序依次应用,例如
[{"x": 90}, {"y": 45}, {"x": -22.5}] - 一个包含三个值的数组,分别表示绕各轴的旋转角度,例如
[90, 45, -22.5] - 一个包含四个值的数组,直接指定四元数,例如
[0.38268346, 0, 0, 0.9238795](表示绕 X 轴旋转 45 度)
- 一个 JSON 对象,键为轴,值为旋转角度,例如
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],默认值)。
方块状态文件(Blockstate Files)
另见:方块状态文件,参见 Minecraft Wiki
方块状态文件用于让游戏将不同的模型分配给不同的 [方块状态][blockstates]。每个注册到游戏中的方块,必须有且只有一个方块状态文件。为方块状态指定方块模型有两种互斥的方式:variants(变体)和 multipart(多部件)。
在 variants 块中,每个方块状态都对应一个元素。这是将方块状态与模型关联的主要方式,也是绝大多数方块所采用的方法。
-
键(key)是去掉方块名称后的方块状态(blockstate)字符串表示。例如,非注水的顶层台阶(slab)为
"type=top,waterlogged=false",而没有任何属性的方块则为""。需要注意的是,未使用的属性可以省略。例如,如果waterlogged属性对模型选择没有影响,那么type=top,waterlogged=false和type=top,waterlogged=true这两个对象可以合并为一个type=top对象。这也意味着空字符串对于所有方块都是合法的键值。 -
值(value)可以是单个模型对象,也可以是模型对象数组。如果使用模型对象数组,则会从中随机选择一个模型。一个模型对象包含以下数据:
model:模型文件的路径,相对于命名空间(namespace)的models文件夹。例如minecraft:block/cobblestone。x和y:模型在 x 轴/y 轴上的旋转角度。仅支持 90 度的整数倍。每个都是可选项,默认值为 0。uvlock:在旋转模型时是否锁定 UV 坐标。可选项,默认值为 false。weight:仅在模型对象数组中有意义。为该对象设置权重,用于随机选择模型对象时参考。可选项,默认值为 1。
相比之下,在 multipart 方块中,元素会根据方块状态(blockstate)的属性进行组合。这种方式主要被栅栏和墙体等方块使用,它们会根据布尔属性启用四个方向的部件。一个 multipart 元素由两个部分组成:when 块和 apply 块。
when块用于指定方块状态的字符串表示,或必须满足的属性列表,才能应用该元素。属性列表可以命名为"OR"或"AND",分别对其内容执行逻辑“或”或“与”操作。无论是单个方块状态还是列表值,都可以通过|分隔指定多个实际值(例如facing=east|facing=west)。apply块指定要使用的模型对象或模型对象数组。其用法与variants块完全相同。
客户端物品(Client Items)
客户端物品 被游戏用于为 ItemStack 的状态分配一个或多个模型。虽然模型 JSON 中有一些特定于物品的字段,但客户端物品会根据上下文选择模型进行渲染,因此它们的大部分信息都被移动到了专门的章节中。
着色(Tinting)
某些方块,比如草地或树叶,会根据它们的位置和/或属性动态改变其纹理颜色。模型元素 可以在其面上指定着色索引(tint index),这样颜色处理器就可以对相应的面进行处理。在代码层面,这一机制通过三个事件实现:一个用于方块颜色处理器(block color handlers),一个用于基于生物群系(biome)的方块着色(与方块颜色处理器配合使用),还有一个用于物品着色源(item tint sources)。它们的工作方式非常类似,我们先来看一个方块处理器的例子:
// 客户端模组总线事件处理器
@SubscribeEvent
public static void registerBlockColorHandlers(RegisterColorHandlersEvent.Block event) {
// 参数分别为方块的状态、方块所在的世界、方块的位置以及色彩索引(tint index)。
// 世界和位置参数可能为 null。
event.register((state, level, pos, tintIndex) -> {
// 用你自己的算法替换这里。可参考 BlockColors 类获取原版实现。
// 颜色采用 ARGB 格式。通常,如果色彩索引为 -1,表示不应进行着色,应该使用默认值。
return 0xFFFFFFFF;
},
// 这里是要应用着色的方块,可变参数形式
EXAMPLE_BLOCK.get(), ...);
}
以下是一个色彩解析器(color resolver)的示例:
// 客户端模组总线事件处理器
@SubscribeEvent
public static void registerColorResolvers(RegisterColorHandlersEvent.ColorResolvers event) {
// 参数分别为当前生物群系(biome)、方块的 X 坐标、方块的 Z 坐标。
event.register((biome, x, z) -> {
// 用你自己的算法替换这里。可参考 BiomeColors 类获取原版实现。
// 颜色采用 ARGB 格式。
return 0xFFFFFFFF;
});
}
关于物品着色(item tinting),请参见 相关的客户端物品文章章节。
注册额外模型(Registering Additional Models)
有些模型并不直接关联到某个方块或物品,但在其它场景下依然需要(例如 方块实体渲染器),可以通过 ModelEvent.RegisterAdditional 进行注册:
// 客户端模组总线事件处理器
@SubscribeEvent
public static void registerAdditional(ModelEvent.RegisterAdditional event) {
// 模型 ID,相对于 `assets/<namespace>/models/<path>.json`
event.register(ResourceLocation.fromNamespaceAndPath("examplemod", "block/example_unused_model"));
}