方块实体渲染器
BlockEntityRenderer 通常简称 BER,用于以静态烘焙模型(JSON、OBJ 等)无法表达的方式渲染方块,例如动态显示箱子类方块内的物品。使用方块实体渲染器时,方块必须具有 BlockEntity,即使它本身不需要存储其他数据。
要创建 BER,需要实现 BlockEntityRenderer 接口。它的泛型参数指定方块所对应的 BlockEntity 类,也是 BER 的 render 方法中方块实体参数的类型。
// Assumes the existence of MyBlockEntity as a subclass of BlockEntity.
public class MyBlockEntityRenderer implements BlockEntityRenderer<MyBlockEntity> {
// Add the constructor parameter for the lambda below. You may also use it to get some context
// to be stored in local fields, such as the entity renderer dispatcher, if needed.
public MyBlockEntityRenderer(BlockEntityRendererProvider.Context context) {
}
// This method is called every frame in order to render the block entity. Parameters are:
// - blockEntity: The block entity instance being rendered. Uses the generic type passed to the super interface.
// - partialTick: The amount of time, in fractions of a tick (0.0 to 1.0), that has passed since the last tick.
// - poseStack: The pose stack to render to.
// - bufferSource: The buffer source to get vertex buffers from.
// - packedLight: The light value of the block entity.
// - packedOverlay: The current overlay value of the block entity, usually OverlayTexture.NO_OVERLAY.
@Override
public void render(MyBlockEntity blockEntity, float partialTick, PoseStack stack, MultiBufferSource bufferSource, int packedLight, int packedOverlay) {
// Do the rendering here.
}
}
每个 BlockEntityType<?> 只能对应一个 BER。因此,属于某个方块实体实例的专有数据,应存放在该方块实体中,而不是 BER 中。
创建 BER 后,还必须通过 EntityRenderersEvent.RegisterRenderers 注册。这个事件在 Mod 事件总线上触发:
@SubscribeEvent // on the mod event bus only on the physical client
public static void registerEntityRenderers(EntityRenderersEvent.RegisterRenderers event) {
event.registerBlockEntityRenderer(
// The block entity type to register the renderer for.
MyBlockEntities.MY_BLOCK_ENTITY.get(),
// A function of BlockEntityRendererProvider.Context to BlockEntityRenderer.
MyBlockEntityRenderer::new
);
}
如果 BER 不需要使用 provider 上下文,也可以去掉构造函数:
public class MyBlockEntityRenderer implements BlockEntityRenderer<MyBlockEntity> {
@Override
public void render( /* ... */ ) { /* ... */ }
}
// In some event handler class
@SubscribeEvent // on the mod event bus only on the physical client
public static void registerEntityRenderers(EntityRenderersEvent.RegisterRenderers event) {
event.registerBlockEntityRenderer(MyBlockEntities.MY_BLOCK_ENTITY.get(),
// Pass the context to an empty (default) constructor call
context -> new MyBlockEntityRenderer()
);
}
BlockEntityWithoutLevelRenderer
BlockEntityWithoutLevelRenderer 通常简称 BEWLR,是普通 BlockEntityRenderer 面向特殊物品渲染的变体。物品没有世界上下文,因此名称中使用了“WithoutLevel”。它的用途与 BER 相同:处理静态模型无法满足的特殊渲染。
要添加 BEWLR,需要继承 BlockEntityWithoutLevelRenderer 并重写 #renderByItem。构造函数也需要进行额外设置:
public class MyBlockEntityWithoutLevelRenderer extends BlockEntityWithoutLevelRenderer {
// We need some boilerplate in the constructor, telling the superclass where to find the central block entity and entity renderers.
public MyBlockEntityWithoutLevelRenderer() {
super(Minecraft.getInstance().getBlockEntityRenderDispatcher(), Minecraft.getInstance().getEntityModels());
}
@Override
public void renderByItem(ItemStack stack, ItemDisplayContext transform, PoseStack poseStack, MultiBufferSource bufferSource, int packedLight, int packedOverlay) {
// Do the rendering here.
}
}
与 BER 一样,BEWLR 也只有一个实例。因此,属于某个物品堆的属性应存储在物品堆中,而不是 BEWLR 中。
BEWLR 不像 BER 那样直接注册。需要向 RegisterClientExtensionsEvent 注册一个 IClientItemExtensions 实例。这个接口可以指定物品的一系列渲染行为,其中就包括 BEWLR。实现方式如下:
public class MyClientItemExtensions implements IClientItemExtensions {
// Cache our BEWLR in a field.
private final MyBlockEntityWithoutLevelRenderer myBEWLR = new MyBlockEntityWithoutLevelRenderer();
// Return our BEWLR here.
@Override
public BlockEntityWithoutLevelRenderer getCustomRenderer() {
return myBEWLR;
}
}
然后通过事件注册 IClientItemExtensions:
@SubscribeEvent // on the mod event bus only on the physical client
public static void registerClientExtensions(RegisterClientExtensionsEvent event) {
event.registerItem(
// The only instance of our IClientItemExtensions, and as such, the only instance of our BEWLR.
new MyClientItemExtensions(),
// A vararg list of items that use this BEWLR.
MyItems.ITEM_1, MyItems.ITEM_2
);
}
说明 通常应将
IClientItemExtensions视为单例。不要在RegisterClientExtensionsEvent之外创建实例!
来源: NeoForged/Documentation(1.21.1)。中文翻译依据提交
4a680cdd4d15。