



Hello everyone following the voxel tutorial, it's been a long time since an update. In this time I've written a new updated tutorial on voxel terrain that supports infinite terrain and saving/loading of chunks. Try it out on my new site: AlexStv.com

using UnityEngine; using System.Collections; using System.Collections.Generic; public class Chunk : MonoBehaviour { private List<Vector3> newVertices = new List<Vector3>(); private List<int> newTriangles = new List<int>(); private List<Vector2> newUV = new List<Vector2>(); private float tUnit = 0.25f; private Vector2 tStone = new Vector2 (1, 0); private Vector2 tGrass = new Vector2 (0, 1); private Mesh mesh; private MeshCollider col; private int faceCount;

mesh = GetComponent<MeshFilter> ().mesh; col = GetComponent<MeshCollider> ();

void CubeTop (int x, int y, int z, byte block) { } void UpdateMesh () { }

void Start () { mesh = GetComponent<MeshFilter> ().mesh; col = GetComponent<MeshCollider> (); CubeTop(0,0,0,0); UpdateMesh (); }

void CubeTop (int x, int y, int z, byte block) { newVertices.Add(new Vector3 (x, y, z + 1)); newVertices.Add(new Vector3 (x + 1, y, z + 1)); newVertices.Add(new Vector3 (x + 1, y, z )); newVertices.Add(new Vector3 (x, y, z )); newTriangles.Add(faceCount * 4 ); //1 newTriangles.Add(faceCount * 4 + 1 ); //2 newTriangles.Add(faceCount * 4 + 2 ); //3 newTriangles.Add(faceCount * 4 ); //1 newTriangles.Add(faceCount * 4 + 2 ); //3 newTriangles.Add(faceCount * 4 + 3 ); //4 Vector2 texturePos; texturePos=tStone; newUV.Add(new Vector2 (tUnit * texturePos.x + tUnit, tUnit * texturePos.y)); newUV.Add(new Vector2 (tUnit * texturePos.x + tUnit, tUnit * texturePos.y + tUnit)); newUV.Add(new Vector2 (tUnit * texturePos.x, tUnit * texturePos.y + tUnit)); newUV.Add(new Vector2 (tUnit * texturePos.x, tUnit * texturePos.y)); }

void UpdateMesh () { mesh.Clear (); mesh.vertices = newVertices.ToArray(); mesh.uv = newUV.ToArray(); mesh.triangles = newTriangles.ToArray(); mesh.Optimize (); mesh.RecalculateNormals (); //col.sharedMesh=null; //col.sharedMesh=mesh; newVertices.Clear(); newUV.Clear(); newTriangles.Clear(); faceCount=0; //Fixed: Added this thanks to a bug pointed out by ratnushock! }

This is what you should see when you run

void Cube (Vector2 texturePos) { newTriangles.Add(faceCount * 4 ); //1 newTriangles.Add(faceCount * 4 + 1 ); //2 newTriangles.Add(faceCount * 4 + 2 ); //3 newTriangles.Add(faceCount * 4 ); //1 newTriangles.Add(faceCount * 4 + 2 ); //3 newTriangles.Add(faceCount * 4 + 3 ); //4 newUV.Add(new Vector2 (tUnit * texturePos.x + tUnit, tUnit * texturePos.y)); newUV.Add(new Vector2 (tUnit * texturePos.x + tUnit, tUnit * texturePos.y + tUnit)); newUV.Add(new Vector2 (tUnit * texturePos.x, tUnit * texturePos.y + tUnit)); newUV.Add(new Vector2 (tUnit * texturePos.x, tUnit * texturePos.y)); faceCount++; // Add this line }

void CubeTop (int x, int y, int z, byte block) { newVertices.Add(new Vector3 (x, y, z + 1)); newVertices.Add(new Vector3 (x + 1, y, z + 1)); newVertices.Add(new Vector3 (x + 1, y, z )); newVertices.Add(new Vector3 (x, y, z )); Vector2 texturePos; texturePos=tStone; Cube (texturePos); }

//CubeNorth newVertices.Add(new Vector3 (x + 1, y-1, z + 1)); newVertices.Add(new Vector3 (x + 1, y, z + 1)); newVertices.Add(new Vector3 (x, y, z + 1)); newVertices.Add(new Vector3 (x, y-1, z + 1)); //CubeEast newVertices.Add(new Vector3 (x + 1, y - 1, z)); newVertices.Add(new Vector3 (x + 1, y, z)); newVertices.Add(new Vector3 (x + 1, y, z + 1)); newVertices.Add(new Vector3 (x + 1, y - 1, z + 1)); //CubeSouth newVertices.Add(new Vector3 (x, y - 1, z)); newVertices.Add(new Vector3 (x, y, z)); newVertices.Add(new Vector3 (x + 1, y, z)); newVertices.Add(new Vector3 (x + 1, y - 1, z)); //CubeWest newVertices.Add(new Vector3 (x, y- 1, z + 1)); newVertices.Add(new Vector3 (x, y, z + 1)); newVertices.Add(new Vector3 (x, y, z)); newVertices.Add(new Vector3 (x, y - 1, z)); //CubeBot newVertices.Add(new Vector3 (x, y-1, z )); newVertices.Add(new Vector3 (x + 1, y-1, z )); newVertices.Add(new Vector3 (x + 1, y-1, z + 1)); newVertices.Add(new Vector3 (x, y-1, z + 1));

You should see this

col.sharedMesh=null; col.sharedMesh=mesh;

Ok, I took a long break since the last part. I'm pretty bad at being active especially with a lot of work to focus on but without further adieu we will start building our meshes to be viewed in 3d. This is probably what a lot of people had in mind when they started this tutorial series but I promise, with the understanding gained from the earlier tutorials this part will come a lot easier. However users that haven't followed the last 4 parts are welcome to start here but I won't be going into as much detail about how meshes are created.Also this tutorial and the next one I'm writing as I go instead of using parts of my finished code (of course still using that as reference) so I'm hoping that will help stop me from making as many mistakes as I shouldn't skip things or have to make changes to things as I past them to the tutorial as much.Let's start by making a new scene in unity with an empty game object. Name that object "Chunk", this will be the mesh for a 16x16x16 area (Or larger) of our world. Also make a new script and call it "Chunk" as well because it goes on the chunk object. Let's make our code create one cube to start.First of all set up the variables:When you're adding these remember to include the line "using System.Collections.Generic;" from line 3 up there. Now, this should look pretty familiar, same lists of verticies, tris and UVs, a tUnit and texture coordinates, our mesh filter and mesh collider and lastly a faceCount which is just a new name for the squareCount we used in the other script.Set up the start function to set some of our variables:After you've done this go to unity and add a Mesh Filter, a Mesh Renderer and a Mesh Collider to our Chunk game object.Now create two functions:And call them in the start loop:CubeTop will be one of six functions that generate a side of the cube and update mesh will commit the verticies and things to the mesh filter. We'll just start with the top to get it working.Because this is actually very similar to the 2d example I'll take this in some larger steps than normal now, here is what we need in the CubeTop function:And here is the UpdateMesh Function:What's happening here? Well CubeTop runs first and it creates verticies for a square facing upwards using the x,y,z coordinates, then it creates numbers for the triangles using the faceCount and lastly it applies the texture at the coordinates to the face. For now though texturePos is just set to tStone. We'll add some ifs to set the texture once we have more than one cube.Now lets hop over to unity and place our gameobjects so that we can run. Put the Chunk at 0,0,0 and set the camera's position y to 10 and rotation x to 45. This should put it dead center.So as you can see there are no textures yet and it's just the top face so let's add the materials first of all. Just drag the tilesheet texture onto the chunk gameobject (for those of you who haven't done the previous tutorials, the tilesheet is a 128x128 size image with 4x4 tiles. Here's the one I'm using: Link! ).For the rest of the faces the functions will be quite similar, all we'll be doing is adjusting the verticies. Pretty much the rest of the function will be the same for every face so what we'll do is remove the common parts of the functions and put them in a separate function instead of having it written out for each face.So create a new function called Cube with a Vector2 called texturePos as a parameter, this function will be called for every face and run all the code common to all faces. Move the newTriangles lines to it and the newUV lines to it. Then add "faceCount++" to the end.Now your CubeTop function should be a little shorter but call Cube(texturePos); at the end of the function. We decide the texture coordinates in the function unique to each side because the Cube function doesn't have any block data to decide what texture to use and because textures might be based on which face of the cube we're making. Your CubeTop function should look like this now:Now we can make the other five functions, they'll look just the same as this one except that they'll use different coordinates for the verticies. Later on they will also decide what textures to use in the unique functions but for now just keep using texturePos=tStone.Now create 5 new functions with the same content as CubeTop called CubeNorth, CubeEast, CubeSouth, CubeWest and CubeBot but change out the newVerticies lines with these:Now you should have 6 functions and one common function for the faces of the cube. Go to the start function and add the five new functions after CubeTop with the parameters 0,0,0,0 for all of them. If you run it in unity now you should see a cube, not so visible in the camera view but if you look around in the scene view you'll see it.Lets have a look at the collision model generation as well, in the 2d example we generated a different collision mesh after the mesh to be rendered but here we'll use the same mesh for both. The commented lines in the UpdateMesh function do just this. First of all we reset the collision mesh and then we set the collision mesh to mesh so we use the same one we've already made for the mesh renderer. So, uncomment these lines:And you'll have a cube with a collision mesh!I'll end this part here, it seems like a logical point to stop but what we have now is more than a cube, what we have is a system to create individual faces which will come in very handy when we're creating a surface that resembles cubes but is actually made of just the visible faces. But that's for next time.Until then please message me with any problems you find and follow me on twitter or google plus to get updated!