PREREQUISITES
Make sure you've completed the datagen setup and created your first item.
For each item model we want to generate, we must create two separate JSON files:
- An item model, which defines the textures, rotation and overall look of the item. It goes in the
generated/assets/example-mod/models/itemdirectory. - A client item, which defines which model should be used based on various criteria, such as components, interactions and more. It goes in the
generated/assets/example-mod/itemsdirectory.
Setup
First, we will need to create our model provider.
Create a class that extends FabricModelProvider, and implement both abstract methods: generateBlockStateModels and generateItemModels. Then, create a constructor matching super.
java
public class ExampleModModelProvider extends FabricModelProvider {
public ExampleModModelProvider(FabricDataOutput output) {
super(output);
}
@Override
public void generateBlockStateModels(BlockModelGenerators blockStateModelGenerator) {
}
@Override
public void generateItemModels(ItemModelGenerators itemModelGenerator) {
}
@Override
public String getName() {
return "ExampleModModelProvider";
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Register this class in your DataGeneratorEntrypoint within the onInitializeDataGenerator method.
Built-In Item Models
For item models, we will be using the generateItemModels method. Its parameter ItemModelGenerators itemModelGenerator is responsible for generating the item models and also contains methods for doing so.
Here's a reference of the most commonly used item model generator methods.
Simple
Simple item models are the default, and they're what most Minecraft items use. Their parent model is GENERATED. They use their 2D texture in the inventory, and are rendered in 3D in-game. An example would be boats, candles or dyes.
java
itemModelGenerator.generateFlatItem(ModItems.RUBY, ModelTemplates.FLAT_ITEM);1
Handheld
Handheld item models are generally used by tools and weapons (axes, swords, trident). They are rotated and positioned a little differently from the simple models to look more natural in hand.
java
itemModelGenerator.generateFlatItem(ModItems.GUIDITE_AXE, ModelTemplates.FLAT_HANDHELD_ITEM);1
Dyeable
The method for dyeable items generates a simple item model and a client item which specifies the tint color. This method requires a default decimal color value, which is used when the item is not dyed. The default value for leather is 0xFFA06540.
java
itemModelGenerator.generateDyedItem(ModItems.LEATHER_GLOVES, 0xFFA06540);1
IMPORTANT
You have to add your item to the ItemTags.DYEABLE tag to be able to dye it in your inventory!
Conditional
Next, we'll look into generating item models that change their visual based when a specific condition, indicated by the second parameter BooleanProperty, is met. Here are some of them:
| Property | Description |
|---|---|
IsKeybindDown | True when a specified key is pressed. |
IsUsingItem | True when the item is being used (e.g. when blocking with a shield). |
Broken | True when the item has 0 durability (e.g. elytra changes texture when broken). |
HasComponent | True when the item has a certain component. |
The third and fourth parameters are the models to be used when the property is true or false, respectively.
java
itemModelGenerator.generateBooleanDispatch(
ModItems.FLASHLIGHT,
ItemModelUtils.isUsingItem(),
ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.FLASHLIGHT, "_lit", ModelTemplates.FLAT_ITEM)),
ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.FLASHLIGHT, ModelTemplates.FLAT_ITEM))
);1
2
3
4
5
6
2
3
4
5
6
IMPORTANT
To obtain the ResourceLocation that is passed in ItemModelUtils.plainModel(), always use itemModelGenerator.createFlatItemModel(), otherwise only the client items will be generated, not the item models!
Composite
Composite item models are composed of one or more textures layered on top of each other. There aren't any vanilla methods for this; you have to use the itemModelGenerator's itemModelOutput field, and call accept() on it.
java
ItemModel.Unbaked hoe = ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.ENHANCED_HOE, ModelTemplates.FLAT_ITEM));
ItemModel.Unbaked hoePlus = ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.ENHANCED_HOE, "_plus", ModelTemplates.FLAT_ITEM));
itemModelGenerator.itemModelOutput.accept(
ModItems.ENHANCED_HOE,
ItemModelUtils.composite(hoe, hoePlus)
);1
2
3
4
5
6
7
2
3
4
5
6
7
Select
Renders an item model based on the value of a specific property. These are some of them:
| Property | Description |
|---|---|
ContextDimension | Renders an item model based on the dimension in which the player is (Overworld, Nether, End). |
MainHand | Renders an item model when the item is equipped in player's main hand. |
DisplayContext | Renders an item model based on where the item is (ground, fixed, head, ...). |
ContextEntityType | Renders an item model based on the entity holding the item. |
In this example, the item changes texture when traveling between dimensions: it's green in the Overworld, red in the Nether, and black in the End.
java
ItemModel.Unbaked crystalOverworld = ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.DIMENSIONAL_CRYSTAL, "_overworld", ModelTemplates.FLAT_ITEM));
ItemModel.Unbaked crystalNether = ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.DIMENSIONAL_CRYSTAL, "_nether", ModelTemplates.FLAT_ITEM));
ItemModel.Unbaked crystalEnd = ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.DIMENSIONAL_CRYSTAL, "_end", ModelTemplates.FLAT_ITEM));
itemModelGenerator.itemModelOutput.accept(
ModItems.DIMENSIONAL_CRYSTAL,
ItemModelUtils.select(new ContextDimension(),
ItemModelUtils.when(Level.OVERWORLD, crystalOverworld),
ItemModelUtils.when(Level.NETHER, crystalNether),
ItemModelUtils.when(Level.END, crystalEnd)
)
);1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
Range Dispatch
Renders an item model based on the value of a numeric property. Takes in an item and list of variants, each paired with a value. Examples include the compass, the bow, and the brush.
There are quite a few supported properties, here are some examples:
| Property | Description |
|---|---|
Cooldown | Renders an item model based on the item's remaining cooldown. |
Count | Renders an item model based on the stack size. |
UseDuration | Renders an item model based on how long the item is being used. |
Damage | Renders an item model based on attack damage (minecraft:damage component). |
This example uses the Count, changing the texture from one knife up to three based on the stack size.
java
ItemModel.Unbaked knifeOne = ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.THROWING_KNIVES, "_one", ModelTemplates.FLAT_ITEM));
ItemModel.Unbaked knifeTwo = ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.THROWING_KNIVES, "_two", ModelTemplates.FLAT_ITEM));
ItemModel.Unbaked knifeThree = ItemModelUtils.plainModel(itemModelGenerator.createFlatItemModel(ModItems.THROWING_KNIVES, "_three", ModelTemplates.FLAT_ITEM));
itemModelGenerator.itemModelOutput.accept(
ModItems.THROWING_KNIVES,
ItemModelUtils.rangeSelect(
new Count(false),
List.of(
ItemModelUtils.override(knifeOne, 1.0F),
ItemModelUtils.override(knifeTwo, 2.0F),
ItemModelUtils.override(knifeThree, 3.0F)
)
)
);1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
Custom Item Models
Generating item models doesn't have to be done with vanilla methods only; you can, of course, create your own. In this section, we will create a custom model for a balloon item.
All fields and methods for this part of the tutorial are declared in a static inner class called CustomItemModelGenerator.
Show CustomItemModelGenerator
java
public static class CustomItemModelGenerator {
//:::custom-item-model:::
public static final ModelTemplate SCALED2X = item("scaled2x", TextureSlot.LAYER0);
//:::custom-item-model:::
//:::custom-item-datagen-method
public static void registerScaled2x(Item item, ItemModelGenerators generator) {
ResourceLocation itemModel = SCALED2X.create(item, TextureMapping.singleSlot(TextureSlot.LAYER0, ModelLocationUtils.getModelLocation(item)), generator.modelOutput);
generator.itemModelOutput.accept(item, ItemModelUtils.plainModel(itemModel));
}
//:::custom-item-datagen-method
@SuppressWarnings("SameParameterValue")
//:::custom-item-model:::
private static ModelTemplate item(String parent, TextureSlot requiredTextureKeys) {
return new ModelTemplate(Optional.of(ResourceLocation.fromNamespaceAndPath(ExampleMod.MOD_ID, "item/" + parent)), Optional.empty(), requiredTextureKeys);
}
//:::custom-item-model:::
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
Creating a Custom Parent
First, let's create a parent item model that defines how the item looks in-game. Let's say we want the balloon to look like simple item models, but scaled up.
To do this, we'll create resources/assets/example-mod/models/item/scaled2x.json, set the parent to be the item/generated model, and then override the scaling.
json
{
"parent": "item/generated",
"display": {
"ground": {
"rotation": [ 0, 0, 0 ],
"translation": [ 0, 2, 0],
"scale":[ 1, 1, 1 ]
},
"head": {
"rotation": [ 0, 180, 0 ],
"translation": [ 0, 13, 7],
"scale":[ 2, 2, 2 ]
},
"thirdperson_righthand": {
"rotation": [ 0, 0, 0 ],
"translation": [ 0, 3, 1 ],
"scale": [ 1.1, 1.1, 1.1 ]
},
"firstperson_righthand": {
"rotation": [ 0, -90, 25 ],
"translation": [ 1.13, 3.2, 1.13],
"scale": [ 1.36, 1.36, 1.36 ]
}
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
This will make the model twice as big as the simple ones.
Creating the ModelTemplate
Next, we need to create an instance of the ModelTemplate class. It will represent the actual parent item model inside our mod.
java
public static final ModelTemplate SCALED2X = item("scaled2x", TextureSlot.LAYER0);
private static ModelTemplate item(String parent, TextureSlot requiredTextureKeys) {
return new ModelTemplate(Optional.of(ResourceLocation.fromNamespaceAndPath(ExampleMod.MOD_ID, "item/" + parent)), Optional.empty(), requiredTextureKeys);
}1
2
3
4
5
6
2
3
4
5
6
The item() method creates a new ModelTemplate instance, pointing to the scaled2x.json file we created earlier.
TextureSlot LAYER0 represents the #layer0 texture variable, which will then be replaced by an identifier pointing to a texture.
Adding a Custom Datagen Method
The last step is creating a custom method, which will be called in the generateItemModels() method and will be responsible for generating our item models.
java
public static void registerScaled2x(Item item, ItemModelGenerators generator) {
ResourceLocation itemModel = SCALED2X.create(item, TextureMapping.singleSlot(TextureSlot.LAYER0, ModelLocationUtils.getModelLocation(item)), generator.modelOutput);
generator.itemModelOutput.accept(item, ItemModelUtils.plainModel(itemModel));
}1
2
3
4
5
2
3
4
5
Let's go over what the parameters are for:
Item item: The item, for which we are generating the models.ItemModelGenerators generator: the same that get passed into thegenerateItemModels()method. Used for its fields.
First, we get the ResourceLocation of the item with SCALED2X.create(), passing in a TextureMapping and the modelOutput from our generator parameter.
Then, we'll use another of its fields, the itemModelOutput (which essentially works as a consumer), and use the accept() method, so that the models are actually generated.
Calling the Custom Method
Now, we only need to call our method in the generateItemModels() method.
java
CustomItemModelGenerator.registerScaled2x(ModItems.BALLOON, itemModelGenerator);1
Don't forget to add a texture file!
Sources and Links
You can view the example tests in Fabric API, this documentation's Example Mod for more information.




