Monday, 29 December 2014

Item Rendering [1.8]


To skip straight to sample code, click here.

A useful tool for adjusting the item rendering (ItemCameraTransform) is here.
Another useful tool for generating more complicated item models is here.

Rendering items is a bit complicated because there are a number of different places they can be seen:
  • In the Inventory (also in the Speedbar overlay) – referred to in Vanilla code as a GUI item (graphical user interface) "gui"
  • Equipped (held in the player’s hand) – in first person view ("firstperson") or third person view ("thirdperson").
  • Dropped (on the ground "ground")- contained within an EntityItem
  • On a player's head (helmet inventory slot)- "head"
  • In a picture frame ("fixed")– contained within an EntityItemFrame
In addition to this,
  • Most Items which are also Blocks are rendered in 3D (eg TNT), which uses a rendering model generally the same as the Block.  This type of item is usually an ItemBlock.
  • If fancy graphics are enabled, 2D Items have thickness when dropped and also slowly rotate.
  • There are several flags which affect the display of items such as bobbing and rotation when dropped.
  •  ItemStack (multiple items/blocks) render with a number in the GUI overlay and as a pile of minicubes when dropped.

The pictures below show these various different renders:

Item (Pickaxe) and 3D Block (TNT) rendered into the GUI ("gui")

 Fancy graphics enabled.
GUI items (red): Item (pickaxe),  3D Block (TNT), 2D Block (Bed), multiple blocks (Dirt)
Equipped Item (pickaxe blue circle);
Dropped Item/EntityItems (purple):  Item (Pickaxe), 3D Block (TNT), 2D Block (Bed), multiple blocks rendered as minicubes (Dirt)

Fancy graphics disabled.
 Dropped Item/EntityItems (yellow):  Item (Pickaxe), 2D Block (Bed)

Equipped Item - first person view: 3D block (TNT)

Equipped item - third person view: 3D block (TNT)


Items rendered in frames - rendered as per EntityItem: Item (pickaxe), 2D Block (bed), 3D Block (TNT)
Minecraft deals with all these different situations as follows:
  1. Each item has a JSON Item Model file which defines the model used for rendering the item.  This falls into one of several categories:
    a) The model uses one of the 3D block models as a base; or
    b) A "2D" model (with optional thickness) is generated from an item texture (see ItemModelGenerator for the vanilla code which does it); or
    c) for a number of predefined hard-coded items (chests, compass, clock, banner, skull), the rendering is hard-coded in render classes.
  2. The JSON model also defines an ItemCameraTransform for one or more of the different ways an item might be viewed (i.e "gui", "firstperson", "thirdperson", "head", "fixed", "ground").  Each ItemCameraTransform consists of translation, rotation, and scaling information, which is used to position and size the item correctly when rendered in a particular view.
This link describes the structure of the JSON Item Model file (see the Item Models section halfway down).
A useful tool for adjusting the item rendering (ItemCameraTransform) is here.  If you place the mod file in {YourProjectFolder}/eclipse/mods, it will be loaded when you build+run your mod's sourcecode from Eclipse or IntelliJ and you can interactively adjust your custom item's rotation, translation, and scale.

Further information

In order for vanilla to find your Item Model file, you need to register it. Currently this is done using in one of three ways:
  1. If your item has no subtypes (metadata) (eg ItemShears):
    ModelResourceLocation res = new ModelResourceLocation("mymod:model", "inventory");
    Minecraft.getMinecraft().getRenderItem().getItemModelMesher().register(item instance, 0, res);
  2. If your item has subtypes (metadata) and you want a model for each one (eg ItemDye):
    {..}.getItemModelMesher().register(item instance, 0, res0);  //res0 = model0
    {..}.getItemModelMesher().register(item instance, 1, res1);                //res1 = model1
    {etc}
  3. If your model has subtypes but you want to use a single model for all of them (eg such as ItemPotion), ignoring the metadata:
        {..}.getItemModelMesher.register(item_instance, new ItemMeshDefinition()
              {
                 public ModelResourceLocation getModelLocation(ItemStack stack)
                {
                   return new ModelResourceLocation("spawn_egg", "inventory");
                }
               }    );

If your Item has variants, you will also need to register them with the ModelBakery.addVariantName(), otherwise it will default to the item unlocalisedname for all variants and throw up 'missing model' errors.

The appearance of an item can be modified by code in a number of ways:
  1. Autogenerated (2D items) are built up in layers: the JSON file can specify a texture for layer0, another texture for layer1, and so on.  See example of the spawn egg below. Layers 0 - 4 are permitted in the code, although vanilla models use at most layer0 and layer1.  During auto-generation, the "tintIndex" flag for each quad within a layer is set to the layer number; for example the spawn egg consists of two layers as shown below.  When the item is rendered, layer 0 is rendered first, then layer1, then layer2, etc.  Item.getColorFromItemStack(stack, layer) is called to determine what the colour multiplier for each layer should be.  This allows a single item model to be rendered with a variety of different colours, the best example being spawn eggs and potions.  
  2. If Item.hasEffect() is true (typically because it is enchanted) then an animated "glint" effect (called "foil" in the vanilla code) is rendered over the top.
  3. When rendering in the GUI, the number of items and the item damage bar are added as an "overlay".  Item.showDurabilityBar() and Item.getDurabilityForDisplay() are useful for controlling the appearance of the damage bar.
  4. In the first person view, the position of the player's arm and hence the item are handled in ItemRenderer.renderItemInFirstPerson.  Two item properties in particular affect this, including:
    ItemStack.getItemUseAction() (NONE, DRINK, EAT, BLOCK, BOW)
    Item.getMaxItemUseDuration()
  5. The item appearance can be animated when it is being held by a player (see RenderItem.renderItemModelForEntity()).  For the fishing rod and the bow, this is hard-coded, however for other Items the model can be changed depending on metadata and duration of use action (eg drawing a bow) by overriding Item.getModel().
File:excerpt from item/spawn_egg.json
{
    "parent": "builtin/generated",
    "textures": {
        "layer0": "items/spawn_egg",
        "layer1": "items/spawn_egg_overlay"    },





IBakedModel.isGui3d() is always false for autogenerated 2D items, and always true otherwise.

The ItemCameraTransform (see example below) is applied in the following order:
  1. GlStateManager.translate(x,y,z)
  2. GlStateManager.rotate{y degrees around y axis}
  3. GlStateManager.rotate{x degrees around x axis}
  4. GlStateManager.rotate{z degrees around z axis}
  5. GLstateManager.scale(x,y,z)

It can be difficult to get these right; I suggest you think of a vanilla item that should be held in a similar way to yours, copy its transform, and then tweak it until it looks right.  I suggest doing the rotation first, one axis at a time, then the scaling, then the translation.  Using this tool of course.

file: excerpt from item/diamond_sword.json
"display": {
"thirdperson": {
    "rotation": [ 0, 90, -35 ],
    "translation": [ 0, 1.25, -3.5 ],
    "scale": [ 0.85, 0.85, 0.85 ]
},
EntityItem and EntityItemFrame are rendered with no transform ("none").

The most interesting vanilla classes to look at for Item Rendering are
  1. ItemRenderer (various methods to render items in different views)
  2. RenderItem (called by ItemRenderer)
  3. TileEntityItemStackRenderer for the hard-coded rendering of TileEntityChest, TileEntityBanner, TileEntitySkull
  4. RenderEntityItem for the rendering of EntityItems (dropped items)
  5. RenderItemFrame for items rendering in an item frame.  The RenderItemInFrameEvent is potentially useful here too.


9 comments:

  1. This comment has been removed by the author.

    ReplyDelete
  2. This comment has been removed by the author.

    ReplyDelete
  3. I am having trouble with my item being rendered correctly.
    Everything seems to be correct and in order, including the model file and texture image, and I am getting nothing unusual in console output. I have already corrected file path errors and even received console output about texture image size (which I corrected with a different image). All other aspects of the item seem to be working correctly.
    The problem is that my item is only being rendered as what I assume is the fallback block (standard 3D block, checkered 2 color texture), and not at all the texture I have referenced in the json. This goes for all viewpoints; first, third, and GUI.

    Thanks,
    avin

    ReplyDelete
  4. Hi
    Yeah it can be very frustrating to troubleshoot when there are almost no symptoms. I am working on a step-by-step troubleshooter at the moment, but in the meantime you can try to track it down yourself by holding your item in your hand and inserting a breakpoint in ModelManager.getModel(). That is usually the place where the default (fallback) model is silently retrieved. You can use that as a starting point to find out why your model is not being correctly retrieved.
    -TGG

    ReplyDelete
  5. I want to thank you for these absolutely awesome and incredibly helpful articles. Thank you!
    Also thank you for the incredibly helpful Item Transformation Helper tool/mod!
    (Btw I just submitted a PR for it for some additional model support and a fix for locale issues in output.)

    -masa

    ReplyDelete
  6. The ItemCameraTransform tool is great. It would have taken me forever to get the position correct without it.

    avin

    ReplyDelete
  7. I can't manage to render a pick with « RenderItem.renderItemModelForEntity() ». Could I have an example please ?

    ReplyDelete
  8. Hi; perhaps best to post your question and code to the Minecraft forge forum... lots of helpful folks there...
    http://www.minecraftforge.net/forum/index.php/board,73.0.html
    -TGG

    ReplyDelete