本篇教程参考为的NeoForge1.20.4Mod开发的视频,这篇教程是我边学边总结的,与其说是教程更像我的学习笔记,如有不清楚的地方,大家可以在评论区提问。在我力所能及的范围内,我都会解答的
方块实体渲染(Block Entity Rendering / BER)*就是:当一个方块的外观*不能只靠静态的烘焙模型(JSON/OBJ 等)表示时,游戏会给这个方块配一个 BlockEntity,并在客户端用 BlockEntityRenderer 每帧(或按需)执行自定义绘制逻辑——比如箱子盖子开合、熔炉燃烧动画、带动态内容的展示框、会旋转/浮动的物体、根据方块实体数据改变显示内容等。Forge 文档明确指出:BER 用于渲染“无法用静态 baked model 表达”的方块,并且它要求方块拥有 BlockEntity。
我们在之前的RubyFrame基础上修改
RubyFrame类
public class RubyFrame extends BaseEntityBlock implements SimpleWaterloggedBlock {
public RubyFrame() {
super(Properties.ofFullCopy(Blocks.STONE).strength(5).noOcclusion());
this.registerDefaultState(this.stateDefinition.any().setValue(BlockStateProperties.WATERLOGGED, false));
}
public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED;
public static final VoxelShape SHAPE1 = Block.box(0,0,0,16,2,16);
public static final VoxelShape SHAPE2 = Block.box(0,14,0,16,16,16);
public static final VoxelShape SHAPE3 = Block.box(0,2,0,2,14,2);
public static final VoxelShape SHAPE4 = Block.box(0,2,16,2,14,16);
public static final VoxelShape SHAPE5 = Block.box(14,2,0,16,14,2);
public static final VoxelShape SHAPE6 = Block.box(14,2,14,16,14,16);
public static final VoxelShape ALL_SHAPE = Shapes.or(SHAPE1, SHAPE2, SHAPE3, SHAPE4, SHAPE5, SHAPE6);
@Override
public VoxelShape getShape( BlockState state, BlockGetter reader, BlockPos pos, CollisionContext collisionContext) {
return ALL_SHAPE;
}
@Override
protected void createBlockStateDefinition(StateDefinition.Builder<Block, BlockState> builder) {
builder.add(WATERLOGGED);
}
@Override
public BlockState getStateForPlacement(BlockPlaceContext ctx) {
BlockPos blockpos = ctx.getClickedPos();
FluidState fluidstate = ctx.getLevel().getFluidState(blockpos);
return this.defaultBlockState().setValue(WATERLOGGED, fluidstate.getType() == Fluids.WATER);
}
@Override
public BlockState updateShape(BlockState state,
Direction facing,
BlockState facingState,
LevelAccessor level,
BlockPos currentPos,
BlockPos facingPos) {
if (state.getValue(WATERLOGGED)) {
level.scheduleTick(currentPos, Fluids.WATER, Fluids.WATER.getTickDelay(level));
}
return super.updateShape(state, facing, facingState, level, currentPos, facingPos);
}
@Override
public FluidState getFluidState(BlockState state) {
return state.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(state);
}
protected boolean isPathfindable(BlockState state,PathComputationType type) {
return switch (type) {
case LAND -> false;
case WATER -> state.getFluidState().is(FluidTags.WATER);
case AIR -> false;
default -> false;
};
}
//新增方法
@Override
protected MapCodec<? extends BaseEntityBlock> codec() {
return null;
}
@Override
public @Nullable BlockEntity newBlockEntity(BlockPos pos, BlockState state) {
return new RubyFrameBlockEntity(pos, state);
}
@Override
public RenderShape getRenderShape(BlockState state) {
return RenderShape.MODEL;
}
}
RubyFrameBlockEntity类
public class RubyFrameBlockEntity extends BlockEntity {
public RubyFrameBlockEntity(BlockPos pos, BlockState blockState) {
super(ModBlockEntities.RUBY_FRAME_BLOCK_ENTITY.get(), pos, blockState);
}
}
创建RubyFrameBlockEntityRender类
这里渲染部分
public class RubyFrameBlockEntityRender implements BlockEntityRenderer<RubyFrameBlockEntity> {
public RubyFrameBlockEntityRender(BlockEntityRendererProvider.Context context) {}
@Override
public void render(RubyFrameBlockEntity blockEntity, float partialTick, PoseStack poseStack, MultiBufferSource buffer, int packedLight, int packedOverlay) {//每帧渲染被调用的入口
poseStack.pushPose();//保存当前的矩阵状态
poseStack.translate(1.0D, 0.0D, 0.0D);//把渲染位置平移到方块坐标系的右侧 1 格
BlockRenderDispatcher blockRenderDispatcher = Minecraft.getInstance().getBlockRenderer();
BlockState blockState = Blocks.CHEST.defaultBlockState();//获取箱子的默认状态
blockRenderDispatcher.renderSingleBlock(blockState, poseStack, buffer, packedLight,packedOverlay);
poseStack.popPose();//恢复push之前的矩阵状态
poseStack.pushPose();
poseStack.translate(0.0D, 1.0D, 0.0D);//把渲染位置平移到上面 1 格
ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer();
ItemStack itemStack = new ItemStack(Items.DIAMOND);
BakedModel bakedModel = itemRenderer.getModel(itemStack,blockEntity.getLevel(),null,0);//获取物品模型,数字为随机种子,用于模型随机变体;0表示固定
itemRenderer.render(itemStack, ItemDisplayContext.FIXED,true,poseStack,buffer,packedLight,packedOverlay,bakedModel);
poseStack.popPose();
}
}
参数说明
render 方法参数
•RubyFrameBlockEntity blockEntity:当前正在渲染的方块实体实例,可用来拿位置、状态、世界等数据
•float partialTick:渲染插值用的部分刻(tick)进度,0~1,用于平滑动画
•PoseStack poseStack:矩阵栈,用来做平移/旋转/缩放,影响当前渲染坐标系
•MultiBufferSource buffer:渲染缓冲区,所有顶点会写到这里
•int packedLight:打包光照值(含方块光和天空光),影响亮度
•int packedOverlay:打包叠加值,用于破坏动画或发光效果等叠加层
renderSingleBlock 参数
blockRenderDispatcher.renderSingleBlock(blockState, poseStack, buffer, packedLight, packedOverlay);
•BlockState blockState:要渲染的方块状态,这里是 Blocks.CHEST.defaultBlockState()
•PoseStack poseStack:当前矩阵栈(已平移过)
•MultiBufferSource buffer:当前缓冲区
•int packedLight:光照值
•int packedOverlay:叠加值
getModel 参数
BakedModel bakedModel = itemRenderer.getModel(itemStack, blockEntity.getLevel(), null, 0);
•ItemStack itemStack:要渲染的物品堆栈,这里是 Items.DIAMOND
•Level level:当前世界,用于让模型根据世界环境变化(比如渲染变种)。传 blockEntity.getLevel()
•LivingEntity entity:用于根据实体状态决定模型变化,这里传 null(无实体上下文)
•int seed:随机种子,用于模型随机变体;0 表示固定
itemRenderer.render 参数
itemRenderer.render(itemStack, ItemDisplayContext.FIXED, true, poseStack, buffer, packedLight, packedOverlay, bakedModel); •ItemStack itemStack:要渲染的物品堆栈
•ItemDisplayContext.FIXED:渲染上下文,决定缩放和朝向,FIXED 类似展示框
•boolean leftHanded:是否以左手方式渲染。这里传 true,会影响朝向
•PoseStack poseStack:矩阵栈 •MultiBufferSource buffer:缓冲区
•int packedLight:光照值 •int packedOverlay:叠加值
•BakedModel bakedModel:最终要渲染的物品模型
ItemDisplayContext的其他取值
•THIRD_PERSON_RIGHT_HAND:第三人称右手持物
•THIRD_PERSON_LEFT_HAND:第三人称左手持物
•FIRST_PERSON_RIGHT_HAND:第一人称右手持物
•FIRST_PERSON_LEFT_HAND:第一人称左手持物
•HEAD:头盔槽位(头部)
•GUI:物品栏/快捷栏等 GUI 展示
•GROUND:掉落在地面的物品
•FIXED:物品展示框等固定展示
•NONE:代码侧的兜底上下文,通常不用于JSON display里
补充:在更高版本(例如 1.21.11+ 的映射)中,枚举里出现了ON_SHELF。是否能用取决于你当前 NeoForge/Minecraft 版本
类介绍
BlockRenderDispatcher类
字段
BlockModelShaper blockModelShaper:用来根据 BlockState 找到对应的 BakedModel
ModelBlockRenderer modelRenderer:实际把方块模型“tesselate/渲染”成顶点的核心渲染器
BlockEntityWithoutLevelRenderer blockEntityRenderer:用于渲染 ENTITYBLOCK_ANIMATED 这种依赖 BEWLR 的方块(例如箱子、床等自定义渲染)
LiquidBlockRenderer liquidBlockRenderer:专门渲染液体方块(流体)
RandomSource random:内部用来产生稳定随机,用于模型随机变体
BlockColors blockColors:方块染色器,用于草、树叶等根据环境决定颜色的方块
构造器
BlockRenderDispatcher(BlockModelShaper blockModelShaper, BlockEntityWithoutLevelRenderer blockEntityRenderer, BlockColors blockColors):注入模型查找器、BEWLR 和颜色系统;并初始化 modelRenderer 和 liquidBlockRenderer
方法 1.模型和渲染器获取
getBlockModelShaper():返回 BlockModelShaper
getModelRenderer():返回 ModelBlockRenderer
getBlockModel(BlockState state):用 blockModelShaper 获取 BakedModel
getLiquidBlockRenderer():返回 LiquidBlockRenderer
2.破坏贴图渲染
renderBreakingTexture(...)(两个重载):渲染方块破坏动画的贴图层 核心流程: BlockState → BakedModel → modelData → tesselateBlock(…) 只对 RenderShape.MODEL 生效
3.批量世界渲染
renderBatched(...)(两个重载):在世界里批量渲染方块(chunk 渲染路径)
4.液体渲染
renderLiquid(...):优先让流体自身扩展渲染(IClientFluidTypeExtensions),否则 fallback 到 LiquidBlockRenderer。同样有异常捕获与 CrashReport
5.单个方块渲染
renderSingleBlock(...)(两个重载):用于在 GUI、物品、方块实体渲染等场景里“独立渲染”一个方块
6.资源重载回调
onResourceManagerReload(ResourceManager resourceManager):资源重载时调用,主要让LiquidBlockRenderer重新抓取贴图
ItemRenderer类
字段
Minecraft minecraft:客户端实例,提供全局资源、设置等
ItemModelShaper itemModelShaper:物品模型映射表:Item → ModelResourceLocation → BakedModel
TextureManager textureManager:纹理管理器,用于绑定贴图
ItemColors itemColors:物品染色器,给可染色物品(如药水、草莓酱类)提供颜色
BlockEntityWithoutLevelRenderer blockEntityRenderer:用于特殊物品的自定义渲染(如箱子、床等)
构造器
ItemRenderer(Minecraft minecraft, TextureManager textureManager, ModelManager modelManager, ItemColors itemColors, BlockEntityWithoutLevelRenderer blockEntityRenderer)
初始化字段,创建 itemModelShaper,并为所有 Item 注册默认的 inventory 模型
方法
1.模型映射
getItemModelShaper():返回 itemModelShaper
2.渲染入口
render(ItemStack itemStack, ItemDisplayContext displayContext, boolean leftHand, PoseStack poseStack, MultiBufferSource buffer, int combinedLight, int combinedOverlay, BakedModel p_model):核心渲染流程
核心流程:
根据显示上下文选择三叉戟/望远镜特殊模型
应用相机变换(handleCameraTransforms)
如果不是自定义渲染器,则走模型渲染流程
若需要“附魔发光(glint)”则选择不同的 VertexConsumer
3.渲染模型列表
renderModelLists(BakedModel model, ItemStack stack, int combinedLight, int combinedOverlay, PoseStack poseStack, VertexConsumer buffer):遍历 6 个面 + 无方向面,把所有 BakedQuad交给renderQuadList
4.渲染 Quad
renderQuadList(PoseStack poseStack, VertexConsumer buffer, List<BakedQuad> quads, ItemStack itemStack, int combinedLight, int combinedOverlay):把quads写入缓冲区,并应用物品染色
5.模型获取
getModel(ItemStack stack, @Nullable Level level, @Nullable LivingEntity entity, int seed):根据 ItemStack + 世界/实体 + 随机种子,拿到最终BakedModel
处理三叉戟/望远镜特殊模型并应用overrides
6.静态渲染封装
renderStatic(...)(两个重载):提供更简化的入口,内部还是走 getModel → render
7.资源重载
onResourceManagerReload(ResourceManager resourceManager):资源重载时刷新itemModelShaper缓存
8.获取自定义渲染器
getBlockEntityRenderer():返回blockEntityRenderer
与发光/附魔相关的工具方法
getArmorFoilBuffer
getCompassFoilBuffer / getCompassFoilBufferDirect
getFoilBuffer / getFoilBufferDirect







暂无评论内容