Search code examples
opengl3dtexturesvoxel

Efficient method for rendering cubes with different textures on each side for a Minecraft-like game?


I'm trying to decide what the most efficient way to render a bunch of cubes with different textures in a Minecraft-like game is.

I discovered instanced rendering. What I've done is I've created a single "cube model" which stores all the vertices, normals, and texture coordinates for a cube, I create an array buffer out of that and pass it to the GPU once. Then I created a array of (translation vector, texture index) structs and I use instanced rendering to redraw the same cube over and over, each time translated and with the appropriate texture.

(Hopefully Notch doesn't mind me using his textures until I make my own)

The problem is that not all 6 sides will always have the same texture, and I'm trying to figure out how I can get them to be different for each block type. The two solutions I've come up with are:

  1. Use a different Model for each block type. This way I can specify different texture coordinates on each of the vertices. I can still use instanced rendering, but I'd have do a separate pass for each block type.
  2. Pass 6 "texture indexes" (1 for each face) instead of 1 for every block.

The 2nd solution requires passing a lot more, possibly redundant, data. I'm not sure how great the benefits of instanced rendering are... so I don't know if it would be better to do, say, up to 256 "passes" (1 for each block type), or "one big pass" with all the data, and render every block in one shot.

Or perhaps there's another method I'm not aware of?


Solution

  • I don't think you can do it efficiently with instances. Vast majority of faces/cubes is never visible and you can save a lot of time by not rendering them. Unfortunately that makes every cube a different object.

    The standard solution (and how it's done in Minecraft) is to divide your terrain into sectors . Compute which faces are visible and upload them to GPU. When a cube changes you just need to re-upload it's sector. When rendering a sector you just draw primitives without any other computations.

    You can do something based on sparse voxel octrees. It's much more work, but you would be able to efficiently and accurately tell which parts of your world are visible.