Sunday, 11 August 2013

Rendering Items

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)- contained within an EntityItem
  • On a player's head (helmet inventory slot)- "head"
  • In a picture frame – 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; 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").  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).

Further information

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.  Item.getColorFromItemStack(stack, layer) is called to determine what the colour multiplier for that 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)
  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.

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.