🇨🇳 中文 (Chinese - China)
🇨🇳 中文 (Chinese - China)
外观
🇨🇳 中文 (Chinese - China)
🇨🇳 中文 (Chinese - China)
外观
本页面基于这个版本编写:
1.21.4
有的时候,用 Minecraft 自带的模型格式和渲染器并不足够。 如果需要为你的方块的视觉效果添加动态渲染,则需要使用 BlockEntityRenderer。
举个例子,让我们来制作一个在 方块实体 文章中出现的 Counter Block,这个方块会在方块顶部显示点击次数。
首先,我们需要为我们的 CounterBlockEntity 创建一个 BlockEntityRenderer。
在为 CounterBlockEntity 创建 BlockEntityRenderer 时,如果您的项目对客户端和服务器端使用了不同的源代码集,则需要确保将该渲染器类放置于对应的源代码集中,例如客户端相关的类应放在 src/client/ 目录下。 直接访问 src/main/ 源代码集中与渲染相关的类并不安全,因为这些类可能已在服务器上加载。
public class CounterBlockEntityRenderer implements BlockEntityRenderer<CounterBlockEntity> {
public CounterBlockEntityRenderer(BlockEntityRendererFactory.Context context) {
}
@Override
public void render(CounterBlockEntity entity, float tickDelta, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, int overlay) {
}
}我们的新类有一个以 BlockEntityRendererFactory.Context 为参数的构造函数。 Context 有几个非常有用的渲染辅助工具,比如 ItemRenderer 或 TextRenderer。 此外,通过包含这样一个构造函数,就可以将该构造函数用作 BlockEntityRendererFactory 功能接口本身:
public class FabricDocsBlockEntityRenderer implements ClientModInitializer {
@Override
public void onInitializeClient() {
BlockEntityRendererFactories.register(ModBlockEntities.COUNTER_BLOCK_ENTITY, CounterBlockEntityRenderer::new);
}
}你应该在 ClientModInitializer 类中注册你的方块实体渲染器。
BlockEntityRendererFactories 是一个注册表,用于将带有自定义渲染代码的每个 BlockEntityType 映射到各自的 BlockEntityRenderer。
现在我们有了渲染器,我们就可以开始绘画了。 render 方法在每一帧都会被调用,这就是渲染魔法发生的地方。
首先,我们需要偏移和旋转文本,使其位于方块的顶部。
INFO
顾名思义,MatrixStack 是一个_堆栈_,这意味着您可以压入和弹出变换。 一个好的经验法则是在 render 方法开始时压入一个新的方块,并在结束时弹出,这样一个方块的渲染就不会影响到其他方块。
更多关于 MatrixStack 的信息可以在 基本渲染术语文章 中找到。
为了更容易理解所需的平移和旋转,让我们将它们可视化。 在该图中,绿色方块是绘制文本的位置,默认情况下位于方块的最左下角:

因此,首先我们需要在 X 轴和 Z 轴上将文本移动到方块的一半,然后在 Y 轴上将其移动到方块的顶部:

这些都可以以单个 translate 调用来实现:
matrices.translate(0.5, 1, 0.5);我们已经完成了 平移,接下来是 旋转 和 缩放。
默认情况下,文字会在 XY 平面上渲染,所以我们需要将其绕 X 轴旋转 90 度,让他面向上方的 XZ 平面:

MatrixStack 没有 rotate 函数,所以我们需要使用 multiply 和 RotationAxis.POSITIVE_X:
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90));那么现在的文字就在正确的位置了,但是文字现在太大了。 BlockEntityRenderer 映射整个方块到一个 [-0.5, 0.5] 的立方体,而 TextRenderer 使用 [0, 9] 的 Y 坐标。 因此,我们需要将其缩小 18 倍:
matrices.scale(1/18f, 1/18f, 1/18f);那么,我们整个的变换看起来就像这样:
matrices.push();
matrices.translate(0.5, 1, 0.5);
matrices.multiply(RotationAxis.POSITIVE_X.rotationDegrees(90));
matrices.scale(1/18f, 1/18f, 1/18f);如前所述,传入渲染器构造函数的 Context 包含一个 TextRenderer ,我们可以用它来绘制文本。 在这个例子中,我们将它保存在一个字段中。
TextRenderer 有一个方法来测量文字 (即 getWidth),这对于将其居中放置非常有用,然后绘制它(使用 draw)。
String text = entity.getClicks() + "";
float width = textRenderer.getWidth(text);
// draw the text. params:
// text, x, y, color, shadow, matrix, vertexConsumers, layerType, backgroundColor, light
textRenderer.draw(
text,
-width/2, -4f,
0xffffff,
false,
matrices.peek().getPositionMatrix(),
vertexConsumers,
TextRenderer.TextLayerType.SEE_THROUGH,
0,
light
);draw 方法接受许多的参数,但是最重要的几个是:
Text(或者 String);X 和 Y 坐标;color 值;Matrix4f(要从一个 MatrixStack 中获取,我们可以使用 .peek().getPositionMatrix() 来获取最顶端条目的 Matrix4f)。经过我们的努力,这就是最终结果:
