*series*of posts in which we write a voxel engine from scratch for Android.

So we’ve talked about why *chunks* are important in #001, and we made blocks as efficient as possible in #002 using *Draw-Call Batching* and T*exture Atlasing*. Now we can start building a chunk, and filling it with blocks. You might remember that we’re storing blocks inside chunks using a *Lookup-Table* that simply contains 4096 short ints describing each block-type, and *Blocklists*, which store the x,y,z position of visible blocks so they can be batched into a 3D model.

Let’s assume we already have 1 Chunk in the world, and throw down some random blocks by filling the first 256 (16×16 blocks) elements of our Lookup-Table with random numbers, and then building a 3D model from that data…

Success! We have the first layer of blocks in our chunk, which actually contains 16×16**x16** blocks, or 4096 total – so we can add the rest by filling the rest of the Lookup-Table, and rebuilding the model. So the steps for building a chunk are..

- Fill the Lookup-Table with values (-1 = empty space, 0=dirt etc..)
- Calculate which blocks (and block faces) are visible by checking neighboring blocks
- Build a temporary Blocklist of visible blocks with their x,y,z positions
- Build a batched mesh and discard the Blocklist from memory (but we keep the Lookup-Table)

This time we’ve used a single block-type for each layer (for illustrative purposes) and filled the entire chunk with blocks. It still doesn’t look very exciting, and nothing like terrain so far, but we’ll be adding proper terrain later.

Something else is missing…

### Lighting

Because this is for mobile we’re going to use the simplest lighting model possible, namely directional vertex lighting with some linear fog. We’ll add more complex lighting *much* later, but for now, just a very basic shader will do the trick..

//Vertex Shader precision highp float; uniform mat4 u_MVPMatrix; uniform mat4 u_MVMatrix; uniform lowp vec4 u_lightAmbient; //Ambient Light uniform vec3 u_lightDir; //Directional Light Direction uniform lowp vec4 u_lightDirDiffuse; //Directional Light Color uniform lowp float u_fogDist; attribute vec4 a_vPosition; attribute mediump vec2 a_texCoord; attribute vec3 a_vNormal; varying mediump vec2 v_texCoord; varying lowp vec4 v_light; varying lowp float v_fogPower; void main() { vec4 mcPosition = u_MVPMatrix * a_vPosition; vec3 mcNormal = a_vNormal; vec3 ecNormal = vec3(u_MVMatrix * vec4(mcNormal, 0.0)); float ecNormalDotLightDirection = max(0.0, dot(ecNormal, u_lightDir)); //Directional Light lowp vec4 dirLight = ecNormalDotLightDirection * u_lightDirDiffuse; //Directional Light v_light = u_lightAmbient + dirLight; v_texCoord = a_texCoord; v_fogPower = clamp((mcPosition.z / u_fogDist),0.0,1.0); gl_Position = mcPosition; }

//Fragment Shader precision mediump float; uniform lowp sampler2D u_texture; uniform lowp vec4 u_fogColor; uniform lowp vec4 u_vColor; varying mediump vec2 v_texCoord; varying lowp vec4 v_light; varying lowp float v_fogPower; void main() { lowp vec4 ftex = texture2D(u_texture, v_texCoord) * u_vColor * v_light; lowp vec4 fcol = mix(ftex,u_fogColor,v_fogPower); gl_FragColor=fcol; }

Voila! With some empty spaces to show off the lighting better, we now have something that looks a little more solid – but we can do much better than this. We can use the Lookup-Table to calculate some per-vertex (cheap & cheerful) *Ambient Occlusion*, which will cause neighboring blocks to cast some subtle shadows on each-other, and we can do this virtually for free by reducing the vertex normals toward zero for any occluded edges.

The effect is subtle here, but will make more sense with less randomness when we get to making actual terrain. You should notice a gradient in the lighting towards neighboring blocks, which should add some fidelity to our world later on.