User Tools

Site Tools


zh_cn:tutorial:blockentityrenderers

This is an old revision of the document!


渲染动态使用块实体渲染器块和物品

这是本教程的1.15版本。 对于1.14版本,请参见使用块实体渲染器动态渲染块和项目(1.14)。 阅读本教程之前,请确保您已添加块实体! ===== 介绍 ===== 方块块本身并不是那么有趣, 它们只是在某个位置和某个大小保持静止直到损坏。 我们可以使用块实体渲染器来更加动态地渲染与块实体相关联的项目和块-渲染多个不同的项目, 在不同的位置和大小,甚至更多。 ===== 例子 ===== 在本教程中,我们将通过向其添加BlockEntityRenderer来构建所创建的方块实体。 渲染器将显示一个自动点唱机,该自动点唱机漂浮在块上方,上下,旋转。 我们需要做的第一件事是创建我们的“ BlockEntityRenderer”类: <code java> public class MyBlockEntityRenderer extends BlockEntityRenderer<DemoBlockEntity> { A jukebox itemstack

  private static ItemStack stack = new ItemStack(Items.JUKEBOX, 1);
  
  public MyBlockEntityRenderer(BlockEntityRenderDispatcher dispatcher) {
      super(dispatcher);
  }
  
  @Override
  public void render(DemoBlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
  }

} </code> 我们将需要注册我们的BlockEntityRenderer,但仅针对客户端。 在单人游戏设置中这无关紧要,因为服务器与客户端在同一进程中运行。 但是,在多人游戏设置中,服务器在与客户端不同的进程中运行,服务器代码 没有BlockEntityRenderer的概念,因此不接受注册。 要仅为客户端运行初始化代码,我们需要设置一个客户端入口点。

在实现ClientModInitializer的主类旁边创建一个新类:

public class ExampleModClient implements ClientModInitializer {
    @Override
    public void onInitializeClient() {
        // Here we will put client-only registration code
    }
}

将此类设置为fabric.mod.json中的“客户端”入口点(根据需要修改路径):

"fabric.mod.json"
"entrypoints": {
    [...]
    "client": [
      {
        "value": "tutorial.path.to.ExampleModClient"
      }
    ]
}    

并在我们的ClientModInitializer中注册BlockEntityRenderer

@Override
public void onInitializeClient() {
    BlockEntityRendererRegistry.INSTANCE.register(DEMO_BLOCK_ENTITY, MyBlockEntityRenderer::new);
}

我们重写了render方法,该方法被称为每一帧(!),并在其中进行渲染

  1. 对于初学者,请调用matrices.push();,这在进行GL调用时是必需的(我们将在紧接之后进行):
    public void render(DemoBlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
       matrices.push();
    }

然后,我们执行自动点唱机的移动(matrices.translate)和旋转(matrices.multiply)。 转换分为两部分:将其转换为高于块中心的0.5、1.25和0.5。 第二部分是更改的部分:y值的偏移量。 偏移量是任何给定框架的项目高度。 每次我们都要重新计算,因为我们希望它可以动画上下跳跃。 我们通过以下方式计算:

  • 获取当前世界时间,该时间会随着时间而变化。
  • 添加部分刻度。 (部分刻度线是一个小数值,代表最后一次完整刻度线和现在之间的时间间隔。我们使用此方法是因为否则动画会抖动,因为每秒的刻度数少于每秒的帧数。)
  • 用8除以减慢运动速度。
  • 以正弦值产生介于-1和1之间的值,例如a正弦波.
  • 将其除以4可垂直压缩正弦波,因此该项目不会上下移动太多。
    public void render(DemoBlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
        [...]
        // Calculate the current offset in the y value
        double offset = Math.sin((blockEntity.getWorld().getTime() + tickDelta) / 8.0) / 4.0;
        // Move the item
        matrices.translate(0.5, 1.25 + offset, 0.5);
 
        // Rotate the item
        matrices.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion((blockEntity.getWorld().getTime() + tickDelta) * 4));
    }

Finally, we will get the Minecraft 'ItemRenderer' and render the jukebox item by using renderItem. We also pass ModelTransformation.Type.GROUND to renderItem because we want a similiar effect to an item lying on the ground. Try experimenting with this value and see what happens (it's an enum). We also need to call matrices.pop(); after these GL calls:

    public void render(DemoBlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
        [...]
        MinecraftClient.getInstance().getItemRenderer().renderItem(stack, ModelTransformation.Type.GROUND, light, overlay, matrices, vertexConsumers);
 
        // Mandatory call after GL calls
        matrices.pop();
    }

You can try your newly created block entity renderer right now. However, if you didn't make your block transparent, you will notice something is amiss - the floating block, the jukebox, is pitch black! This is because by default, whatever you render in the block entity, will receive light as if it's in the same position as the block entity. So the floating block receives light from inside our opaque block, which means it receives no light! To fix this, we will tell Minecraft to receive light from one block above the location of the block entity.

To get the light, we call WorldRenderer#getLightmapCoordinates() on the position above our block entity, and to use the light we use it in renderItem():

    @Override
    public void render(DemoBlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
        [...]
 
        int lightAbove = WorldRenderer.getLightmapCoordinates(blockEntity.getWorld(), blockEntity.getPos().up());
        MinecraftClient.getInstance().getItemRenderer().renderItem(stack, ModelTransformation.Type.GROUND, lightAbove, OverlayTexture.DEFAULT_UV, matrices, vertexConsumers);
 
        [...]
    }

The jukebox should now have the proper lighting.

zh_cn/tutorial/blockentityrenderers.1576750215.txt.gz · Last modified: 2019/12/19 10:10 by lightcolour