Créer un terrain vallonné avec Three.js
La première chose que je veux faire pour le projet, c’est le sol : je veux un terrain vallonné, avec du relief. Je choisis de le générer directement avec Three.js plutôt que de le modéliser dans Blender.
L’idée est de créer une surface plane avec une PlaneGeometry, puis de modifier les positions de ses vertices via son BufferAttribute attributes.position pour obtenir du relief.
const geometry = new THREE.PlaneGeometry(32, 32, 64, 64);
geometry.rotateX(-Math.PI / 2); // on positionne la surface à plat
const material = new THREE.MeshStandardMaterial({
color: "#704a39",
flatShading: true, // style lowpoly
});
const mesh = new THREE.Mesh(this.geometry, this.material);
this.scene.add(mesh);
Du bruit pour un relief naturel
Pour créer des reliefs, l’idée est d’onduler la surface sur plusieurs octaves à partir d’un bruit, pour un rendu plus naturel. J’utilise la fonction createNoise2D pour générer un bruit simplex en 2 dimensions. Contrairement à un aléatoire pur, le bruit varie de façon douce et continue : deux points voisins ont des valeurs proches, ce qui donne un relief lisse et non chaotique.
import { createNoise2D } from "simplex-noise";
this.noise2D = createNoise2D(alea(this.params.seed));
Le paramètre seed me permet de tester plusieurs bruits différents, et de conserver, grâce à cette seed, le terrain généré qui me plaît.
On définit ensuite nos octaves pour faire onduler le terrain (j’ai testé les valeurs à l’aide des tweaks jusqu’à obtenir ce qui me convenait).
this.params = {
octaves: [
{ frequency: 0.091, amplitude: 0.65 }, // grandes collines
{ frequency: 0.067, amplitude: 0.6 }, // bosses moyennes
{ frequency: 0.018, amplitude: 0.3 }, // petits détails
],
};
Appliquer le relief à la géométrie
Enfin, on modifie les positions du BufferAttribute attributes.position en combinant les octaves et le bruit :
const pos = geometry.attributes.position;
for (let i = 0; i < pos.count; i++) {
const x = pos.getX(i);
const z = pos.getZ(i);
// On combine plusieurs "octaves" de bruit pour du relief riche
let height = 0;
for (const octave of this.params.octaves) {
height +=
this.noise2D(x * octave.frequency, z * octave.frequency) *
octave.amplitude;
}
pos.setY(i, height);
}
pos.needsUpdate = true;
this.geometry.computeVertexNormals(); // Pour que les normales tiennent compte des modifications
}
Voici le résultat :
N’hésitez pas à jouer avec les tweaks pour changer le bruit ou les valeurs des octaves.
J’en ai donc fini avec la première étape de mon projet : la création d’un terrain vallonné. La prochaine étape sera d’ajouter de l’herbe sur ce terrain !