Some important things to note:
- You can only see faces which point in your direction. Any faces which are pointing the other way (eg faces 2 and 0 in the pictures above) are not visible until you walk to the other side of the block (as per faces 4 and 5 above).
- You need to override isOpaqueCube() to return false, otherwise the adjacent faces of adjacent blocks won't be rendered properly, for example see below. For more information on the various effects of isOpaqueCube, see here.
|isOpaqueCube returns true - grass under the block is not rendered|
- The transparency is either on or off - a pixel is either fully transparent or fully opaque. For exampe - if your alpha channel has 50% transparency, it will be treated as opaque.
- pass 0 (all pixels either "opaque" or "fully transparent"), back faces not rendered
- pass 1 (0 - 100% transparency; back faces visible).
|Ice rendered in pass 1 (left) or pass 0 (right).|
If our example cube is converted to have a striped alpha channel on the "2" face, i.e. from top to bottom 0%, 25%, 50%, 75%:
then it renders as follows in the two different passes:
|Pass 0 render (left) vs pass 1 render (right)|
The key differences are:
- Pass 1 renders 25%, 50%, 75% transparency as partially transparent.
- The back faces (eg 3) are visible in pass 1
It is possible to render a block in both passes, but this is not generally useful.
If multiple transparent blocks are placed next to each other, the internal faces are all visible (the two "4" faces in the picture below). This is different from (for example) glass and ice, where these "internal faces" are not shown.
Minecraft achieves this using the shouldSideBeRendered() method. For example - BlockGlass overrides shouldSideBeRendered(), and returns false if the adjacent block is also a glass block. (see BlockBreakable.shouldSideBeRendered()).
|BlockGlass.shouldSideBeRendered(): left = vanilla code; right = overridden to always return true|