[Tutorial] Procedural meshes and voxel terrain C#


C# Voxel Tutorial

This tutorial is now out of date, I’ve replaced it with a new updated tutorial here: [Tutorial] c# voxel terrain with infinite terrain, saving and loading - Learn Content & Certification - Unity Discussions

Learn to create editable voxel terrain made famous by MineCraft and used in a lot of recent games! Voxel terrain has really been taking off recently, it’s a great way to create beautiful and interesting terrain and give the player full reign over the environment. It this tutorial we’ll be making almost everything you would expect for a prototype voxel game. We’ll be using Unity’s mesh class to procedurally generate efficient voxel meshes. We start out by making a 2d tilebased platformer terrain to understand generating meshes and storing level data and in parts 5 and 6 we start building chunks of voxels. This is an intermediate tutorial so if you don’t have any experience with C# you’re going to run into a lot of trouble.

So how am I qualified to make this tutorial? I’ve been exploring Unity’s options for procedural meshes and voxel systems for about a year now. I’ve unfortunately moved my focus away from making a voxel game in unity but I feel like it’s an area a lot of people have an interest in that should be easier to get into because it’s not as complicated as it seems.

This is an example of my voxel terrain and by the end of this tutorial series I expect everyone
following along to be able to produce similar results by the end (You can almost do it by the end of part 6).

Note: Everything covered here is supported by Unity Free, Pro will give you some image effects that might
make things look better but the things we’ll make won’t require a pro licence.

I’m really interested in feedback (This is my first tutorial series) and will do my best to help if anyone has problems. Taryndactyl has already been really helpful in fixing the first few tutorials of problems and I’m trying to get better at avoiding making mistakes but I still need people to let me know if something doesn’t work, even if you manage to fix it the next guy might not so leave a comment.

There are also a lot of great resources out there about voxel development and other concepts that aren’t necessarily directed at unity or voxels that are still very helpful, here are a few of those:
Let’s make a Voxel Engine: Concepts behind a Voxel engine explained in detail by the developer of Vox.
LibNoise: Using noise functions to do amazing things (Voxel engines use noise for adding randomized detail to terrain)
Save Mesh Created by Script in Editor PlayMode: How to save a mesh generated from code ingame by UnityCoder.com
Pathfinding in unity for voxel structures: Again from UnityCoder.com pathfinding for voxel games
Unity forum’s “After Playing MineCraft” thread: You’ve probably seen this but this is the main thread where people have made MineCraft like games using Unity
Cubiquity: An excellent free voxel terrain asset for Unity
More Voxel Resources: Lastly, UnityCoder.com lists even more voxel resources

5 Likes

I will definitely check these out and if I like them you will surely hear back from me. Wish me luck, I love learning this stuff!

EDIT: I noticed errors in your code.

newUV.Add(new Vector2 (tUnit * tStone.x, tUnit * tStone.y)

Should actually be:

newUV.Add(new Vector2 (tUnit * tStone.x, tUnit * tStone.y));

The final parentheses and semi-colon are missing.

And then:

newTriangles.Add(0);
newTriangles.Add(1);
newTriangles.Add(2);
newTriangles.Add(0);
newTriangles.Add(2);
newTriangles.Add(3);

Suddenly becomes:

newTriangles.Add(0);
newTriangles.Add(1);
newTriangles.Add(3);
newTriangles.Add(1);
newTriangles.Add(2);
newTriangles.Add(3);

Without any explanation.

Also, you may want to bold the added line

mesh.uv = newUV.ToArray();

Just to make sure you get the reader’s attention with that other wise it looks wrong.

What I think about this tutorial:
I only finished the first one but I quite like it already.
I will be viewing the rest now.

Thank you so much for pointing out those errors, this is the first tutorial I’ve written so I’m bound to make a few errors so it’s nice to have people who know their stuff. I’m glad you like it! Procedural mesh generation is very exciting :smile:

Tutorial #2

I am getting 20 compiler errors using your exact code.

Here they are, and how to solve them.

  • The name ‘z’ does not exist in the current context. (GenSquare only uses x, y, and texture)
  • Vector3s have some invalid arguments. (Vector3 uses floats (not ints), i.e. 1f)
  • Argument #3 cannot convert ‘object’ to ‘float’. (fixed by adding “float z = transform.position.z;” to the top of GenSquare)

In GenCollider the Vector3s need to be floats, not ints.

I noticed the line [quote]
So that code was just defining the points of the square and then creating the triangle data. The colCount is the same as the faceCount was to the last mesh code we did.
[/quote]
You mention faceCount as if it’s a variable, but that is the ONLY time you mention it… is something missing?

After about 30 of fiddling with my code and redoing this over and over I discovered why my collider meshes were not being rendered.

1347041--66058--$Screen Shot 2013-09-02 at 5.23.28 PM.png
Be sure to check your Gizmo visibility setting and ensure that Mesh Collider is checked on!

Now on to Tutorial #3! (These are great by the way, definitely worth the time!)

I apologize for the double post but I did not want to make this another edit as it is for another tutorial.

Tutorial #3

In the new GenTerrain function you use ‘py’ in a For within another For that also has a variable ‘py’.
This causes a scoping problem. This will explain scoping.

Your [quote]
byte[128, 128]
[/quote] is too large (or maybe I mucked it up somehow) because Unity decided it was all 1 mesh and threw the error of “No more than 65000” vertices in one mesh. I ended up using[quote]
byte[100, 100].
[/quote]

I was unable to reproduce something like

Due to the fact that your instructions were a bit unclear with the multiple Forloops.
Here was my final product, you will notice it is lacking the rolling hills and top layer of dirt/grass.
1347110--66060--$Screen Shot 2013-09-02 at 5.58.14 PM.png

This was definitely an interesting lesson in Perlin Noise and I’m stoked about the final tutorial!

EDIT:

Maybe I will do the final one at a different date. I cannot seem to get the Raycasting to hit correctly.

Ow wow, thanks again Taryndactyl. I’ve updated the posts to fix the problems you pointed out and I changed the array size to 96x128. 128x128 is too large when the array is completely full and it’s displaying a block for every slot but I only tested once I had the terrain in place so I switched it to less so that now even completely filled it doesn’t exceed unity’s limits. I also cleared up what I think was the unclearness in my tutorial with the for loops, I only define py once but at one point there was some code that could have been interpreted as a new for loop whereas I meant it as context to some changes to a few lines in it.

By the way I think your lack of hills might be that with a 100x100 array size the noise for the dirt and rock height are taller than your array. If you were to use 96x128 instead or instead of adding 75 to the dirt and stone variables added 50 you would see them I think.

Again, thanks so much for taking the time to solve the problems you’ve encountered and document them. In the future I will have to start trying my own tutorial in a fresh project to eliminate errors. That must be the best way avoid bugs like these :stuck_out_tongue:

Ok, Sorry to double post but after a long break I’ve finished parts 5 and 6 of the tutorial, by the end you should be able to make landscapes of voxel terrain! The main post is updated with links :smile:

This is what the prototype made in the tutorial looks when finished with placeholder textures.

Thank you, 12pt. I haven’t done all of it yet but so far so good. By the way, that grappling thing looks very neat.

Fantastic Tutorial, and many thanks to Taryndactyl for pointing out the errors. I love the unity community! Weldone 12pt this has been bookmarked

I just added part 7, I got really pumped and felt like editing the terrain is pretty essential so I made it.

Also I did some layout changes to the main post.

Not sure what to work on next, there are a lot of options so if anyone has any suggestions on what to prioritize let me know. I’m thinking maybe lighting or water but I’m not as experienced in those areas as what I’ve done so far so we’ll see. I could also make a player script or spend a little time on terrain generation or add noise to the mesh vertexes or I could show how to make the chunks load around the player instead of everywhere at once. :smile: We’ll see.

Very cool! Thanks for putting this together.

Hi, what i’m trying to make is a 2.5d minecraft-like game. I just finished the tutorial with perlin noise and was wandering how would i go about making the front(by front i mean 0 coordinate on z-axis) vertices that are exposed to air (on x,y) have some displacement? I tried playing with the vertex coordinates that have nothing above them but since vertices aren’t shared between two nearby block i get these big gaps and can’t figure out how to make the vertex displacement work. For more clear idea of what i want: http://forum.unity3d.com/attachment.php?attachmentid=23795&d=1313703312. I’m new to game development and Unity so if you have a solution please dumb it down as much as possible please. Oh also i made my code generate textured squares on top and on the right of the cube (used the collision mesh as an example).

Hey Wieghant, it’s really cool that you’re working with the 2d part of the tutorial. I’ve always though it would make an interesting game environment. So that picture you linked to is similar to something I’ve done before with 3d voxels. What I did to achieve that effect was move all the vertices of the mesh up or down based on perlin noise every time it was built.

Now true, the quads don’t share verts with other quads so you can’t just apply a change to one and have it apply to all the quads sharing a corner but what you can do is move each vertex based on perlin noise that will be the same for every vertex at those positions.

Here’s an example on the 2d terrain that I put together quickly:

1404654--73033--$wavy.jpg

I’m going to be using a script covered in part 6, it’s a script that someone else has written and you can download it, it’s the link in part 6 called Perlin Simplex Noise for C# and XNA so search for that and follow the instructions to implement it (And sorry, you’re going to have to rename the previous Noise function to something else or use Mathf.PerlinNoise but I’m just used to using this noise function). In the start of the genCollider and the genSquare function I generate two floats:

float yNoise=Noise.GetNoise((double)x/10,(double)1000,(double)1000);
float yNoise2=Noise.GetNoise((double)(x+1)/10,(double)1000,(double)1000);

Like this. The first is for the left side of the block, the other is for the right. Then for every vertex that’s +1 in x you add yNoise2 to y and the rest that are just x you add yNoise to the y. Here’s an example of my genSquare function’s verticies part:

newVertices.Add( new Vector3 (x		,  y+yNoise		, 0	));
newVertices.Add( new Vector3 (x + 1	,  y+yNoise2		, 0	));
newVertices.Add( new Vector3 (x + 1	,  y+yNoise2-1	, 0	));
newVertices.Add( new Vector3 (x		,  y+yNoise-1	, 0	));

You add these values to all the verticies and you’ll get noise added to the height of each vertex. Make sure you add only yNoise to the left facing quads for the colliders and your new faces and only yNoise2 for the right facing faces.

Just a side note, with all those faces with the extras you’ve added you might run into Unity’s vertex limit for the mesh in which case you’ll have to make the array smaller.

Good luck!

1 Like

Sorry for the doublepost but I just finished the eighth and final part of the tutorial!

Part 8: Loading Chunks

I hope everyone’s had fun with this and gotten some things made. It’s been a lot of fun to write and I’ll be making another tutorial as soon as I have time and figure out what to write about. Thanks for all the comments and for all the help ironing out the bugs, next time I’m hoping to have a few testers to try the parts before I release them.

Could you post the finished project? :slight_smile: Btw nice tutorial!

Here’s a post with a webplayer demo and a unity package of the project: Student Game Dev has moved!: Voxel Tutorial: Webplayer, Project

Hi dude,

Amazing thread, before I start watching, does this support iOS mobile.
Can these worlds be created for phone and performance is lag free?

Hey, 12pt. I must agree that this is an awesome thread! I’ve tried to learn mesh generation before, but I’ve never understood it until now.
So thank you! This has been a great help for my game! :slight_smile:

I’ve copied the full scripts from part 6 but there seems to be problems with the code:

  1. There were some ""s that were causing errors. (Line 33 in Chunk, and Line 45 in World)
  2. I get “Assets/Resources/scripts/World 2.0/World.cs(60,10): error CS0103: The name `Noise’ does not exist in the current context” when I compile.

Can you please tell me how to fix the second error?

Hey Epicwolf, glad you worked through the errors with the backslashes, it’s an unfortunate problem with quotes and html that I should probably make a note about in the tutorials. As for the Noise function that’s a reference to the script I linked to in part 6, it’s an implementation of simplex noise for C# that you’ll have to paste into a new c# script. Open Part 6 and find “Perlin Simplex Noise for C# and XNA” on the page for the instructions. I didn’t include this one along with the full scripts I posted because it’s just a matter of copying this from the implementation in a new file.

MrEsquire, I haven’t run this code on iOS but I have tried it out on android. There are optimizations that have to be made, it won’t handle the same size as the computer and you could really improve it by removing the colliders and writing some custom collider code based on the level data. It’s definitely doable but it will require more optimization and some compromises.

@12pt

This is a great set of walkthroughs! Is there any interest on your end for an additional tutorial on smoothing things out with Marching Cubes? Marching cubes is something I just can’t seem to wrap my head around. Again, great stuff! :slight_smile: