I. Introduction▲
Cette série explique comment générer de manière procédurale des continents dans Unity.
		Vous pouvez retrouver les autres épisodes de cette série dans le sommaire dédié.
II. Vidéo▲
Unity - Génération procédurale de terrain - Modèle 3D du terrain
III. Résumé▲
Dans cet épisode, vous allez créer un modèle 3D à partir de la carte des hauteurs afin de créer le relief de votre terrain.
III-A. Implémentation▲
III-A-1. Explications de la méthode▲
Le modèle est créé à partir de triangles. Pour constituer les triangles, vous devez passer à Unity une liste (tableau à une dimension) des sommets que vous souhaitez afficher.
Si vous avez un tableau de neuf cases comme suit :
0 1 2
3 4 5
6 7 8Le premier triangle sera :
0, 4, 3L'ordre des sommets est important. En effet, l'ordre par défaut est un ordre allant dans le sens des aiguilles d'une montre. En réalité, cette convention est utilisée par la carte graphique afin de connaître quelle est la face avant et la face arrière. Aussi, si vous utilisez la suppression de la face arrière (« backface culling »), l'ordre est d'autant plus important à suivre, sans quoi vous ne verrez pas votre triangle.
Le deuxième triangle sera :
4, 0, 1Et ainsi de suite.
Aussi, vous devez être en mesure de calculer :
- le nombre de sommets : largeur * hauteur ;
 - le nombre de triangles : (largeur -1) * (hauteur -1) * 6.
 
III-A-2. Script▲
La création du modèle de terrain se fait dans un nouveau script, appelé MeshGenerator.cs :
using UnityEngine;
using System.Collections;
public static class MeshGenerator {
    public static MeshData GenerateTerrainMesh(float[,] heightMap) {
        int width = heightMap.GetLength (0);
        int height = heightMap.GetLength (1);
        // Permet de centrer le modèle
        float topLeftX = (width - 1) / -2f;
        float topLeftZ = (height - 1) / 2f;
        MeshData meshData = new MeshData (width, height);
        int vertexIndex = 0;
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                meshData.vertices [vertexIndex] = new Vector3 (topLeftX + x, heightMap [x, y], topLeftZ - y);
                meshData.uvs [vertexIndex] = new Vector2 (x / (float)width, y / (float)height);
                if (x < width - 1 && y < height - 1) {
                    meshData.AddTriangle (vertexIndex, vertexIndex + width + 1, vertexIndex + width);
                    meshData.AddTriangle (vertexIndex + width + 1, vertexIndex, vertexIndex + 1);
                }
                vertexIndex++;
            }
        }
        return meshData;
    }
}Évidemment, la fonction de génération GenerateTerrainMesh() prend en paramètre la carte des hauteurs. Elle produit les sommets du terrain ainsi que les triangles pour l'affichage.
La fonction génère aussi les coordonnées de texture pour le terrain, ici appelés uvs. Leurs valeurs sont comprises entre 0 et 1.
Pour des soucis de simplicité, une classe MeshData est créée afin de regrouper les sommets et les triangles :
public class MeshData {
    public Vector3[] vertices;
    public int[] triangles;
    public Vector2[] uvs;
    int triangleIndex;
    public MeshData(int meshWidth, int meshHeight) {
        vertices = new Vector3[meshWidth * meshHeight];
        uvs = new Vector2[meshWidth * meshHeight];
        triangles = new int[(meshWidth-1)*(meshHeight-1)*6];
    }
    public void AddTriangle(int a, int b, int c) {
        triangles [triangleIndex] = a;
        triangles [triangleIndex + 1] = b;
        triangles [triangleIndex + 2] = c;
        triangleIndex += 3;
    }
    public Mesh CreateMesh() {
        Mesh mesh = new Mesh ();
        mesh.vertices = vertices;
        mesh.triangles = triangles;
        mesh.uv = uvs;
        mesh.RecalculateNormals ();
        return mesh;
    }
}Celle-ci permet de facilement créer les tableaux qui seront passés à Unity, ajouter des triangles et de créer le modèle à partir de ceux-ci.
C'est un MeshData qui est retourné par la fonction GenerateTerrainMesh() afin de permettre l'implémentation du multithread par la suite et ainsi permettre de ne pas bloquer le jeu.
		Aussi, il n'est pas possible de créer un modèle (Mesh) au sein d'un thread et de l'utiliser dans un autre.
III-A-3. Affichage▲
Pour permettre l'affichage du modèle, nous complétons l'énumération DrawMode et ajoutons une fonction DrawMesh() :
public void DrawMesh(MeshData meshData, Texture2D texture) {
    meshFilter.sharedMesh = meshData.CreateMesh ();
    meshRenderer.sharedMaterial.mainTexture = texture;
}Son appel, réalisé dans le fichier MapGenerator.cs est réalisé comme suit :
display.DrawMesh (MeshGenerator.GenerateTerrainMesh (noiseMap), TextureGenerator.TextureFromColourMap (colourMap, mapWidth, mapHeight));Actuellement, il n'est pas possible d'afficher un modèle trop grand. Cela sera corrigé dans un prochain épisode, dans lequel la carte sera générée par morceau.
IV. Commenter▲
Vous pouvez commenter et donner vos avis dans la discussion associée sur le forum.



