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
zh_cn:tutorial:blockentityrenderers [2019/12/19 10:10] lightcolourzh_cn:tutorial:blockentityrenderers [2023/08/29 10:31] (current) – [例子] wjz_p
Line 1: Line 1:
-====== 渲染动态使用块实体渲染器块和物品 ======+====== 使用块实体渲染器动态渲染方块和物品 ====== 
 +// 
 +这是本教程的 1.15 以上版本。对于 1.14 版本,请参见[[zh_cn:tutorial:1.14:blockentityrenderers|使用方块实体渲染器动态渲染方块和物品(1.14)]]。//
  
-//这是本教程的1.15版本。 对于1.14版本,请参见[[tutorial:1.14:blockentityrenderers |使用块实体渲染器动态渲染块和项目(1.14)]]。 +阅读本教程之前,请确保您已[[blockentity|添加块实体]]!
- +
-阅读本教程之前,请确保您已[[tutorial:blockentity |添加块实体]]! +
 ===== 介绍 ===== ===== 介绍 =====
-块本身并不是那么有趣, +方块本身并不是那么有趣,只是在某个位置和某个大小保持静止直到损坏。我们可以使用块实体渲染器(block entity renderer)更加动态地渲染与块实体关的物品——在不同的位置、以不同的大小渲染个物品
-它们只是在某个位置和某个大小保持静止直到损坏。 +
-我们可以使用块实体渲染器更加动态地渲染与块实体项目和块-渲染多个不同的项目, +
-不同的位置和大小,甚至更多。 +
 ===== 例子 ===== ===== 例子 =====
-在本教程中,我们将通过向其添加''BlockEntityRenderer''来构建所创建的方块实体。 +在本教程中,我们将通过向其添加 ''BlockEntityRenderer'' 来构建所创建的方块实体。渲染器将显示一个唱机,漂浮在块上方,上下移动并旋转。
-渲染器将显示一个自动点唱机,该自动点唱机漂浮在块上方,上下旋转。+
      
-我们需要做的第一件事是创建我们的“ BlockEntityRenderer类:+我们需要做的第一件事是创建我们的 ''BlockEntityRenderer'' 类:
 <code java> <code java>
-public class MyBlockEntityRenderer extends BlockEntityRenderer<DemoBlockEntity>+@Environment(EnvType.CLIENT) 
-    // A jukebox itemstack+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 MyBlockEntityRenderer(BlockEntityRenderDispatcher dispatcher) { +    public DemoBlockEntityRenderer(BlockEntityRendererFactory.Context ctx) {}
-        super(dispatcher); +
-    }+
          
     @Override     @Override
Line 28: Line 23:
 } }
 </code> </code>
-我们将需要注册我们的''BlockEntityRenderer'',但仅针对客户端。 
-在单人游戏设置中这无关紧要,因为服务器与客户端在同一进程中运行。 
-但是,在多人游戏设置中,服务器在与客户端不同的进程中运行,服务器代码 
-没有''BlockEntityRenderer''的概念,因此不接受注册。 
-要仅为客户端运行初始化代码,我们需要设置一个''客户端''入口点。 
  
-在实现''ClientModInitializer''的主类旁边创建一个新类:+我们将需要注册我们的 ''BlockEntityRenderer'',但仅针对客户端。在单人游戏设置中这无关紧要,因为服务器与客户端在同一进程中运行。但是,在多人游戏设置中,服务器在与客户端不同的进程中运行,服务器代码没有 ''BlockEntityRenderer'' 的概念,因此不接受注册。要仅为客户端运行初始化代码,我们需要设置一个 ''client'' 入口点(entrypoint)。 
 + 
 +在实现 ''ClientModInitializer'' 的主类旁边创建一个新类: 
 <code java> <code java>
 +@Environment(EnvType.CLIENT)
 public class ExampleModClient implements ClientModInitializer { public class ExampleModClient implements ClientModInitializer {
     @Override     @Override
     public void onInitializeClient() {     public void onInitializeClient() {
-        // Here we will put client-only registration code+        // 这里我们放置只在客户端注册的代码
     }     }
 } }
 </code> </code>
-将此类设置为''fabric.mod.json''中的“客户端”入口点(根据需要修改路径):+将此类设置为 ''fabric.mod.json'' 中的“client”入口点(根据需要修改路径):
 <code javascript "fabric.mod.json"> <code javascript "fabric.mod.json">
 "entrypoints": { "entrypoints": {
Line 49: Line 43:
     "client": [     "client": [
       {       {
-        "value": "tutorial.path.to.ExampleModClient"+        "value": "net.fabricmc.example.ExampleModClient"
       }       }
     ]     ]
Line 55: 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, MyBlockEntityRenderer::new); +        BlockEntityRendererRegistry.register(DEMO_BLOCK_ENTITY, DemoBlockEntityRenderer::new); 
-}+        //不行就试试BlockEntityRendererRegistry.INSTANCE.register(DEMO_BLOCK_ENTITY, DemoBlockEntityRenderer::new); 
 +    }
 </code> </code>
-我们重写''render''方法,该方法被称为每一帧(!),并在其中进行渲染 +我们重写在每一帧都会被调用的 ''render'' 方法,我们将在其中进行渲染——对于初学者,请调用 ''matrices.push();'',这在进行GL调用时是必需的(我们将在紧接之后进行): 
-  -对于初学者,请调用''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 69: Line 65:
     }     }
 </code> </code>
-然后,我们执行自动点唱机(matrices.translate)和旋转(matrices.multiply)。 +然后,我们进行平移(matrices.translate)和旋转(matrices.multiply)。平移分为两部分:将其平移到高于块中心的 0.5、1.25 和 0.5。第二部分是变化的部分:y 值的偏移量。偏移量是任何给定物品高度。每次我们都要重新计算,因为我们希望它可以动画上下跳跃。我们通过以下方式计算:
-转换分为两部分:将其转换为高于块中心的0.5、1.25和0.5。 +
-第二部分是更改的部分:y值的偏移量。 偏移量是任何给定框架项目高度。 +
-每次我们都要重新计算,因为我们希望它可以动画上下跳跃。 我们通过以下方式计算:+
    *获取当前世界时间,该时间会随着时间而变化。    *获取当前世界时间,该时间会随着时间而变化。
-   *添加部分刻。 (部分刻度线是一个小数值,代表最后一次完整刻度线和现在之间的时间间隔。我们使用此方法是因为否则动画会抖动,因为每秒的刻数少于每秒的帧数。) +   *添加部分刻。(部分刻是一个小数值,代表最后一次完整刻和现在之间的时间间隔。我们使用此方法,要不然动画会抖动,因为每秒的刻数少于每秒的帧数。) 
-   *用8除以减慢运动速度。 +   *将其以8以减慢运动速度。 
-   *以正弦值产生介于-1和1之间的值,例如a[[https://www.electronicshub.org/wp-content/uploads/2015/07/11.jpg|正弦波]]. +   *以正弦值产生介于-1和1之间的值,类似于[[https://www.electronicshub.org/wp-content/uploads/2015/07/11.jpg|正弦波]] 
-   * 将其除以4可垂直压缩正弦波,因此项目不会上下移动太多+   * 将其除以4可垂直压缩正弦波,这样物品不会过度上下移动。
 <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) {
         [...]         [...]
-        // Calculate the current offset in the value+        // 计算当前y值的偏移
         double offset = Math.sin((blockEntity.getWorld().getTime() + tickDelta) / 8.0) / 4.0;         double offset = Math.sin((blockEntity.getWorld().getTime() + tickDelta) / 8.0) / 4.0;
-        // Move the item+        // 移动物品
         matrices.translate(0.5, 1.25 + offset, 0.5);         matrices.translate(0.5, 1.25 + offset, 0.5);
  
-        // Rotate the item +        // 旋转物品 
-        matrices.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion((blockEntity.getWorld().getTime() + tickDelta) * 4));+        matrices.multiply(RotationAxis.POSITIVE_Y.rotationDegrees((blockEntity.getWorld().getTime() + tickDelta) * 4));
     }     }
 </code> </code>
-Finally, we will get the Minecraft 'ItemRenderer' and render the jukebox item by using ''renderItem''.  +最后,我们将获得 Minecraft 的 ''ItemRenderer'',并使用 ''renderItem'' 渲染唱片机物品。我们还将 ''ModelTransformation.Type.GROUND'' 传递给 ''renderItem'',因为我们希望有类似与物品置于地上的效果。尝试对此值进行试验,看看会发生什么(这是一个枚举)。在这些 GL 调用之后,我们还需要调用''matrices.pop();''
-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:+
 <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);
  
-        // Mandatory call after GL calls+        // GL 调用之后的必要调用
         matrices.pop();         matrices.pop();
     }     }
 </code> </code>
  
-You can try your newly created block entity renderer right now.  +您现在就可以尝试新创建的方块实体渲染器。但是,如果您没有使方块透明,您会发现有些不对劲——这个浮动的方块,即唱片机,是黑色的!这是因为默认情况下,//无论您在方块实体中渲染什么,都将接收该方块实体所在位置的光照度//。所以浮动的方块接收这个不透明方块内部的光照,这意味着接收不到光。为了解决此问题,我们会让Minecraft接收方块实体上方位置的光照强度。
-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,  +要获取光照,我们在方块实体上方的位置调用 ''WorldRenderer#getLightmapCoordinates();'',并在 ''renderItem()'' 使用这个光照。
-and to use the light we use it in ''renderItem()'':+
 <code java> <code java>
     @Override     @Override
Line 118: 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.Type.GROUND, lightAbove, OverlayTexture.DEFAULT_UV, matrices, vertexConsumers);+        MinecraftClient.getInstance().getItemRenderer().renderItem(stack, ModelTransformation.Mode.GROUND, lightAbove, OverlayTexture.DEFAULT_UV, matrices, vertexConsumers, 0);
                  
         [...]         [...]
Line 124: Line 109:
 </code> </code>
  
-The jukebox should now have the proper lighting. +唱片机现在应该得到了适当的光照。 
 + 
 +===== 根据方块实体数据进行渲染 ===== 
 +有时候你需要根据方块实体的数据(nbt)进行渲染,结果发现这些数据全是空的,尽管通过 ''/data get block'' 命令可以正常访问数据。这是因为你没有将服务器的数据同步至客户端。参见[[zh_cn:tutorial:blockentity#将服务器数据同步至客户端]]。
zh_cn/tutorial/blockentityrenderers.1576750215.txt.gz · Last modified: 2019/12/19 10:10 by lightcolour