Saturday, 20 July 2013

Rendering Non-standard Blocks

In the vanilla code, rendering a non-standard block is typically done by calling the same methods as standard blocks (i.e.  renderStandardBlock, or the various .renderFace#### methods), after changing one or more static member variables in RenderBlocks:
  •  .setRenderBounds(minX, minY, minZ, maxX, maxY, maxZ): These define the size and location of the block faces within the 1x1x1 cube and allow you to draw blocks which are smaller than the full 1x1x1 cube. See example pictures below.  For simple blocks you can just set the boundaries using  this.setBlockBounds() in the constructor, or setBlockBoundsBasedOnState if the boundaries vary depending on the metadata.  Note - if you set the render bounds smaller than the full cube, makes sure your MyBlock overrides isOpaqueCube() to return false, otherwise you will see blank patches of colour where adjacent block faces should be.  
  • .flipTexture (for X and Z renders only): flips the texture left-right. The flipTexture flag is not used by the Top and Bottom faces. See example pictures below. Note! You must set this flag back to false afterwards, otherwise other blocks in the scene will also be flipped.
  • .uvRotateSouth, uvRotateTop, etc : rotates the texture on the corresponding face through 90, 180, or 270 degrees. For example, uvRotateTop is used by renderFaceYPos. The face number, direction, renderFace method, and flag name are listed below. Unfortunately, most of these flags are currently incorrectly named. And some of the faces get flipped left-right before rotating by 90 or 270 degrees. Confused? So am I! The example pictures below may help. Note that flipTexture has no effect when using the uvRotate#### flags. 
                0 = bottom = YNeg = uvRotateBottom
                1 = top = YPos = uvRotateTop
                2 = north = ZNeg = uvRotateEast 
                3 = south = ZPos = uvRotateWest 
                4 = west = XNeg = uvRotateNorth
                5 = east = XPos = uvRotateSouth


Many of the non-standard blocks can be rendered in this way, with repeated calls to renderStandardBlock() or renderFace####() as necessary, changing the flags each time.  However if the render requires any faces which aren't aligned with the axes (eg a torch, which is at an angle to the wall), then Tesselator.addVertexWithUV is used instead.  More details here.

If you call the renderFace####() methods, you will need to set up the lighting information beforehand.   See here for more information on lighting.   The relatively easy way is to use Tessellator.setBrightness() and Tessellator. setColorOpaque_F().   More hardcore is the "smooth lighting" setting - if you set .enableAO to true, the renderFace####() methods will expect you to set up all the per-vertex lighting information as well (12 colour settings eg .colorRedBottomRight, plus 4 brightness settings eg .brightnessTopRight, etc).  This is an exercise in head damage.  Luckily I can't think of any situations where it would be required.


  1. I love the effort you put into this. It would really help us beginners get a feel of how all the Minecraft classes interact with eachother.

  2. Thank you for all of this hard work.

  3. Thank you for this all, especially your Ambient Occlusion article
    Even if it is outdated 1.7.10 coding material, keep it online because there are still people to care to maintain and improuve old mods (even when some other people are dismissing this as a valid choice because they want to promote the ever-changing flow of new shiny versions you can never keep-up with and kills the most refined mods projects.