zh_cn:tutorial:custom_model
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| zh_cn:tutorial:custom_model [2024/01/02 10:31] – [Sprites] solidblock | zh_cn:tutorial:custom_model [2024/08/27 04:34] (current) – 更新翻译 solidblock | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| ====== 使用自定义模型动态渲染方块和物品 ====== | ====== 使用自定义模型动态渲染方块和物品 ====== | ||
| - | 可以通过方块模型 JSON 文件将模型添加到游戏,但也可以通过 Java 代码来渲染。本教程中,我们将会将一个四面熔炉模型添加到游戏。 | + | 可以通过方块模型 JSON 文件将模型添加到游戏,但也可以通过 Java 代码来渲染。本教程中,我们将会把一个四面熔炉模型添加到游戏。 |
| 注意模型会在区块被重建时渲染。如果需要更加动态的渲染,可以使用 '' | 注意模型会在区块被重建时渲染。如果需要更加动态的渲染,可以使用 '' | ||
| Line 13: | Line 13: | ||
| ==== Sprites ==== | ==== Sprites ==== | ||
| - | 渲染纹理离不开'' | + | 渲染纹理离不开'' |
| - | 这里,我们会使用两个熔炉纹理。它们是方块纹理,所以要从方块atlas'' | + | |
| <code java> | <code java> | ||
| + | // 对于 1.21 之前的版本,将 `Identifier.ofVanilla` 替换为 `new Identifier`。 | ||
| private static final SpriteIdentifier[] SPRITE_IDS = new SpriteIdentifier[]{ | private static final SpriteIdentifier[] SPRITE_IDS = new SpriteIdentifier[]{ | ||
| - | new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, | + | new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, |
| - | new SpriteIdentifier(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, | + | new SpriteIdentifier(PlayerScreenHandler.BLOCK_ATLAS_TEXTURE, |
| }; | }; | ||
| - | private Sprite[] SPRITES = new Sprite[2]; | + | private Sprite[] SPRITES = new Sprite[SPRITE_IDS.length]; |
| - | // Some constants to avoid magic numbers, these need to match the SPRITE_IDS | + | // 一些常量,以避免魔法数据,需要匹配 |
| private static final int SPRITE_SIDE = 0; | private static final int SPRITE_SIDE = 0; | ||
| private static final int SPRITE_TOP = 1; | private static final int SPRITE_TOP = 1; | ||
| </ | </ | ||
| - | ==== Meshes | + | ==== Mesh ==== |
| '' | '' | ||
| <code java> | <code java> | ||
| Line 33: | Line 33: | ||
| </ | </ | ||
| - | ==== UnbakedModel方法 ==== | + | ==== UnbakedModel 方法 ==== |
| <code java> | <code java> | ||
| @Override | @Override | ||
| Line 41: | Line 41: | ||
| @Override | @Override | ||
| - | public | + | public |
| - | | + | // 与模型继承有关,我们这里还不需要使用到 |
| } | } | ||
| @Override | @Override | ||
| - | public BakedModel bake(ModelLoader loader, Function< | + | public BakedModel bake(Baker baker, Function< |
| - | // 获得sprites | + | // 获得 sprites |
| for(int i = 0; i < 2; ++i) { | for(int i = 0; i < 2; ++i) { | ||
| SPRITES[i] = textureGetter.apply(SPRITE_IDS[i]); | SPRITES[i] = textureGetter.apply(SPRITE_IDS[i]); | ||
| } | } | ||
| - | // 用Renderer API构建mesh | + | // 用 Renderer API 构建 mesh |
| Renderer renderer = RendererAccess.INSTANCE.getRenderer(); | Renderer renderer = RendererAccess.INSTANCE.getRenderer(); | ||
| MeshBuilder builder = renderer.meshBuilder(); | MeshBuilder builder = renderer.meshBuilder(); | ||
| Line 58: | Line 58: | ||
| for(Direction direction : Direction.values()) { | for(Direction direction : Direction.values()) { | ||
| - | int spriteIdx = direction == Direction.UP || direction == Direction.DOWN ? 1 : 0; | + | int spriteIdx = direction == Direction.UP || direction == Direction.DOWN ? SPRITE_TOP |
| - | // 将新的面(face)添加到mesh | + | // 将新的面(face)添加到 mesh |
| emitter.square(direction, | emitter.square(direction, | ||
| - | // 设置面的sprite,必须在.square()之后调用 | + | // 设置面的 sprite,必须在 .square() 之后调用 |
| - | // 我们还没有指定任何uv坐标,所以我们使用整个纹理,BAKE_LOCK_UV恰好就这么做。 | + | // 我们还没有指定任何 uv 坐标,所以我们使用整个纹理,BAKE_LOCK_UV 恰好就这么做。 |
| emitter.spriteBake(0, | emitter.spriteBake(0, | ||
| // 启用纹理使用 | // 启用纹理使用 | ||
| emitter.spriteColor(0, | emitter.spriteColor(0, | ||
| - | // 将quad添加到mesh | + | // 将 quad 添加到 mesh |
| emitter.emit(); | emitter.emit(); | ||
| } | } | ||
| Line 80: | Line 80: | ||
| @Override | @Override | ||
| public List< | public List< | ||
| - | return Collections.emptyList(); | + | return Collections.emptyList(); |
| } | } | ||
| Line 105: | Line 105: | ||
| @Override | @Override | ||
| public Sprite getParticleSprite() { | public Sprite getParticleSprite() { | ||
| - | return SPRITES[1]; // 方块被破坏时产生的颗粒,使用furnace_top | + | return SPRITES[1]; // 方块被破坏时产生的颗粒,使用 furnace_top |
| } | } | ||
| Line 140: | Line 140: | ||
| } | } | ||
| </ | </ | ||
| + | |||
| + | 注意:确保覆盖了 '' | ||
| ===== 注册模型 ===== | ===== 注册模型 ===== | ||
| - | 我们先写一个 '' | ||
| - | 我们用 '' | + | 要让模型在游戏内被渲染需要注册,为注册我们需要创建 |
| <code java> | <code java> | ||
| @Environment(EnvType.CLIENT) | @Environment(EnvType.CLIENT) | ||
| - | public class TutorialModelProvider | + | public class TutorialModelLoadingPlugin |
| - | public static final Identifier | + | public static final ModelIdentifier |
| @Override | @Override | ||
| - | public | + | public |
| - | if(identifier.equals(FOUR_SIDED_FURNACE_MODEL)) { | + | |
| - | return new FourSidedFurnaceModel(); | + | pluginContext.modifyModelOnLoad().register((original, |
| - | } else { | + | // 这个每次加载模型时都会调用,所以确保我们只针对我们的 |
| - | return | + | final ModelIdentifier id = context.topLevelId(); |
| - | } | + | |
| + | return new FourSidedFurnaceModel(); | ||
| + | } else { | ||
| + | // 如果不修改模型,就照样返回原来的 | ||
| + | | ||
| + | } | ||
| + | }); | ||
| } | } | ||
| } | } | ||
| Line 166: | Line 175: | ||
| @Override | @Override | ||
| public void onInitializeClient() { | public void onInitializeClient() { | ||
| - | | + | |
| | | ||
| - | /* 其他客户端指定的初始化 */ | + | /* 其他客户端特定的初始化 */ |
| } | } | ||
| } | } | ||
| Line 174: | Line 183: | ||
| 不要忘记在 '' | 不要忘记在 '' | ||
| - | < | + | < |
| - | /* ... */ | + | { |
| + | [...] | ||
| " | " | ||
| - | | + | |
| " | " | ||
| " | " | ||
| ] | ] | ||
| }, | }, | ||
| + | [...] | ||
| + | } | ||
| </ | </ | ||
| ===== 使用模型 ===== | ===== 使用模型 ===== | ||
| - | 你现在可以注册你的方块以使用新模型。比如,如果你的方块只有一个状态,把这个放在'' | + | 你可以[[blocks|注册方块]]以使用你的新模型。我们假设方块的 id 是 '' |
| - | <code json> | + | |
| + | < | ||
| + | public final class TutorialBlocks { | ||
| + | [...] | ||
| + | public static final Block FOUR_SIDED_FURNACE = register(" | ||
| + | [...] | ||
| + | } | ||
| + | </ | ||
| + | <code javascript src/ | ||
| { | { | ||
| " | " | ||
| Line 203: | Line 223: | ||
| ==== 更新模型 ==== | ==== 更新模型 ==== | ||
| 我们复用相同的模型类,但是有一点点小改变: | 我们复用相同的模型类,但是有一点点小改变: | ||
| - | * 我们会使用 '' | + | * 我们会使用 '' |
| 现在对 '' | 现在对 '' | ||
| <code java> | <code java> | ||
| - | // Minecraft 默认方块模型 | ||
| - | private static final Identifier DEFAULT_BLOCK_MODEL = new Identifier(" | ||
| - | |||
| - | private ModelTransformation transformation; | ||
| - | | ||
| - | // 将默认模型添加到依赖中 | ||
| - | public Collection< | ||
| - | return Arrays.asList(DEFAULT_BLOCK_MODEL); | ||
| - | } | ||
| - | | ||
| - | // 我们给 bake 函数添加一点逻辑 | ||
| - | @Override | ||
| - | public BakedModel bake(ModelLoader loader, Function< | ||
| - | // 加载默认方块模型 | ||
| - | JsonUnbakedModel defaultBlockModel = (JsonUnbakedModel) loader.getOrLoadModel(DEFAULT_BLOCK_MODEL); | ||
| - | // 获取 ModelTransformation | ||
| - | transformation = defaultBlockModel.getTransformations(); | ||
| - | | ||
| - | /* 先前的代码 */ | ||
| - | } | ||
| | | ||
| // 我们需要实现 getTransformation() 和 getOverrides() | // 我们需要实现 getTransformation() 和 getOverrides() | ||
| @Override | @Override | ||
| public ModelTransformation getTransformation() { | public ModelTransformation getTransformation() { | ||
| - | return | + | return |
| } | } | ||
| Line 248: | Line 248: | ||
| @Override | @Override | ||
| public void emitItemQuads(ItemStack itemStack, Supplier< | public void emitItemQuads(ItemStack itemStack, Supplier< | ||
| - | | + | |
| } | } | ||
| </ | </ | ||
| ==== 加载模型 ==== | ==== 加载模型 ==== | ||
| - | 更新我们先前创建的 '' | + | 更新我们先前创建的 '' |
| <code java> | <code java> | ||
| @Environment(EnvType.CLIENT) | @Environment(EnvType.CLIENT) | ||
| - | public class TutorialModelProvider | + | public class TutorialModelLoadingPlugin |
| - | public static final FourSidedFurnaceModel | + | public static final ModelIdentifier |
| - | public static final Identifier FOUR_SIDED_FURNACE_MODEL_BLOCK = new Identifier(" | + | public static final ModelIdentifier |
| - | public static final Identifier | + | |
| @Override | @Override | ||
| - | public | + | public |
| - | if(identifier.equals(FOUR_SIDED_FURNACE_MODEL_BLOCK) || identifier.equals(FOUR_SIDED_FURNACE_MODEL_ITEM)) { | + | |
| - | return | + | pluginContext.modifyModelOnLoad().register((original, |
| - | } else { | + | // 这个每次加载模型时都会调用,所以确保我们只针对我们的 |
| - | return | + | final ModelIdentifier id = context.topLevelId(); |
| - | } | + | |
| + | return | ||
| + | } else { | ||
| + | // 如果不修改模型,就照样返回原来的 | ||
| + | | ||
| + | } | ||
| + | }); | ||
| } | } | ||
| } | } | ||
| Line 278: | Line 283: | ||
| ===== 更加动态的渲染 ===== | ===== 更加动态的渲染 ===== | ||
| - | '' | + | '' |
| <code java> | <code java> | ||
| @Override | @Override | ||
zh_cn/tutorial/custom_model.1704191471.txt.gz · Last modified: 2024/01/02 10:31 by solidblock