User Tools

Site Tools


zh_cn:tutorial:blockentityrenderers

Differences

This shows you the differences between two versions of the page.

Link to this comparison view

Both sides previous revisionPrevious revision
Next revision
Previous revision
Last revisionBoth sides next revision
zh_cn:tutorial:blockentityrenderers [2021/09/28 14:12] – [例子] solidblockzh_cn:tutorial:blockentityrenderers [2023/08/29 09:59] – [例子] wjz_p
Line 1: Line 1:
 ====== 使用方块实体渲染器动态渲染方块和物品 ====== ====== 使用方块实体渲染器动态渲染方块和物品 ======
 // //
-这是本教程的1.15和1.16版本。对于1.14版本,请参见[[zh_cn:tutorial:1.14:blockentityrenderers|使用方块实体渲染器动态渲染方块和物品(1.14)]]。//+这是本教程的 1.15 以上版本。对于 1.14 版本,请参见[[zh_cn:tutorial:1.14:blockentityrenderers|使用方块实体渲染器动态渲染方块和物品(1.14)]]。//
  
-阅读本教程之前,请确保您已[[zh_cn:tutorial:blockentity|添加方块实体]]!+阅读本教程之前,请确保您已[[blockentity|添加方块实体]]!
 ===== 介绍 ===== ===== 介绍 =====
 方块本身并不是那么有趣,只是在某个位置和某个大小保持静止直到损坏。我们可以使用方块实体渲染器(block entity renderer)更加动态地渲染与方块实体有关的物品和方块——在不同的位置、以不同的大小渲染多个物品。 方块本身并不是那么有趣,只是在某个位置和某个大小保持静止直到损坏。我们可以使用方块实体渲染器(block entity renderer)更加动态地渲染与方块实体有关的物品和方块——在不同的位置、以不同的大小渲染多个物品。
Line 11: Line 11:
 我们需要做的第一件事是创建我们的 ''BlockEntityRenderer'' 类: 我们需要做的第一件事是创建我们的 ''BlockEntityRenderer'' 类:
 <code java> <code java>
-public class DemoBlockEntityRenderer extends BlockEntityRenderer<DemoBlockEntity> {+@Environment(EnvType.CLIENT) 
 +public class DemoBlockEntityRenderer implements BlockEntityRenderer<DemoBlockEntity> {
     // 唱片机物品堆     // 唱片机物品堆
     private static ItemStack stack = new ItemStack(Items.JUKEBOX, 1);     private static ItemStack stack = new ItemStack(Items.JUKEBOX, 1);
          
-    public DemoBlockEntityRenderer(BlockEntityRenderDispatcher dispatcher) { +    public DemoBlockEntityRenderer(BlockEntityRendererFactory.Context ctx) {}
-        super(dispatcher); +
-    }+
          
     @Override     @Override
Line 25: Line 24:
 </code> </code>
  
-我们将需要注册我们的 ''BlockEntityRenderer'',但仅针对客户端。在单人游戏设置中这无关紧要,因为服务器与客户端在同一进程中运行。但是,在多人游戏设置中,服务器在与客户端不同的进程中运行,服务器代码没有 ''BlockEntityRenderer'' 的概念,因此不接受注册。要仅为客户端运行初始化代码,我们需要设置一个' 'client'' 入口点(entrypoint)。+我们将需要注册我们的 ''BlockEntityRenderer'',但仅针对客户端。在单人游戏设置中这无关紧要,因为服务器与客户端在同一进程中运行。但是,在多人游戏设置中,服务器在与客户端不同的进程中运行,服务器代码没有 ''BlockEntityRenderer'' 的概念,因此不接受注册。要仅为客户端运行初始化代码,我们需要设置一个 ''client'' 入口点(entrypoint)。 
 + 
 +在实现 ''ClientModInitializer'' 的主类旁边创建一个新类:
  
-在实现''ClientModInitializer''的主类旁边创建一个新类: 
 <code java> <code java>
 +@Environment(EnvType.CLIENT)
 public class ExampleModClient implements ClientModInitializer { public class ExampleModClient implements ClientModInitializer {
     @Override     @Override
Line 48: Line 49:
 </code> </code>
  
-在我们的ClientModInitializer中注册 ''BlockEntityRenderer''+在我们的 ClientModInitializer 中注册 ''BlockEntityRenderer''
  
 <code java> <code java>
-@Override +    @Override 
-public void onInitializeClient() { +    public void onInitializeClient() { 
-    BlockEntityRendererRegistry.INSTANCE.register(DEMO_BLOCK_ENTITY, DemoBlockEntityRenderer::new); +        BlockEntityRendererRegistry.register(DEMO_BLOCK_ENTITY, DemoBlockEntityRenderer::new); 
-}+        //不行就试试BlockEntityRendererRegistry.INSTANCE.register(DEMO_BLOCK_ENTITY, DemoBlockEntityRenderer::new); 
 +    }
 </code> </code>
 我们重写在每一帧都会被调用的 ''render'' 方法,我们将在其中进行渲染——对于初学者,请调用 ''matrices.push();'',这在进行GL调用时是必需的(我们将在紧接之后进行): 我们重写在每一帧都会被调用的 ''render'' 方法,我们将在其中进行渲染——对于初学者,请调用 ''matrices.push();'',这在进行GL调用时是必需的(我们将在紧接之后进行):
 +
 <code java> <code java>
     public void render(DemoBlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {     public void render(DemoBlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
Line 62: Line 65:
     }     }
 </code> </code>
-然后,我们对唱片机进行平移(matrices.translate)和旋转(matrices.multiply)。平移分为两部分:将其平移到高于方块中心的0.5、1.25和0.5。第二部分是变化的部分:y值的偏移量。偏移量是任何给定帧的物品高度。每次我们都要重新计算,因为我们希望它可以动画上下跳跃。我们通过以下方式计算:+然后,我们对唱片机进行平移(matrices.translate)和旋转(matrices.multiply)。平移分为两部分:将其平移到高于方块中心的 0.5、1.25 和 0.5。第二部分是变化的部分:y 值的偏移量。偏移量是任何给定帧的物品高度。每次我们都要重新计算,因为我们希望它可以动画上下跳跃。我们通过以下方式计算:
    *获取当前世界时间,该时间会随着时间而变化。    *获取当前世界时间,该时间会随着时间而变化。
    *添加部分刻。(部分刻是一个小数值,代表最后一次完整刻和现在之间的时间间隔。我们使用此方法,要不然动画会抖动,因为每秒的刻数少于每秒的帧数。)    *添加部分刻。(部分刻是一个小数值,代表最后一次完整刻和现在之间的时间间隔。我们使用此方法,要不然动画会抖动,因为每秒的刻数少于每秒的帧数。)
Line 77: Line 80:
  
         // 旋转物品         // 旋转物品
-        matrices.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion((blockEntity.getWorld().getTime() + tickDelta) * 4));+        matrices.multiply(Vec3f.POSITIVE_Y.getDegreesQuaternion((blockEntity.getWorld().getTime() + tickDelta) * 4));
     }     }
 </code> </code>
-最后,我们将获得Minecraft的 ''ItemRenderer'',并使用 ''renderItem'' 渲染唱片机物品。我们还将 ''ModelTransformation.Type.GROUND'' 传递给 ''renderItem'',因为我们希望有类似与物品置于地上的效果。尝试对此值进行试验,看看会发生什么(这是一个枚举)。在这些 GL 调用之后,我们还需要调用''matrices.pop();''+最后,我们将获得 Minecraft 的 ''ItemRenderer'',并使用 ''renderItem'' 渲染唱片机物品。我们还将 ''ModelTransformation.Type.GROUND'' 传递给 ''renderItem'',因为我们希望有类似与物品置于地上的效果。尝试对此值进行试验,看看会发生什么(这是一个枚举)。在这些 GL 调用之后,我们还需要调用''matrices.pop();''
 <code java> <code java>
     public void render(DemoBlockEntity blockEntity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {     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);+        MinecraftClient.getInstance().getItemRenderer().renderItem(stack, ModelTransformation.Mode.GROUND, light, overlay, matrices, vertexConsumers, 0);
  
         // GL 调用之后的必要调用         // GL 调用之后的必要调用
Line 93: Line 96:
 您现在就可以尝试新创建的方块实体渲染器。但是,如果您没有使方块透明,您会发现有些不对劲——这个浮动的方块,即唱片机,是黑色的!这是因为默认情况下,//无论您在方块实体中渲染什么,都将接收该方块实体所在位置的光照度//。所以浮动的方块接收这个不透明方块内部的光照,这意味着接收不到光。为了解决此问题,我们会让Minecraft接收方块实体上方位置的光照强度。 您现在就可以尝试新创建的方块实体渲染器。但是,如果您没有使方块透明,您会发现有些不对劲——这个浮动的方块,即唱片机,是黑色的!这是因为默认情况下,//无论您在方块实体中渲染什么,都将接收该方块实体所在位置的光照度//。所以浮动的方块接收这个不透明方块内部的光照,这意味着接收不到光。为了解决此问题,我们会让Minecraft接收方块实体上方位置的光照强度。
  
-要获取光照,我们在方块实体上方的位置调用''WorldRenderer#getLightmapCoordinates();'',并在''renderItem()''使用这个光照。+要获取光照,我们在方块实体上方的位置调用 ''WorldRenderer#getLightmapCoordinates();'',并在 ''renderItem()'' 使用这个光照。
 <code java> <code java>
     @Override     @Override
Line 100: Line 103:
                  
         int lightAbove = WorldRenderer.getLightmapCoordinates(blockEntity.getWorld(), blockEntity.getPos().up());         int lightAbove = WorldRenderer.getLightmapCoordinates(blockEntity.getWorld(), blockEntity.getPos().up());
-        MinecraftClient.getInstance().getItemRenderer().renderItem(stack, ModelTransformation.Mode.GROUND, lightAbove, OverlayTexture.DEFAULT_UV, matrices, vertexConsumers);+        MinecraftClient.getInstance().getItemRenderer().renderItem(stack, ModelTransformation.Mode.GROUND, lightAbove, OverlayTexture.DEFAULT_UV, matrices, vertexConsumers, 0);
                  
         [...]         [...]
Line 107: Line 110:
  
 唱片机现在应该得到了适当的光照。 唱片机现在应该得到了适当的光照。
 +
 +===== 根据方块实体数据进行渲染 =====
 +有时候你需要根据方块实体的数据(nbt)进行渲染,结果发现这些数据全是空的,尽管通过 ''/data get block'' 命令可以正常访问数据。这是因为你没有将服务器的数据同步至客户端。参见[[zh_cn:tutorial:blockentity#将服务器数据同步至客户端]]。
zh_cn/tutorial/blockentityrenderers.txt · Last modified: 2023/08/29 10:31 by wjz_p