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();
    }

We then perform the movement of the jukebox (matrices.translate) and rotation (matrices.multiply). There are two parts to the translation: we translate it to 0.5, 1.25, and 0.5 which is above the center of our block. The second part is the part that changes: the offset in the y value. The offset is the height of the item for any given frame. We recalculate this each time because we want it to be animating bouncing up and down. We calculate this by:

  • Getting the current world time, which changes over time.
  • Adding the partial ticks. (The partial ticks is a fractional value representing the amount of time that’s passed between the last full tick and now. We use this because otherwise the animation would be jittery because there are fewer ticks per second than frames per second.)
  • Dividing that by 8 to slow the movement down.
  • Taking the sine of that to produce a value that ranges between -1 and 1, like a sine wave.
  • Dividing that by 4 to compress the sine wave vertically so the item doesn’t move up and down as much.
    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.1576750093.txt.gz · Last modified: 2019/12/19 10:08 by lightcolour