Skip to content

方块实体渲染器

字数
1089 字
阅读时间
5 分钟

方块实体渲染器

BlockEntityRenderer,通常缩写为 BER,用于以静态烘焙模型(JSON、OBJ 等)无法表示的方式渲染方块。例如,这可以用于动态渲染类似箱子的方块的容器内容。方块实体渲染器要求方块具有 BlockEntity,即使方块不存储任何数据。

要创建 BER,请创建一个继承自 BlockEntityRenderer 的类。它接受一个泛型参数,指定方块的 BlockEntity 类,该类用作 BER 渲染方法中的参数类型。

java
// 假设存在 MyBlockEntity 作为 BlockEntity 的子类。
public class MyBlockEntityRenderer implements BlockEntityRenderer<MyBlockEntity> {
    // 为下面的 lambda 添加构造函数参数。您也可以使用它来获取一些上下文
    // 并将其存储在本地字段中,例如实体渲染器分发器(如果需要)。
    public MyBlockEntityRenderer(BlockEntityRendererProvider.Context context) {
    }
    
    // 此方法每帧调用以渲染方块实体。参数为:
    // - blockEntity:   正在渲染的方块实体实例。使用传递给超接口的泛型类型。
    // - partialTick:   自上一刻以来经过的时间,以刻的分数表示(0.0 到 1.0)。
    // - poseStack:     要渲染到的姿态堆栈。
    // - bufferSource:  从中获取顶点缓冲区的缓冲区源。
    // - packedLight:   方块实体的光照值。
    // - packedOverlay: 方块实体的当前覆盖值,通常为 OverlayTexture.NO_OVERLAY。
    @Override
    public void render(MyBlockEntity blockEntity, float partialTick, PoseStack stack, MultiBufferSource bufferSource, int packedLight, int packedOverlay) {
        // 在此处进行渲染。
    }
}

对于给定的 BlockEntityType<?>,只能存在一个 BER。因此,特定于单个方块实体实例的值应存储在该方块实体实例中,而不是 BER 本身。

创建 BER 后,您还必须将其注册到 EntityRenderersEvent.RegisterRenderers,这是一个在 Mod 事件总线上触发的事件:

java
@SubscribeEvent
public static void registerEntityRenderers(EntityRenderersEvent.RegisterRenderers event) {
    event.registerBlockEntityRenderer(
            // 要为其注册渲染器的方块实体类型。
            MyBlockEntities.MY_BLOCK_ENTITY.get(),
            // 从 BlockEntityRendererProvider.Context 到 BlockEntityRenderer 的函数。
            MyBlockEntityRenderer::new
    );
}

如果您在 BER 中不需要 BER 提供者上下文,您也可以删除构造函数:

java
public class MyBlockEntityRenderer implements BlockEntityRenderer<MyBlockEntity> {
    @Override
    public void render( /* ... */ ) { /* ... */ }
}

// 在您的事件处理类中
@SubscribeEvent
public static void registerEntityRenderers(EntityRenderersEvent.RegisterRenderers event) {
    event.registerBlockEntityRenderer(MyBlockEntities.MY_BLOCK_ENTITY.get(),
            // 将上下文传递给空(默认)构造函数调用
            context -> new MyBlockEntityRenderer()
    );
}

无层级方块实体渲染器

BlockEntityWithoutLevelRenderer,俗称 BEWLR,是常规 BlockEntityRenderer 的适配器,用于特殊物品渲染(因此称为“无层级”,因为物品没有层级上下文)。它的总体目的相同:在静态模型不足的情况下进行特殊渲染。

要添加 BEWLR,请创建一个扩展 BlockEntityWithoutLevelRenderer 并重写 #renderByItem 的类。它还需要一些额外的构造函数设置:

java
public class MyBlockEntityWithoutLevelRenderer extends BlockEntityWithoutLevelRenderer {
    // 我们需要在构造函数中进行一些样板代码,告诉超类在哪里找到中央方块实体和实体渲染器。
    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) {
        // 在此处进行渲染。
    }
}

请记住,与 BER 一样,您的 BEWLR 只有一个实例。因此,堆栈特定的属性应存储在堆栈中,而不是 BEWLR 中。

与 BER 不同,我们不直接注册 BEWLR。相反,我们将 IClientItemExtensions 的实例注册到 RegisterClientExtensionsEventIClientItemExtensions 是一个接口,允许我们指定物品上的许多与渲染相关的行为,例如(但不限于)BEWLR。因此,我们的接口实现可能如下所示:

java
public class MyClientItemExtensions implements IClientItemExtensions {
    // 在字段中缓存我们的 BEWLR。
    private final MyBlockEntityWithoutLevelRenderer myBEWLR = new MyBlockEntityWithoutLevelRenderer();

    // 在此处返回我们的 BEWLR。
    @Override
    public BlockEntityWithoutLevelRenderer getCustomRenderer() {
        return myBEWLR;
    }
}

然后,我们可以将 IClientItemExtensions 注册到事件中:

java
@SubscribeEvent
public static void registerClientExtensions(RegisterClientExtensionsEvent event) {
    event.registerItem(
            // 我们的 IClientItemExtensions 的唯一实例,因此也是我们的 BEWLR 的唯一实例。
            new MyClientItemExtensions(),
            // 使用此 BEWLR 的物品的变长参数列表。
            MyItems.ITEM_1, MyItems.ITEM_2
    );
}

信息IClientItemExtensions 通常应被视为单例。不要在 RegisterClientExtensionsEvent 之外构造它们!

贡献者

The avatar of contributor named as 小飘 小飘

文件历史