Models
Models are JSON files that determine the visual shape and texture(s) of a block or item. A model consists of cuboid elements, each with their own size, that then get assigned a texture to each face.
Each item gets an item model assigned to it by its registry name. For example, an item with the registry name examplemod:example_item
would get the model at assets/examplemod/models/item/example_item.json
assigned to it. For blocks, this is a bit more complicated, as they get assigned a blockstate file first. See below for more information.
Specification
See also: Model on the Minecraft Wiki
A model is a JSON file with the following optional properties in the root tag:
loader
: NeoForge-added. Sets a custom model loader. See Custom Model Loaders for more information.parent
: Sets a parent model, in the form of a resource location relative to themodels
folder. All parent properties will be applied and then overridden by the properties set in the declaring model. Common parents include:minecraft:block/block
: The common parent of all block models.minecraft:block/cube
: Parent of all models that use a 1x1x1 cube model.minecraft:block/cube_all
: Variant of the cube model that uses the same texture on all six sides, for example cobblestone or planks.minecraft:block/cube_bottom_top
: Variant of the cube model that uses the same texture on all four horizontal sides, and separate textures on the top and the bottom. Common examples include sandstone or chiseled quartz.minecraft:block/cube_column
: Variant of the cube model that has a side texture and a bottom and top texture. Examples include wooden logs, as well as quartz and purpur pillars.minecraft:block/cross
: Model that uses two planes with the same texture, one rotated 45° clockwise and the other rotated 45° counter-clockwise, forming an X when viewed from above (hence the name). Examples include most plants, e.g. grass, saplings and flowers.minecraft:item/generated
: Parent for classic 2D flat item models. Used by most items in the game. Ignores anelements
block since its quads are generated from the textures.minecraft:item/handheld
: Parent for 2D flat item models that appear to be actually held by the player. Used predominantly by tools. Submodel ofitem/generated
, which causes it to ignore theelements
block as well.minecraft:builtin/entity
: Specifies no textures other thanparticle
. If this is the parent,BakedModel#isCustomRenderer()
returnstrue
to allow use of aBlockEntityWithoutLevelRenderer
.- Block items commonly (but not always) use their corresponding block models as parent. For example, the cobblestone item model uses the parent
minecraft:block/cobblestone
.
ambientocclusion
: Whether to enable ambient occlusion or not. Only effective on block models. Defaults totrue
. If your custom block model has weird shading, try setting this tofalse
.render_type
: See Render Types.gui_light
: Can be"front"
or"side"
. If"front"
, light will come from the front, useful for flat 2D models. If"side"
, light will come from the side, useful for 3D models (especially block models). Defaults to"side"
. Only effective on item models.textures
: A sub-object that maps names (known as texture variables) to texture locations. Texture variables can then be used in elements. They can also be specified in elements, but left unspecified in order for child models to specify them.- Block models should additionally specify a
particle
texture. This texture is used when falling on, running across, or breaking the block. - Item models can also use layer textures, named
layer0
,layer1
, etc., where layers with a higher index are rendered above those with a lower index (e.g.layer1
would be rendered abovelayer0
). Only works if the parent isitem/generated
, and only works for up to 5 layers (layer0
throughlayer4
).
- Block models should additionally specify a
elements
: A list of cuboid elements.overrides
: A list of override models. Only effective on item models.display
: A sub-object that holds the different display options for different perspectives, see linked article for possible keys. Only effective on item models, but often specified in block models so that item models can inherit the display options. Every perspective is an optional sub-object that may contain the following options, which are applied in that order:translation
: The translation of the model, specified as[x, y, z]
.rotation
: The rotation of the model, specified as[x, y, z]
.scale
: The scale of the model, specified as[x, y, z]
.right_rotation
: NeoForge-added. A second rotation that is applied after scaling, specified as[x, y, z]
.
transform
: See Root Transforms.
If you're having trouble finding out how exactly to specify something, have a look at a vanilla model that does something similar.
Render Types
Using the optional NeoForge-added render_type
field, you can set a render type for your model. If this is not set (as is the case in all vanilla models), the game will fall back to the render types hardcoded in ItemBlockRenderTypes
. If ItemBlockRenderTypes
doesn't contain the render type for that block either, it will fall back to minecraft:solid
. Vanilla provides the following default render types:
minecraft:solid
: Used for fully solid blocks, such as stone.minecraft:cutout
: Used for blocks where any pixel is either fully solid or fully transparent, i.e. with either full or no transparency, for example glass.minecraft:cutout_mipped
: Variant ofminecraft:cutout
that will scale down textures at large distances to avoid visual artifacts (mipmapping). Does not apply the mipmapping to item rendering, as it is usually undesired on items and may cause artifacts. Used for example by leaves.minecraft:cutout_mipped_all
: Variant ofminecraft:cutout_mipped
which applies mipmapping to item models as well.minecraft:translucent
: Used for blocks where any pixel may be partially transparent, for example stained glass.minecraft:tripwire
: Used by blocks with the special requirement of being rendered to the weather target, i.e. tripwire.
Selecting the correct render type is a question of performance to some degree. Solid rendering is faster than cutout rendering, and cutout rendering is faster than translucent rendering. Because of this, you should specify the "strictest" render type applicable for your use case, as it will also be the fastest.
If you want, you can also add your own render types. To do so, subscribe to the mod bus event RegisterNamedRenderTypesEvent
and #register
your render types. #register
has three or four parameters:
- The name of the render type. Will be prefixed with your mod id. For example, using
"my_cutout"
here will provideexamplemod:my_cutout
as a new render type for you to use (provided that your mod id isexamplemod
, of course). - The chunk render type. Any of the types in the list returned by
RenderType.chunkBufferLayers()
can be used. - The entity render type. Must be a render type with the
DefaultVertexFormat.NEW_ENTITY
vertex format. - Optional: The fabulous render type. Must be a render type with the
DefaultVertexFormat.NEW_ENTITY
vertex format. Will be used instead of the regular entity render type if the graphics mode is set to Fabulous!. If omitted, falls back to the regular render type. Generally recommended to set if the render type uses transparency in some way.
Elements
An element is a JSON representation of a cuboid object. It has the following properties:
from
: The coordinate of the start corner of the cuboid, specified as[x, y, z]
. Specified in 1/16 block units. For example,[0, 0, 0]
would be the "bottom left" corner,[8, 8, 8]
would be the center, and[16, 16, 16]
would be the "top right" corner of the block.to
: The coordinate of the end corner of the cuboid, specified as[x, y, z]
. Likefrom
, this is specified in 1/16 block units.
Values in from
and to
are limited by Minecraft to the range [-16, 32]
. However, it is highly discouraged to exceed [0, 16]
, as that will lead to lighting and/or culling issues.
neoforge_data
: See Extra Face Data.faces
: An object containing data for of up to 6 faces, namednorth
,south
,east
,west
,up
anddown
, respectively. Every face has the following data:uv
: The uv of the face, specified as[u1, v1, u2, v2]
, whereu1, v1
is the top left uv coordinates andu2, v2
is the bottom right uv coordinates.texture
: The texture to use for the face. Must be a texture variable prefixed with a#
. For example, if your model had a texture namedwood
, you would use#wood
to reference that texture. Technically optional, will use the missing texture if absent.rotation
: Optional. Rotates the texture clockwise by 90, 180 or 270 degrees.cullface
: Optional. Tells the render engine to skip rendering the face when there is a full block touching it in the specified direction. The direction can benorth
,south
,east
,west
,up
ordown
.tintindex
: Optional. Specifies a tint index that may be used by a color handler, see Tinting for more information. Defaults to -1, which means no tinting.neoforge_data
: See Extra Face Data.
Additionally, it can specify the following optional properties:
shade
: Only for block models. Optional. Whether the faces of this element should have direction-dependent shading on it or not. Defaults to true.rotation
: A rotation of the object, specified as a sub object containing the following data:angle
: The rotation angle, in degrees. Can be -45 through 45 in steps of 22.5 degrees.axis
: The axis to rotate around. It is currently not possible to rotate an object around more than one axis.origin
: Optional. The origin point to rotate around, specified as[x, y, z]
. Note that these are absolute values, i.e. they are not relative to the cube's position. If unspecified, will use[0, 0, 0]
.
Extra Face Data
Extra face data (neoforge_data
) can be applied to both an element and a single face of an element. It is optional in all contexts where it is available. If both element-level and face-level extra face data is specified, the face-level data will override the element-level data. Extra data can specify the following data:
color
: Tints the face with the given color. Must be an ARGB value. Can be specified as a string or as a decimal integer (JSON does not support hex literals). Defaults to0xFFFFFFFF
. This can be used as a replacement for tinting if the color values are constant.block_light
: Overrides the block light value used for this face. Defaults to 0.sky_light
: Overrides the sky light value used for this face. Defaults to 0.ambient_occlusion
: Disables or enables ambient occlusion for this face. Defaults to the value set in the model.
Using the custom neoforge:item_layers
loader, you can also specify extra face data to apply to all the geometry in an item/generated
model. In the following example, layer 1 will be tinted red and glow at full brightness:
{
"loader": "neoforge:item_layers",
"parent": "minecraft:item/generated",
"textures": {
"layer0": "minecraft:item/stick",
"layer1": "minecraft:item/glowstone_dust"
},
"neoforge_data": {
"1": {
"color": "0xFFFF0000",
"block_light": 15,
"sky_light": 15,
"ambient_occlusion": false
}
}
}
Overrides
Item overrides can assign a different model to an item based on a float value, called the override value. For example, bows and crossbows use this to change the texture depending on how long they have been drawn. Overrides have both a model and a code side to them.
The model can specify one or multiple override models that should be used when the override value is equal to or greater than the given threshold value. For example, the bow uses two different properties pulling
and pull
. pulling
is treated as a boolean value, with 1 being interpreted as pulling and 0 as not pulling, while pull
represents how much the bow is currently pulled. It then uses these properties to specify usage of three alternative models when charged to below 65% (pulling
1, no pull
value), 65% (pulling
1, pull
0.65) and 90% (pulling
1, pull
0.9). If multiple models apply (because the value keeps on becoming bigger), the last element of the list matches, so make sure your order is correct. The overrides look as follows:
{
// other stuff here
"overrides": [
{
// pulling = 1
"predicate": {
"pulling": 1
},
"model": "item/bow_pulling_0"
},
{
// pulling = 1, pull >= 0.65
"predicate": {
"pulling": 1,
"pull": 0.65
},
"model": "item/bow_pulling_1"
},
// pulling = 1, pull >= 0.9
{
"predicate": {
"pulling": 1,
"pull": 0.9
},
"model": "item/bow_pulling_2"
}
]
}
The code side of things is pretty simple. Assuming that we want to add a property named examplemod:property
to our item, we would use the following code in a client-side event handler:
@SubscribeEvent
public static void onClientSetup(FMLClientSetupEvent event) {
event.enqueueWork(() -> { // ItemProperties#register is not threadsafe, so we need to call it on the main thread
ItemProperties.register(
// The item to apply the property to.
ExampleItems.EXAMPLE_ITEM,
// The id of the property.
ResourceLocation.fromNamespaceAndPath("examplemod", "property"),
// A reference to a method that calculates the override value.
// Parameters are the used item stack, the level context, the player using the item,
// and a random seed you can use.
(stack, level, player, seed) -> someMethodThatReturnsAFloat()
);
});
}
Vanilla Minecraft only allows for float values between 0 and 1. NeoForge patches this to allow arbitrary float values.
Root Transforms
Adding the transform
property at the top level of a model tells the loader that a transformation to all geometry should be applied right before the rotations in a blockstate file (for block models) or the transformations in a display
block (for item models) are applied. This is added by NeoForge.
The root transforms can be specified in two ways. The first way would be as a single property named matrix
containing a transformation 3x4 matrix (row major order, last row is omitted) in the form of a nested JSON array. The matrix is the composition of the translation, left rotation, scale, right rotation and the transformation origin in that order. An example would look like this:
{
// ...
"transform": {
"matrix": [
[0, 0, 0, 0],
[0, 0, 0, 0],
[0, 0, 0, 0]
]
}
}
The second way is to specify a JSON object containing any combination of the following entries, applied in that order:
translation
: The relative translation. Specified as a three-dimensional vector ([x, y, z]
) and defaults to[0, 0, 0]
if absent.rotation
orleft_rotation
: Rotation around the translated origin to be applied before scaling. Defaults to no rotation. Specified in one of the following ways:- A JSON object with a single axis to rotation mapping, e.g.
{"x": 90}
- An array of JSON objects with a single axis to rotation mapping each, applied in the order they are specified in, e.g.
[{"x": 90}, {"y": 45}, {"x": -22.5}]
- An array with three values that each specify the rotation around each axis, e.g.
[90, 45, -22.5]
- An array with four values directly specifying a quaternion, e.g.
[0.38268346, 0, 0, 0.9238795]
(= 45 degrees around the X axis)
- A JSON object with a single axis to rotation mapping, e.g.
scale
: The scale relative to the translated origin. Specified as a three-dimensional vector ([x, y, z]
) and defaults to[1, 1, 1]
if absent.post_rotation
orright_rotation
: Rotation around the translated origin to be applied after scaling. Defaults to no rotation. Specified the same asrotation
.origin
: Origin point used for rotation and scaling. The transformation is also moved here as a final step. Specified either as a three-dimensional vector ([x, y, z]
) or using one of the three builtin values"corner"
(=[0, 0, 0]
),"center"
(=[0.5, 0.5, 0.5]
) or"opposing-corner"
(=[1, 1, 1]
, default).
Blockstate Files
See also: Blockstate files on the Minecraft Wiki
Blockstate files are used by the game to assign different models to different [blockstates]. There must be exactly one blockstate file per block registered to the game. Specifying block models for blockstates works in two mutually exclusive ways: via variants or via multipart.
Inside a variants
block, there is an element for each blockstate. This is the predominant way of associating blockstates with models, used by the vast majority of blocks.
- The key is the string representation of the blockstate without the block name, so for example
"type=top,waterlogged=false"
for a non-waterlogged top slab, or""
for a block with no properties. It is worth noting that unused properties may be omitted. For example, if thewaterlogged
property has no influence on the model chosen, two objectstype=top,waterlogged=false
andtype=top,waterlogged=true
may be collapsed into onetype=top
object. This also means that an empty string is valid for every block. - The value is either a single model object or an array of model objects. If an array of model objects is used, a model will be randomly chosen from it. A model object consists of the following data:
model
: A path to a model file location, relative to the namespace'smodels
folder, for exampleminecraft:block/cobblestone
.x
andy
: Rotation of the model on the x-axis/y-axis. Limited to steps of 90 degrees. Optional each, defaults to 0.uvlock
: Whether to lock the UVs of the model when rotating or not. Optional, defaults to false.weight
: Only useful with arrays of model objects. Gives the object a weight, used when choosing a random model object. Optional, defaults to 1.
In contrast, inside a multipart
block, elements are combined depending on the properties of the blockstate. This method is mainly used by fences and walls, who enable the four directional parts based on boolean properties. A multipart element consists of two parts: a when
block and an apply
block.
- The
when
block specifies either a string representation of a blockstate or a list of properties that must be met for the element to apply. The lists can either be named"OR"
or"AND"
, performing the respective logical operation on its contents. Both single blockstate and list values can additionally specify multiple actual values by separating them with|
(for examplefacing=east|facing=west
). - The
apply
block specifies the model object or an array of model objects to use. This works exactly like with avariants
block.
Tinting
Some blocks, such as grass or leaves, change their texture color based on their location and/or properties. Model elements can specify a tint index on their faces, which will allow a color handler to handle the respective faces. The code side of things works through two events, one for block color handlers and one for item color handlers. They both work pretty similar, so let's have a look at a block handler first:
// Client-side mod bus event handler
@SubscribeEvent
public static void registerBlockColorHandlers(RegisterColorHandlersEvent.Block event) {
// Parameters are the block's state, the level the block is in, the block's position, and the tint index.
// The level and position may be null.
event.register((state, level, pos, tintIndex) -> {
// Replace with your own calculation. See the BlockColors class for vanilla references.
// Colors are in ARGB format. Generally, if the tint index is -1, it means that no tinting
// should take place and a default value should be used instead.
return 0xFFFFFFFF;
},
// A varargs of blocks to apply the tinting to
EXAMPLE_BLOCK.value(), ...);
}
Item handlers work pretty much the same, except for some naming and the lambda parameters:
// Client-side mod bus event handler
@SubscribeEvent
public static void registerItemColorHandlers(RegisterColorHandlersEvent.Item event) {
// Parameters are the item stack and the tint index.
event.register((stack, tintIndex) -> {
// Like above, replace with your own calculation. Vanilla values are in the ItemColors class.
// Also like above, tint index -1 means no tint and should use a default value instead.
return 0xFFFFFFFF;
},
// A varargs of items to apply the tinting to
EXAMPLE_ITEM.value(), ...);
}
Be aware that the item/generated
model specifies tint indices for its various layers - layer0
has tint index 0, layer1
has tint index 1, etc. Also, remember that block items are items, not blocks, and require an item color handler to be colored.
Registering Additional Models
Models that are not associated with a block or item in some way, but are still required in other contexts (e.g. block entity renderers), can be registered through ModelEvent.RegisterAdditional
:
// Client-side mod bus event handler
@SubscribeEvent
public static void registerAdditional(ModelEvent.RegisterAdditional event) {
event.register(new ModelResourceLocation(
// The id of the model
ResourceLocation.fromNamespaceAndPath("examplemod", "block/example_unused_model"),
// The string representing what variant of the model this is for
// In normal vanilla, this would be one of three values:
// - Blocks: The stringified block state
// - Items: 'inventory' as it is the inventory model
// - Standalone: 'standalone' as this does not refer to any other model
"variant_type=true"
));
// An inventory model example
event.register(ModelResourceLocation.inventory(
ResourceLocation.fromNamespaceAndPath("examplemod", "item/example_unused_inventory_model")
));
// A standalone model example
event.register(ModelResourceLocation.standalone(
ResourceLocation.fromNamespaceAndPath("examplemod", "block/example_unused_standalone_model")
));
}