Thanks for a great tutorial and you explained it very well. This is my first time procedurally generating anything and creating a mesh through code and.... it works! Just out of curiosity is there not an easier way to do this and also, surely this would not be good for optimization?
Sadly manually creating each vertice and triangle is the only way, luckily once you create one cube you can create many of them just by looping! Ideally to increase performance you'd use chunks so you don't have to redraw the entire terrain, and instead you only need to redraw a 16x16 block :D
Just to create "simple" Minecraft style world generation, at this stage I won't be going over biomes, or ores depends on the response to the first few episodes, however we will be going over terrain, trees and grass as well as caves:)
In this situation, either or would work, no right or wrong answer, I personally prefer to divvy stuff up into functions for my own readability. If the scope of this project was larger then I'd default to switches, but in this case, doesn't matter :D
Isen't it better to not make new vertices after you make your front and back face since at that point you have all the vertices you need in your vertices list?
Not necessarily... Technically it sounds correct "optimise your mesh by sharing vertices" however, the issue with sharing vertices is that your also sharing normals. Normals are what help our mesh determine how to light each face (basically it does the lighting on a model). If we share vertices, if means that all our faces would share the same lighting data, producing a very gross looking cube XD To get a nice sharp edged cube, we need to create a new vertex for each face. This is a for all models if you want sharp edges, if we were creating a smooth looking terrain then we'd share vertices and normals. Hope this makes sense, its a difficult concept to wrap your head around, procedural mesh generation isn't easy so don't worry if you get stuck! Feel free to join the Discord if you wanna talk about it further :D
Code form video (Make sure to rename Voxel to script name or vise versa):
using System.Collections;
using UnityEngine;
using System.Collections.Generic;
[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class Voxel : MonoBehaviour
{
public Vector3 pos;
public Mesh mesh;
public List vertices = new List();
public List triangles = new List();
public List uvs = new List();
private int lastVertex;
private void Start(){
// Init Mesh
mesh = new Mesh();
// Create mesh data
drawCube();
// Set Mesh data
mesh.vertices = vertices.ToArray();
mesh.triangles = triangles.ToArray();
mesh.SetUVs(0,uvs.ToArray());
// Recalculate Lighting
mesh.RecalculateNormals();
// Set the mesh
GetComponent().mesh = mesh;
}
void drawCube(){
generateFrontFace();
generateBackFace();
generateLeftFace();
generateRightFace();
generateTopFace();
generateBottomFace();
}
void generateFrontFace(){
lastVertex = vertices.Count;
// Declare vertices
vertices.Add(pos + Vector3.forward); // 0
vertices.Add(pos + Vector3.forward + Vector3.up); // 1
vertices.Add(pos + Vector3.forward + Vector3.up + Vector3.right); // 2
vertices.Add(pos + Vector3.forward + Vector3.right); // 3
// First triangle
triangles.Add(lastVertex + 2);
triangles.Add(lastVertex + 1);
triangles.Add(lastVertex);
// Second triangle
triangles.Add(lastVertex);
triangles.Add(lastVertex + 3);
triangles.Add(lastVertex + 2);
}
void generateBackFace(){
lastVertex = vertices.Count;
// Declare vertices
vertices.Add(pos + Vector3.right); // 0
vertices.Add(pos + Vector3.up + Vector3.right); // 1
vertices.Add(pos + Vector3.up); // 2
vertices.Add(pos); // 3
// First triangle
triangles.Add(lastVertex + 2);
triangles.Add(lastVertex + 1);
triangles.Add(lastVertex);
// Second triangle
triangles.Add(lastVertex);
triangles.Add(lastVertex + 3);
triangles.Add(lastVertex + 2);
}
void generateLeftFace(){
lastVertex = vertices.Count;
// Declare vertices
vertices.Add(pos); // 0
vertices.Add(pos + Vector3.up); // 1
vertices.Add(pos + Vector3.forward + Vector3.up); // 2
vertices.Add(pos + Vector3.forward); // 3
// First triangle
triangles.Add(lastVertex + 2);
triangles.Add(lastVertex + 1);
triangles.Add(lastVertex);
// Second triangle
triangles.Add(lastVertex);
triangles.Add(lastVertex + 3);
triangles.Add(lastVertex + 2);
}
void generateRightFace(){
lastVertex = vertices.Count;
// Declare vertices
vertices.Add(pos + Vector3.right + Vector3.forward); // 0
vertices.Add(pos + Vector3.one); // 1
vertices.Add(pos + Vector3.right + Vector3.up); // 2
vertices.Add(pos + Vector3.right); // 3
// First triangle
triangles.Add(lastVertex + 2);
triangles.Add(lastVertex + 1);
triangles.Add(lastVertex);
// Second triangle
triangles.Add(lastVertex);
triangles.Add(lastVertex + 3);
triangles.Add(lastVertex + 2);
}
void generateTopFace(){
lastVertex = vertices.Count;
// Declare vertices
vertices.Add(pos + Vector3.up + Vector3.right); // 0
vertices.Add(pos + Vector3.one); // 1
vertices.Add(pos + Vector3.forward + Vector3.up); // 2
vertices.Add(pos + Vector3.up); // 3
// First triangle
triangles.Add(lastVertex + 2);
triangles.Add(lastVertex + 1);
triangles.Add(lastVertex);
// Second triangle
triangles.Add(lastVertex);
triangles.Add(lastVertex + 3);
triangles.Add(lastVertex + 2);
}
void generateBottomFace(){
lastVertex = vertices.Count;
// Declare vertices
vertices.Add(pos); // 0
vertices.Add(pos + Vector3.forward); // 1
vertices.Add(pos + Vector3.forward + Vector3.right); // 2
vertices.Add(pos + Vector3.right); // 3
// First triangle
triangles.Add(lastVertex + 2);
triangles.Add(lastVertex + 1);
triangles.Add(lastVertex);
// Second triangle
triangles.Add(lastVertex);
triangles.Add(lastVertex + 3);
triangles.Add(lastVertex + 2);
}
}
tysm you saved me so much time!
to lazy to actually follow the tutorial XD
I had so much errors and it won’t render tysm
Great content!
Thanks!!
Thanks for a great tutorial and you explained it very well. This is my first time procedurally generating anything and creating a mesh through code and.... it works! Just out of curiosity is there not an easier way to do this and also, surely this would not be good for optimization?
Sadly manually creating each vertice and triangle is the only way, luckily once you create one cube you can create many of them just by looping! Ideally to increase performance you'd use chunks so you don't have to redraw the entire terrain, and instead you only need to redraw a 16x16 block :D
Good tutorial! What are your goals for this series?
Just to create "simple" Minecraft style world generation, at this stage I won't be going over biomes, or ores depends on the response to the first few episodes, however we will be going over terrain, trees and grass as well as caves:)
@@ErenCode Amazing cant wait for second episode
!
This is great. I only have one question: How do I set the triangles to visible? I do not see them in my scene... 🙈
I figured it out myself 😁
haha nice work! :D
where do lo learn to do that ? unity have a lot of things like vector3, recalculate texture bla bla idk how learn that
lots of practice haha, the more you make, the easier it gets :D
why did you make six different functions instead of making a single function that needs an enum face type passed through and use a switch
In this situation, either or would work, no right or wrong answer, I personally prefer to divvy stuff up into functions for my own readability. If the scope of this project was larger then I'd default to switches, but in this case, doesn't matter :D
Nice
Isen't it better to not make new vertices after you make your front and back face since at that point you have all the vertices you need in your vertices list?
Not necessarily... Technically it sounds correct "optimise your mesh by sharing vertices" however, the issue with sharing vertices is that your also sharing normals. Normals are what help our mesh determine how to light each face (basically it does the lighting on a model). If we share vertices, if means that all our faces would share the same lighting data, producing a very gross looking cube XD To get a nice sharp edged cube, we need to create a new vertex for each face. This is a for all models if you want sharp edges, if we were creating a smooth looking terrain then we'd share vertices and normals. Hope this makes sense, its a difficult concept to wrap your head around, procedural mesh generation isn't easy so don't worry if you get stuck! Feel free to join the Discord if you wanna talk about it further :D
Nice walkthrough.. Down to earth..
Sadly you removed the code...
72th
79th?!
39rd
Seventy seconth