Welkom terug bij deel 2 van onze serie: “Maak een Minecraft-achtig Voxel wereld game in Unity”! In deel 1 hebben we ons Unity-project opgezet. Vandaag maken we ons eerste 3D-object: de bouwsteen van onze voxel wereld.

Wat is een 3D-object in Unity?

In Unity bestaat een 3D-object meestal uit een Mesh, dat wordt opgebouwd uit:

  • Vertices (hoekpunten/Vertex)
  • Triangles (vlakken/Faces)
  • Eventueel UV-coördinaten, normals en meer

Voor een voxel-game zoals Minecraft bouwen we elk blok handmatig op uit triangles. Unity’s Mesh-klasse maakt dit super simpel voor ons.

Waarom gebruiken we driehoeken?

Unity (en eigenlijk de hele 3D-wereld) gebruikt driehoeken omdat:

  • Ze altijd vlak zijn (dus geen vertekeningen)
  • Ze snel en efficiënt worden verwerkt door de GPU

Elke zijde van een kubus wordt gemaakt uit 2 driehoeken → een blok heeft dus 6 zijdes × 2 driehoeken = 12 driehoeken.

Een blok maken met code in Unity

Nu we weten dat een blok uit 6 zijdes bestaat en elke zeide weer bestaat uit 2 driehoeken, weten we dat we in totaal 12 driehoeken moeten maken.
Om onze eerste driehoek te kunnen maken hebben we een script nodig, deze kan je aanmaken met de volgende stappen:

  1. Maak een folder met de naam Scripts
  2. Maak een nieuw MonoBehaviour bestand aan met de naam Triangle : Create → Scripting → MonoBehaviour Script

Nu we onze eerste script hebben gemaakt kunnen we deze openen met een C# Editor zoals Visual Studio of Rider. Onze script zal er dan als volgt uitzien:

using UnityEngine;

public class Triangle : MonoBehaviour
{
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
{

}

// Update is called once per frame
void Update()
{

}
}

Om te kunnen beginnen met onze eerste driehoek hebben we een aantal Componenten nodig zoal een MeshFilter en een MeshRenderer. Om te zorgen dat deze altijd toegewezen zijn aan het GameObject waar onze Triangle script staat ingesteld kunnen we de volgende regels toevoegen boven onze class:

[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class Triangle : MonoBehaviour
{
    // Standaard code van Unity
}

Vervolgens defineren we deze componenten als variabelen en zorgen dat deze refereren naar de componenten op het huidige GameObject.

    private MeshFilter meshFilter;
    private MeshRenderer meshRenderer;
    
    void Start()
    {
        meshFilter = GetComponent<MeshFilter>();
        meshRenderer = GetComponent<MeshRenderer>();
    }

Nu we de basis van onze Triangle script hebben gemaakt kunnen we beginnen met het maken van onze eerste Triangle. In de functie Generate zullen we een nieuwe Mesh aanmaken en deze vullen met 3 posities. Deze 3 posities zijn de hoeken van de driehoek.
Als we naar onderstaande driehoek kijken dan heeft de driehoek 3 punten, deze driepunten kunnen we coordinaten geven in 2 dimensies, de X-as en de Y-as.

Driehoek met 3 punten

De coordinaten voor deze driehoek zijn als volgt:

Hoek 1: X-as: 0 Y-as: 0
Hoek 2: X-as: 0 Y-as: 1
Hoek 3: X-as: 1 Y-as: 0

Nu we de 2 dimensie coordinaten weten kunnen we een 3 dementie toevoegen namelijk de Z-as deze is voor een 3 hoek niet belangrijk maar later voor een 3D blok wel heel belangrijk.
Deze Z-as kunnen we voor de driehoek op 0 houden. Deze coordinaten moeten we nu in een Array van Vector3’s stoppen:

    Vector3[] vertices = new[]
    {
        new Vector3(0, 0, 0),
        new Vector3(0, 1, 0),
        new Vector3(1, 0, 0),
    };

Nu we een Array hebben met deze coordinaten kunnen we een Mesh aanmaken en deze vertices in de Mesh zetten:

    Mesh mesh = new Mesh();
mesh.vertices = vertices;

Nu we de Vertices hebben kunnen we de Triangle maken door de index van onze vertices op te geven in een Array van integers. Dit zijn voor ons dus index 0, 1 en 2

    int[] triangles = new[]
    {
        0, 1, 2,
    };

    mesh.triangles = triangles;

Om de triangle nu zichtbaar te maken moeten we de normals berekenen en de mesh in de MeshFilter zetten, ook moeten we niet vergeten om de Generate functie aan te roepen in Start:

    mesh.RecalculateNormals();
    meshFilter.mesh = mesh;

Dan zou het script er uit moeten zien als:

using UnityEngine;

[RequireComponent(typeof(MeshFilter))]
[RequireComponent(typeof(MeshRenderer))]
public class Triangle : MonoBehaviour
{
    private MeshFilter meshFilter;
    private MeshRenderer meshRenderer;
    
    void Start()
    {
        meshFilter = GetComponent<MeshFilter>();
        meshRenderer = GetComponent<MeshRenderer>();
        Generate();
    }

    void Generate()
    {
        Vector3[] vertices = new[]
        {
            new Vector3(0, 0, 0),
            new Vector3(0, 1, 0),
            new Vector3(1, 0, 0),
        };

        int[] triangles = new[]
        {
            0, 1, 2,
        };
        
        Mesh mesh = new Mesh();
        mesh.vertices = vertices;
        mesh.triangles = triangles;
        mesh.RecalculateNormals();
        meshFilter.mesh = mesh;
        
    }

    // Update is called once per frame
    void Update()
    {
        
    }
}

Nu kunnen we in Unity een GameObject maken met de naam Triangle en het script Triangle toevoegen als component op het GameObject.

Unity window

Als we nu op Play drukken dan zien we een roze driehoek:

Wat hebben we geleerd

  • Hoe je handmatig een 3D-object maakt (een driehoek)
  • Hoe Unity’s Mesh werkt
  • Dat elke blok uit 12 driehoeken bestaan

Volgende stap: Onze eerste blok

In deel 3 gaan we onze eerste blok genereren met behulp van meerdere driehoeken.
Klaar om onze eerste klok to maken? Tot de volgende keer!