Unity - Génération procédurale de terrain

Bordures

L'auteur

Liens sociaux

Viadeo Twitter Facebook Share on Google+   

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 - Bordures


III. Résumé

Cet épisode a pour but d'éliminer les bordures visibles entre les morceaux de terrain.

IV. Bogue

Au cours de l'épisode précédent, un bogue a été introduit. Celui-ci fait que certains morceaux de terrain ne disparaissent jamais.

Cela est provoqué par la non-mise à jour du tableau terrainChunksVisibileLastUpdate. En effet, la dernière fois, à travers la classe LODMesh, nous avons implémenté une méthode pour ajouter des modèles sans pour autant modifier le fonctionnement du tableau.

Pour corriger cela, le tableau devient statique et est mis à jour dans TerrainChunk::UpdateTerrainChunk() :

EndlessTerrain.cs
Sélectionnez
terrainChunksVisibleLastUpdate.Add (this);

V. Éliminer les bordures

On remarque que si on modifie le décalage (« offset ») de la génération, le terrain change de forme. Aussi, la modification du décalage sur l'axe Y ne déplace pas le terrain dans la bonne direction.

Pour le second problème, il suffit de modifier l'opération dans le fichier Noise.cs :

Noise.cs
Sélectionnez
float offsetY = prng.Next (-100000, 100000) - offset.y;

Ensuite, nous voulons que le décalage soit impacté par la fréquence et l'échelle (« scale ») :

Noise.cs
Sélectionnez
float sampleX = (x-halfWidth + octaveOffsets[i].x) / scale * frequency;
float sampleY = (y-halfHeight + octaveOffsets[i].y) / scale * frequency;

Ce qui corrige la modification du terrain lors du changement du décalage.

Finalement, des bordures apparaissent, car lors de l'utilisation de Mathf.InverseLerp dans le fichier Noise.cs, la valeur maximale passée change pour chaque section de terrain.

La méthode utilisée jusque-là fonctionne très bien pour une génération de terrain finie.

Pour corriger cela, nous allons implémenter un autre mode de calcul pour la normalisation (sans pour autant enlever l'ancienne technique).

Noise.cs
Sélectionnez
for (int y = 0; y < mapHeight; y++) {
    for (int x = 0; x < mapWidth; x++) {
        if (normalizeMode == NormalizeMode.Local) {
            noiseMap [x, y] = Mathf.InverseLerp (minLocalNoiseHeight, maxLocalNoiseHeight, noiseMap [x, y]);
        } else {
            float normalizedHeight = (noiseMap [x, y] + 1) / (maxPossibleHeight/0.9f);
            noiseMap [x, y] = Mathf.Clamp(normalizedHeight,0, int.MaxValue);
        }
    }
}

La valeur maxPossibleHeight est calculée dans la première boucle de la même fonction :

 
Sélectionnez
float amplitude = 1;
float frequency = 1;

for (int i = 0; i < octaves; i++) {
    float offsetX = prng.Next (-100000, 100000) + offset.x;
    float offsetY = prng.Next (-100000, 100000) - offset.y;
    octaveOffsets [i] = new Vector2 (offsetX, offsetY);

    maxPossibleHeight += amplitude;
    amplitude *= persistance;
}

Par ces modifications, il est possible d'avoir des hauteurs dépassant 1. Par conséquent, le code de coloration est modifié pour s'assurer que l'intégralité du terrain aura une couleur appropriée :

MapGenerator.cs
Sélectionnez
Color[] colourMap = new Color[mapChunkSize * mapChunkSize];
for (int y = 0; y < mapChunkSize; y++) {
    for (int x = 0; x < mapChunkSize; x++) {
        float currentHeight = noiseMap [x, y];
        for (int i = 0; i < regions.Length; i++) {
            if (currentHeight >= regions [i].height) {
                colourMap [y * mapChunkSize + x] = regions [i].colour;
            } else {
                break;
            }
        }
    }
}

Il reste deux problèmes après ces modifications :

  • les normales ne sont pas correctes sur les bordures ;
  • la jointure entre deux niveaux de détail n'est pas parfaite.

Le second point est négligeable, car le défaut n'apparaît que si le joueur est loin et ne sera donc pas visible.

VI. Dimensionnement

Afin de rendre le terrain à des dimensions adéquates par rapport au joueur, nous ajoutons un facteur de redimensionnement (« scale ») prenant effet dans la classe TerrainChunk :

EndlessTerrain.cs
Sélectionnez
meshObject.transform.position = positionV3 * scale;
meshObject.transform.parent = parent;
meshObject.transform.localScale = Vector3.one * scale;

VII. Commenter

Vous pouvez commenter et donner vos avis dans la discussion associée sur le forum.

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Copyright © 2017 Unity Technologies. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.