Skip to main content
Version: 1.21.4

烘焙模型(Baked Models)

BakedModel 是在代码中用于表示带有纹理的形状的对象。每一个模型 JSON 文件,在被反序列化为 UnbakedModel 后,都会通过某次对 UnbakedModel#bake 的调用,转化为这种可渲染的实体。一些 方块实体渲染器 也会用到烘焙模型。模型的复杂度理论上没有上限。

所有模型都存储在 ModelManager 中,可以通过 Minecraft.getInstance().modelManager 访问。之后,你可以调用 ModelManager#getModel,通过 ModelResourceLocation 获取指定的模型。模组通常都会复用之前自动加载并烘焙好的模型。

warning

不要将这些和 物品模型 混淆,物品模型在渲染时会使用 BakedModel

BakedModel 的方法(Methods of BakedModel

getQuads

烘焙模型(baked model)中最重要的方法就是 getQuads。这个方法负责返回一组 BakedQuad,这些四边形数据会被发送到 GPU。四边形(quad)类似于建模程序(以及大多数其他游戏)中的三角形,不过由于 Minecraft 通常以方块为主,开发者选择用四边形(4 个顶点)而不是三角形(3 个顶点)来进行渲染。getQuads 方法有五个参数可用:

  • 一个 BlockState:当前被渲染的 方块状态。可能为 null,表示正在渲染物品。
  • 一个 Direction:当前被剔除(culling)的面的方向。可能为 null,表示应返回所有不会被遮挡的四边形。
  • 一个 RandomSource:客户端专用的随机源,可用于随机化效果。
  • 一个 ModelData:额外的模型数据。这里可能包含渲染时方块实体所需的附加数据。由 BakedModel#getModelData 提供。
  • 一个 RenderType:用于渲染方块的 渲染类型。可能为 null,表示应返回该模型所有渲染类型的四边形。否则,它是 BakedModel#getRenderTypes(见下文)返回的渲染类型之一。

模型应尽量进行缓存。这是因为,即使区块只会在内部方块发生变化时才重建,这个方法中的计算仍然需要尽可能快,并且由于每个区块分区(chunk section)会调用多次(每种渲染类型最多七次 × 该模型使用的渲染类型数量 × 每区块分区 4096 个方块),所以最好对结果进行大量缓存。此外,方块实体渲染器(BER)实体渲染器 可能每帧会多次调用该方法。

applyTransformgetTransforms

applyTransform 方法允许你在对模型应用透视变换(perspective transformation)时,执行自定义逻辑,甚至可以返回一个完全不同的模型。此方法由 NeoForge 添加,用于替代原版的 getTransforms() 方法。原版方法只允许你自定义变换本身,但无法控制变换的应用方式。而 applyTransform 的默认实现会委托给 getTransforms,因此如果你只需要自定义变换本身,也可以仅重写 getTransforms 即可。applyTransform 提供了三个参数:

  • 一个 ItemDisplayContext:模型将要转换到的 透视
  • 一个 PoseStack:用于渲染的姿态堆栈。
  • 一个 boolean:是否对左手渲染使用修改后的值(而不是默认的右手渲染);如果渲染的手是左手(副手,或在选项中启用左手模式时为主手),则为 true
note

applyTransformgetTransforms 只适用于物品模型(item models)。

其他方法(Others)

你可以重写和/或查询的 BakedModel 中的其他方法包括:

签名(Signature)效果(Effect)
TriState useAmbientOcclusion()是否使用 环境光遮蔽。该方法接受一个 BlockStateRenderTypeModelData 参数,并返回一个 TriState,不仅可以强制关闭 AO,也可以强制开启 AO。该方法有两个重载版本,分别只接受一个 BlockState 或无参数,并返回 boolean,但这两种写法已被弃用,建议使用第一个变体。
boolean isGui3d()判断该模型在 GUI 槽位中是以三维(3D)还是平面(flat)方式渲染。
boolean usesBlockLight()决定在为模型打光时,使用三维光照(true)还是仅从正面进行平面光照(false)。
ModelData getModelData(BlockAndTintGetter, BlockPos, BlockState, ModelData)返回用于该模型的模型数据(model data)。此方法会传入一个已有的 ModelData,如果方块有对应的方块实体(block entity),则为 BlockEntity#getModelData() 的结果,否则为 ModelData.EMPTY。这个方法适用于需要模型数据但没有方块实体的方块,例如带有连接纹理(connected textures)的方块。
TextureAtlasSprite getParticleIcon(ModelData)返回该模型使用的粒子贴图(particle sprite)。可以根据模型数据返回不同的粒子贴图。此方法为 NeoForge 新增,用于替换原版无参数的 getParticleIcon() 重载。
ChunkRenderTypeSet getRenderTypes(BlockState, RandomSource, ModelData)返回一个包含渲染该方块模型所需渲染类型(render type)的 ChunkRenderTypeSetChunkRenderTypeSet 是一个基于集合且有序的 Iterable<RenderType>。默认情况下,会回退到 从模型 JSON 获取渲染类型。仅用于方块模型,物品模型请使用下方的重载方法。
RenderType getRenderType(ItemStack)返回用于渲染物品模型的 RenderType。默认情况下,会回退到常规的模型绑定渲染类型查找。仅 物品模型 使用此方法,方块模型请使用 getRenderTypes

视角类型(Perspectives)

Minecraft 的渲染引擎一共识别 8 种物品渲染视角类型(如果算上代码内的回退机制,则有 9 种)。这些视角类型用于模型 JSON 文件中的 display 块,并在代码中通过 ItemDisplayContext 枚举(enum)来表示。

枚举值(Enum value)JSON 键(JSON key)用途(Usage)
THIRD_PERSON_RIGHT_HAND"thirdperson_righthand"第三人称视角下的右手(F5 视角,或其他玩家手中)
THIRD_PERSON_LEFT_HAND"thirdperson_lefthand"第三人称视角下的左手(F5 视角,或其他玩家手中)
FIRST_PERSON_RIGHT_HAND"firstperson_righthand"第一人称视角下的右手
FIRST_PERSON_LEFT_HAND"firstperson_lefthand"第一人称视角下的左手
HEAD"head"当物品处于玩家头部护甲栏位时(通常只能通过命令实现)
GUI"gui"物品栏、玩家快捷栏
GROUND"ground"掉落在地面的物品;注意掉落物的旋转由掉落物渲染器处理,而不是模型本身
FIXED"fixed"展示框中的物品
NONE"none"代码中的回退用途,不应在 JSON 中使用

DelegateBakedModel

DelegateBakedModel 可以用来修改已经存在的 BakedModelDelegateBakedModelBakedModel 的一个子类(subclass),它在构造函数中接收另一个 BakedModel(即“原始”模型),并默认将所有方法调用重定向到原始模型。你可以只重写(override)你需要的方法,例如:

public class MyDelegateBakedModel extends DelegateBakedModel {
// 将原始模型传递给父类构造函数。
public MyDelegateBakedModel(BakedModel originalModel) {
super(originalModel);
}

// 在这里重写你需要的方法。如果需要,也可以访问 originalModel。
}

在编写好你的模型包装器类之后,你需要将包装器应用到对应的模型上。你应该在 客户端事件处理器 中监听 ModelEvent.ModifyBakingResult,并在 mod 事件总线 上进行操作:

@SubscribeEvent
public static void modifyBakingResult(ModelEvent.ModifyBakingResult event) {
// 针对方块模型
event.getBakingResult().blockStateModels().computeIfPresent(
// 这里是要修改的模型的模型资源位置(model resource location)。可以通过
// BlockModelShaper#stateToModelLocation 方法,并传入需要影响的 blockstate 获得。
BlockModelShaper.stateToModelLocation(MyBlocksClass.EXAMPLE_BLOCK.defaultBlockState()),
// 这是一个 BiFunction,参数为位置和原始模型,返回新的模型。
(location, model) -> new MyDelegateBakedModel(model);
);
}
warning

通常建议优先使用 自定义模型加载器(custom model loader),而不是在 ModelEvent.ModifyBakingResult 事件中包装 baked models。自定义模型加载器在需要时同样可以使用 DelegateBakedModel

客户端
事件处理器
mod 事件总线
自定义模型加载器