zh_cn:tutorial:datagen_model
Differences
This shows you the differences between two versions of the page.
| Both sides previous revisionPrevious revisionNext revision | Previous revision | ||
| zh_cn:tutorial:datagen_model [2023/02/20 05:16] – [严格验证] solidblock | zh_cn:tutorial:datagen_model [2025/04/18 14:55] (current) – solidblock | ||
|---|---|---|---|
| Line 1: | Line 1: | ||
| ======模型生成====== | ======模型生成====== | ||
| + | 我们知道,几乎每个物品都需要对应的**物品烘焙模型**(item baked model,以下简称物品模型),从 1.21.4 开始还需要**物品模型映射**(item models definition)。每个方块都需要**方块烘焙模型**(block baked model,以下简称方块模型)和**方块状态映射**(block states definition),还需要对应的物品烘焙模型或者物品模型映射。一个方块就有这么多大大小小复杂的 JSON 文件。显然,一个个去制作太费神了。因此,我们使用数据生成器为方块和物品生成模型。 | ||
| - | 你可以通过 '' | + | 在数据生成器中,模型和映射通常是一起生成的,通常来说,生成模型时返回一个模型 id,然后利用这个模型 id 会被方块状态映射或物品模型映射使用。我们将从简单到复杂逐个开始。 |
| - | 开始之前,我们创建一个类来继承(extends) | + | > :!: **注意:**我们在之前的教程中,在 '' |
| - | <code java> | + | > :!: **注意:**从 1.21.4 开始,数据生成会区分客户端和服务器,原版中与模型有关的类都会被加上 '' |
| - | private static class MyModelGenerator extends FabricModelProvider { | + | ===== 准备 ===== |
| - | private MyModelGenerator(FabricDataGenerator generator) { | + | |
| - | super(generator); | + | |
| - | } | + | |
| - | @Override | + | 首先,先创建一个类,继承 '' |
| - | public | + | <code java TutorialModelGenerator.java> |
| - | // ... | + | public |
| - | } | + | public TutorialModelGenerator(FabricDataOutput output) { |
| + | | ||
| + | } | ||
| - | @Override | ||
| - | public void generateItemModels(ItemModelGenerator itemModelGenerator) { | ||
| - | // ... | ||
| - | } | ||
| - | } | ||
| - | // ... | + | |
| - | + | public void generateBlockStateModels(BlockStateModelGenerator blockStateModelGenerator) { | |
| - | @Override | + | |
| - | public void onInitializeDataGenerator(FabricDataGenerator fabricDataGenerator) { | + | |
| // ... | // ... | ||
| - | fabricDataGenerator.addProvider(MyModelGenerator:: | + | } |
| + | |||
| + | |||
| + | @Override | ||
| + | public void generateItemModels(ItemModelGenerator itemModelGenerator) { | ||
| + | // ... | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <code java ExampleModDataGenerator.java> | ||
| + | public class ExampleModDataGenerator implements DataGeneratorEntrypoint { | ||
| + | @Override | ||
| + | public void onInitializeDataGenerator(FabricDataGenerator generator) { | ||
| // ... | // ... | ||
| + | | ||
| + | pack.addProvider(TutorialModelGenerator:: | ||
| + | } | ||
| } | } | ||
| </ | </ | ||
| - | =====添加方块模型===== | + | ===== 简单的方块模型 ===== |
| + | 我们在 [[blocks]] 的教程中创建过一个示例方块。那么在这里,我们使用短短几行代码,为它创建方块状态映射和方块模型: | ||
| + | <code java TutorialModelGenerator.java> | ||
| + | @Override | ||
| + | public void generateBlockStateModels(BlockStateModelGenerator blockStateModelGenerator) { | ||
| + | blockStateModelGenerator.registerSimpleCubeAll(TutorialBlocks.EXAMPLE_BLOCK); | ||
| + | } | ||
| + | </ | ||
| + | 这行代码会创建一个最简单的方块模型,该模型是一个完整的方块,各面都使用与其 id 一致的纹理:'' | ||
| - | '' | + | 或者也可以这样(下面的代码仍是在 |
| + | <code java> | ||
| + | final Identifier exampleBlockModelId = TexturedModel.CUBE_ALL.upload(TutorialBlocks.EXAMPLE_BLOCK, | ||
| + | blockStateModelGenerator.registerParentedItemModel(TutorialBlocks.EXAMPLE_BLOCK, | ||
| + | </code> | ||
| + | 如果需要指定不同的纹理,可以手动创建方块模型(例如六面都使用红树原木的顶部纹理): | ||
| <code java> | <code java> | ||
| - | public static Block SIMPLE_BLOCK | + | final Identifier exampleBlockModelId |
| - | public static BlockItem SIMPLE_BLOCK_ITEM = Registry.register(Registries.ITEM, ..., new BlockItem(SIMPLE_BLOCK, | + | |
| - | // ... | + | </code> |
| - | @Override | + | ===== 简单的物品模型(1.21.4 之后) ===== |
| - | public void generateBlockStateModels(BlockStateModelGenerator blockStateModelGenerator) { | + | 生成物品模型也很简单: |
| - | blockStateModelGenerator.registerSimpleCubeAll(SIMPLE_BLOCK); | + | <code java TutorialModelGenerator.java> |
| - | } | + | |
| + | public void generateItemModels(ItemModelGenerator itemModelGenerator) { | ||
| + | | ||
| + | } | ||
| </ | </ | ||
| - | 因为 '' | + | 这个物品模型将使用最基本的物品模型映射,物品模型为 '' |
| - | ====严格验证===== | + | > 如果 '' |
| - | 默认情况下,如果运行过程中,没有为所有属于被处理的模组的方块生成方块状态,数据生成将报错。Fabric API 允许禁用该功能,为此,请编辑你的 '' | + | 如果想要指定不同的纹理(例如在这个例子中,直接使用原版的白色羊毛纹理),那么也可以手动创建模型和模型映射(下面的代码仍是在 |
| - | =====添加物品模型===== | + | <code java TutorialModelGenerator.java> |
| + | itemModelGenerator.register(TutorialItems.CUSTOM_ITEM, | ||
| + | final Identifier modelId | ||
| + | itemModelGenerator.output.accept(TutorialItems.CUSTOM_ITEM, | ||
| - | '' | + | </ |
| - | 在这个例子中,我们重写上一个例子中的 '' | + | ===== 常见的原版方块模型(以楼梯和台阶为例) ===== |
| - | <code java> | + | 有时方块模型并不简单,因为涉及多种复杂的方块状态。例如,楼梯就有多种朝向,可以是东南西北,可以是正放或倒放,而且还可以是角落的。我们自己去为这些方块创建模型和方块状态映射显然会很费神。好在这些常用的方块,原版已经给我们写好了,我们只需要使用就可以。这里以楼梯和台阶为例,我们为钻石块创建相应的楼梯和台阶。首先,我们先快速地创建这些方块: |
| - | public static Block SIMPLE_BLOCK = Registry.register(Registry.BLOCK, | + | |
| - | public static BlockItem SIMPLE_BLOCK_ITEM = Registry.register(Registry.ITEM, | + | |
| - | // ... | + | |
| - | @Override | + | 对于 1.21.2 及之后的版本: |
| - | public | + | <code java TutorialBlocks.json> |
| - | itemModelGenerator.register(SIMPLE_BLOCK_ITEM, Models.GENERATED); | + | public |
| - | } | + | settings -> new StairsBlock(Blocks.DIAMOND_BLOCK.getDefaultState(), settings), |
| + | | ||
| + | public static final Block DIAMOND_SLAB = register(" | ||
| + | SlabBlock:: | ||
| + | AbstractBlock.Settings.copy(Blocks.DIORITE_SLAB)); | ||
| </ | </ | ||
| - | FIXME // | ||
| - | ====定向块的数据生成==== | + | 对于 1.21.2 之前的版本: |
| + | <code java TutorialBlocks.json> | ||
| + | public static final Block DIAMOND_STAIRS | ||
| + | new StairsBlock(Blocks.DIAMOND_BLOCK.getDefaultState(), | ||
| + | AbstractBlock.Settings.copy(Blocks.DIAMOND_BLOCK))); | ||
| + | public static final Block DIAMOND_SLAB | ||
| + | new SlabBlock(AbstractBlock.Settings.copy(Blocks.DIORITE_SLAB))); | ||
| + | </ | ||
| - | **快速警告**:这将非常复杂!!! | + | 然后,我们先分别创建常规楼梯模型、内角落楼梯模型、外角落楼梯模型、底台阶模型、顶台阶模型。双台阶模型我们直接使用原版的钻石块模型。创建这些模型时,会返回模型的 id,然后使用 '' |
| - | 在本例中,我们将为 '' | + | <code java TutorialModelGenerator.json> |
| + | final TextureMap diamondTexture = TextureMap.all(Identifier.ofVanilla(" | ||
| + | |||
| + | final Identifier stairsModelId = Models.STAIRS.upload(TutorialBlocks.DIAMOND_STAIRS, | ||
| + | final Identifier innerStairsModelId = Models.INNER_STAIRS.upload(TutorialBlocks.DIAMOND_STAIRS, | ||
| + | final Identifier outerStairsModelId = Models.OUTER_STAIRS.upload(TutorialBlocks.DIAMOND_STAIRS, | ||
| + | blockStateModelGenerator.blockStateCollector.accept( | ||
| + | BlockStateModelGenerator.createStairsBlockState(TutorialBlocks.DIAMOND_STAIRS, | ||
| + | BlockStateModelGenerator.createWeightedVariant(innerStairsModelId), | ||
| + | BlockStateModelGenerator.createWeightedVariant(stairsModelId), | ||
| + | BlockStateModelGenerator.createWeightedVariant(outerStairsModelId))); | ||
| + | blockStateModelGenerator.registerParentedItemModel(TutorialBlocks.DIAMOND_STAIRS, | ||
| - | 首先,添加方块自身并且注册它。 | + | final Identifier slabBottomModelId = Models.SLAB.upload(TutorialBlocks.DIAMOND_SLAB, |
| - | <code java> | + | final Identifier slabTopModelId |
| - | // 在 Tutorial 类里 | + | blockStateModelGenerator.blockStateCollector.accept( |
| - | public static | + | BlockStateModelGenerator.createSlabBlockState(TutorialBlocks.DIAMOND_SLAB, |
| + | BlockStateModelGenerator.createWeightedVariant(slabBottomModelId), | ||
| + | BlockStateModelGenerator.createWeightedVariant(slabTopModelId), | ||
| + | BlockStateModelGenerator.createWeightedVariant(Identifier.ofVanilla(" | ||
| + | | ||
| + | blockStateModelGenerator.registerParentedItemModel(TutorialBlocks.DIAMOND_SLAB, | ||
| + | </ | ||
| - | @Override | + | > 在 1.21.4 及之前的版本中,不需要调用 '' |
| - | public void onInitialize() | + | |
| - | { | + | 大功告成!我们就仅仅通过这么几行代码,成功地添加了楼梯和台阶所需要的一切模型、方块状态映射和物品模型映射! |
| - | | + | |
| + | ===== 带有朝向的方块(以竖直台阶为例) ===== | ||
| + | |||
| + | 带有朝向的方块通常仅使用一个方块模型,但是在方块状态映射中,会映射到不同的模型变种,例如不同的 x 旋转、y 旋转以及 uvlock。(这些词是不是在之前手动写方块状态映射的 JSON 时有些熟悉?) | ||
| + | |||
| + | 我们以 [[directionalblock]] 中创建的竖直台阶为例,通过数据生成器为其生成模型和方块状态映射。 | ||
| + | |||
| + | ==== 自定义模型 ==== | ||
| + | |||
| + | 我们之前创建过一个 '' | ||
| + | |||
| + | 为了在数据生成器中继承此模板模型,我们需要为此模板模型创建 '' | ||
| + | <code java TutorialModelGenerator.java> | ||
| + | public class TutorialModelGenerator extends FabricModelProvider { | ||
| + | public static final Model VERTICAL_SLAB = new Model( | ||
| + | Optional.of(Identifier.of(" | ||
| + | Optional.empty(), | ||
| + | TextureKey.BOTTOM, | ||
| + | |||
| + | // ... | ||
| } | } | ||
| </ | </ | ||
| - | 现在我们成功地注册好好了方块,让我们进入重点! | + | 然后再调用 '' |
| + | <code java TutorialModelGenerator.java> | ||
| + | @Override | ||
| + | public void generateBlockStateModels(BlockStateModelGenerator blockStateModelGenerator) { | ||
| + | // ... | ||
| + | |||
| + | final Identifier verticalSlabModelId = VERTICAL_SLAB.upload(TutorialBlocks.POLISHED_ANDESITE_VERTICAL_SLAB, | ||
| + | blockStateModelGenerator.registerParentedItemModel(TutorialBlocks.POLISHED_ANDESITE_VERTICAL_SLAB, | ||
| + | } | ||
| + | </ | ||
| - | <code java> | + | ==== 自定义方块状态映射(1.21.5 之后) ==== |
| - | private static class MyModelGenerator extends FabricModelProvider { | + | 重头戏来了——现在我们要为竖直台阶方块创建方块状态映射。其实没那么复杂,因为我们知道模型都是一样的,只需要有不同的旋转而已。 |
| - | private MyModelGenerator(FabricDataGenerator generator) { | + | |
| - | super(generator); | + | 在 1.21.5 中,方块状态映射是 '' |
| - | } | + | * '' |
| - | + | * '' | |
| - | @Override | + | |
| - | public void generateBlockStateModels(BlockStateModelGenerator blockStateModelGenerator) { | + | 对于 '' |
| - | // ... | + | * **方法一**:先指定一个模型变种,然后再根据方块状态修改其变种,如修改 x 旋转、y 旋转和 uvlock,各方块状态都使用同一模型 id,只是变种可能不同。 |
| - | blockStateModelGenerator.blockStateCollector.accept(MultipartBlockStateSupplier.create(Tutorial.MACHINE_BLOCK) | + | * **方法二**:直接为不同的方块状态分配模型变种,然后仍可继续根据方块状态修改变种。这种情况下,各方块状态可以使用不同的模型 id。 |
| - | .with(When.create().set(Properties.HORIZONTAL_FACING, | + | |
| - | | + | 我们的竖直台阶有两个方块状态属性:'' |
| - | } | + | <code java TutorialModelGenerator.java> |
| - | + | @Override | |
| - | @Override | + | public void generateBlockStateModels(BlockStateModelGenerator blockStateModelGenerator) { |
| - | public void generateItemModels(ItemModelGenerator itemModelGenerator) { | + | // ... |
| - | // ... | + | |
| - | } | + | |
| - | } | + | VariantsBlockModelDefinitionCreator.of(TutorialBlocks.POLISHED_ANDESITE_VERTICAL_SLAB, |
| + | | ||
| + | | ||
| + | | ||
| + | .register(Direction.NORTH, | ||
| + | | ||
| + | | ||
| + | .register(Direction.WEST, BlockStateModelGenerator.ROTATE_Y_270))); | ||
| + | } | ||
| </ | </ | ||
| + | |||
| + | 这里的 '' | ||
| + | |||
| + | > 可以使用方法二吗?当然可以,代码如下: | ||
| + | > <code java TutorialModelGenerator.java> | ||
| + | blockStateModelGenerator.blockStateCollector.accept( | ||
| + | VariantsBlockModelDefinitionCreator.of( | ||
| + | TutorialBlocks.POLISHED_ANDESITE_VERTICAL_SLAB) | ||
| + | .with(BlockStateVariantMap.models(VerticalSlabBlock.FACING) | ||
| + | .register(Direction.NORTH, | ||
| + | .register(Direction.EAST, | ||
| + | .register(Direction.SOUTH, | ||
| + | .register(Direction.WEST, | ||
| + | ) | ||
| + | .apply(BlockStateModelGenerator.UV_LOCK) | ||
| + | ); | ||
| + | </ | ||
| + | > 我们发现,在方法二中,调用 '' | ||
| + | |||
| + | 在上面的方法一和方法二中,除了通过 '' | ||
| + | |||
| + | 如果方块状态有多个可能会影响到模型变种的属性,那么可以直接在 '' | ||
zh_cn/tutorial/datagen_model.1676870168.txt.gz · Last modified: 2023/02/20 05:16 by solidblock