Wednesday, 11 September 2013

Custom Item rendering using IItemRenderer

If you want your item to have non-vanilla rendering, your best best is probably to make use of the Forge IItemRenderer interface.  The same method in this interface is called whenever your item is rendered, regardless of whether the view is Inventory, Equipped (First person or Third person), or Dropped ("ENTITY").  The diagram below shows the various entry points.  The key concepts are:
  1. Write your rendering class to implement IItemRenderer.  Register it with MinecraftForgeClient.registerItemRenderer().
  2. The same method (IItemRenderer.renderItem) is called for all views, with one of the five ItemRenderTypes (INVENTORY, ENTITY, etc) passed in as a parameter.
  3. Your render code in renderItem() should look at the rendertype parameter to decide which view it needs to render.
  4. Your code should override .handleRenderType to return true for each of the rendering views it supports.
  5. ForgeHooksClient can apply a number of different transformations to the view before passing control to your .renderItem code.  These are called RenderHelpers.  Before calling .renderItem, MinecraftForgeClient queries IItemRenderer.shouldUseRenderHelper(HELPER) to see whether it should apply that helper or not.  For further details see below.

Diagram showing how the vanilla code interfaces with IItemRenderer to render the various different views of an Item.


The diagrams below show how the four different render types (INVENTORY, EQUIPPED_FIRST_PERSON,  EQUIPPED, and ENTITY) are affected by the various RenderHelpers. Unfortunately, the coordinate range that the caller expects you to render over is not consistent for the different views. In most cases a transformation using GL11.glTranslatef() and GL11.glScalef() will be the easiest way to compensate for this.  If you're finding it all a bit confusing, looking at the sample code may help.
Diagram identifying the faces of the test cube used for the examples below.  (In the pictures below, each face also has a unique colour.)  

Rendering options for renderItem(INVENTORY).  

Rendering Options for renderItem(EQUIPPED_FIRST_PERSON).

Rendering options for renderItem(EQUIPPED).  Also depends on whether Item.isFull3D() is overridden to return true.

Rendering options for renderItem(ENTITY).

Some miscellaneous notes

If your Item's custom renderer uses an icon from the block texture map, make sure that Item.getSpriteNumber() returns 0, otherwise the tessellator will render using the item texture map, i.e. the wrong icons will be used.

In order to get the lighting right for your custom render, you will need to use tessellator.setNormal to set the normal before you draw each face.  The normal affects the brightness of the face; if the normal points directly towards the scene's light source, the face will be bright.  As the normal moves away from the scene's light source, the face brightness will decrease.
  • If you can't be bothered to light each face differently, use
    tessellator.setNormal(0.0F, 1.0F, 0.0F);
     This will make all faces bright (the normal faces up).
  • For cubes, the normal points in the direction of the axis, eg east face is [1.0F, 0.0F, 0.0F],  bottom face is [0.0F, -1.0F, 0.0F], etc
  • For arbitrary faces, calculate the normalised cross product of two adjacent edges of each face.  for example, for a south-east face, i.e. the normal is [0.707, 0.0, 0.707].   This tool can be useful for these calculations, you will need to adjust the sign of the normal to make sure it is pointing in the correct direction. 
Diagram showing how the Normal relates to the face.
For some reason, rendering in Third Person Equipped turns off back-face culling.  i.e. you can see faces from both sides.  If this makes your rendering look strange, you can turn it back on using GL11.glEnable(GL11.GL_CULL_FACE);

No comments:

Post a Comment