
Simuler le système Terre-Lune en HTML et JavaScript (1/2)
Lors d’une visite au CNES, mon attention a été attirée par des écrans affichant une constellation de satellites en orbite autour de la Terre. J’ai appris qu’il s’agissait d’une application Web simulant la position des satellites en temps réel.
Intrigué par cette application, je me suis demandé à quel point un tel projet peut-il être complexe. Pour répondre à cette interrogation, j’ai décidé de relever un défi personnel : développer une simulation simplifiée de la Lune, satellite naturel de la Terre, dans son mouvement orbital.
Découvrons ensemble les défis techniques et le temps requis pour simuler le système Terre-Lune en HTML et JavaScript.
Trouver des pistes pour simuler le système Terre-Lune
Lorsqu’il s’agit de développer un projet ambitieux, comme simuler le système Terre-Lune, repartir de zéro est rarement une bonne idée. Avec un peu de recherche, il est très probable que des outils ou des API déjà existants puissent répondre partiellement, voire complètement, à nos besoins. Pourquoi recréer une librairie de rendu 3D quand des solutions robustes sont à portée de main ?
Mes premières recherches en ligne ont rapidement fait émerger plusieurs options intéressantes :
- Exploiter la balise HTML
<canvas>
- S’appuyer sur la librairie Three.js
- Adopter un moteur de jeu compatible avec le Web
La balise HTML <canvas>
Cette balise permet d’afficher une surface de dessin dans une page Web, à laquelle on peut associer un contexte 3D via l’API JavaScript WebGL. Bien que cette API soit extrêmement puissante et riche, elle reste bas niveau, ce qui signifie qu’obtenir un rendu satisfaisant nécessite d’écrire beaucoup de code et de gérer manuellement de nombreux détails.
Utiliser la librairie Three.js
La librairie Three.js, qui utilise également <canvas>
, simplifie considérablement l’utilisation de WebGL. Grâce à elle, on peut manipuler une scène 3D en organisant indépendamment ses composants (caméra, lumière, objets 3D, textures, etc.). C’est un gain de temps considérable pour structurer et gérer une simulation complexe.
Utiliser un moteur de jeu compatible avec le Web
Les moteurs de jeu comme Unity ou Godot offrent des environnements puissants pour développer des scènes en trois dimensions. Cependant, ils ne permettent pas de coder directement en JavaScript et incluent souvent bien plus de fonctionnalités que nécessaire pour un projet de cette envergure.
Le meilleur compromis : la librairie Globe.GL
Enfin, une découverte a particulièrement retenu mon attention : la librairie Globe.GL. Construite sur Three.js, elle propose une API JavaScript orientée spécifiquement vers la visualisation de la Terre. Elle offre ainsi un excellent compromis entre simplicité d’utilisation et puissance. Voici un exemple illustrant ses capacités :
Simuler la Terre en 3D avec Globe.GL
Commençons par nous familiariser avec Globe.GL en adaptant le code source des exemples proposés dans la documentation. L’objectif ici est simple : créer une page HTML capable d’afficher une représentation 3D de la Terre dans l’espace. Voici le code de base pour l’initialisation :
<!-- /index.html -->
<!doctype html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Système Terre-Lune</title>
<link rel="stylesheet" href="lib/style.css">
</head>
<body>
<div id="view"></div>
<script src="https://unpkg.com/globe.gl"></script>
<script src="lib/script.js"></script>
</body>
</html>
L’élément clé de ce fichier est la balise <div>
avec l’id view
, qui accueillera le canvas
généré par la librairie Globe.GL.
Ensuite, ajoutons une feuille de styles minimaliste :
/* /lib/style.css */
html,
body {
margin: 0;
padding: 0;
}
Ces styles suppriment les marges par défaut des navigateurs pour permettre à notre canvas
de remplir toute la fenêtre.
Passons maintenant au script JavaScript qui configure la scène et affiche la Terre :
// /lib/script.js
// Configuration de la scene et de la Terre
const world = Globe()
(document.getElementById('view'))
.globeImageUrl('https://unpkg.com/three-globe/example/img/earth-blue-marble.jpg')
.bumpImageUrl('https://unpkg.com/three-globe/example/img/earth-topology.png')
.backgroundImageUrl('https://unpkg.com/three-globe/example/img/night-sky.png')
;
// Ajout d'un event listener pour redéfinir la taille de la view automatiquement
window.addEventListener('resize', (_) => {
world.width(window.innerWidth);
world.height(window.innerHeight);
}); // <1>
Cette instruction, bien que facultative, garantit que le canvas
s’ajuste automatiquement lorsque la fenêtre du navigateur est redimensionnée.
Avec seulement quelques lignes de code, la scène est prête à afficher une Terre réaliste dans un fond étoilé :
Ajouter la Lune à la scène 3D
Après avoir configuré la Terre, ajoutons maintenant la Lune à notre scène 3D. Pour cela, nous allons suivre ces étapes :
- Créer et texturer la Lune à l’aide de la librairie Three.js.
- Utiliser le système de Custom Layers de Globe.GL pour l’intégrer et la positionner dans la scène.
Chargement des textures avec Three.js
La documentation de Globe.GL recommande d’importer Three.js via un CDN. Nous utiliserons le fichier disponible à l’adresse suivante :https://unpkg.com/three/build/three.module.js
.
Ce fichier est un module JavaScript. Nous devons donc ajuster la déclaration de notre script dans le fichier HTML pour activer la prise en charge des modules :
// /index.html
// ...
<script src="https://unpkg.com/globe.gl"></script>
- <script src="lib/script.js"></script>
+ <script src="lib/script.js" type="module"></script>
</body>
</html>
Ensuite, mettons à jour notre script pour charger les textures nécessaires à la création de la Lune :
// /lib/script.js
+import {
+ TextureLoader,
+} from 'https://unpkg.com/three/build/three.module.js';
+
+
+// Chargement des ressources Three.js
+const LOADER = new TextureLoader();
+
+const MOON_TEXTURE = LOADER
+ .load('https://raw.githubusercontent.com/vasturiano/globe.gl/master/example/moon-landing-sites/lunar_bumpmap.jpg');
+const BUMPMOON_TEXTURE = LOADER
+ .load('https://raw.githubusercontent.com/vasturiano/globe.gl/master/example/moon-landing-sites/lunar_bumpmap.jpg');
+
+
// Configuration de la scene et de la Terre
const world = Globe()
// ...
La classe TextureLoader
permet de charger des textures 3D directement depuis une URL. Ici, nous utilisons des ressources disponibles dans le dépôt GitHub de Globe.GL.
Déclaration des données personnalisées
Pour ajouter des objets personnalisés à la scène, Globe.GL propose la fonction customLayerData
, qui attend un tableau contenant les données nécessaires. Voici comment déclarer les informations pour la Lune :
// /lib/script.js
// ...
+// Constantes <1>
+const EARTH_RADIUS = 6371;
+const MOON_RADIUS = 1737.4;
+
+
// Configuration de la scene et de la Terre
const world = Globe()
(document.getElementById('view'))
.globeImageUrl('https://unpkg.com/three-globe/example/img/earth-blue-marble.jpg')
.bumpImageUrl('https://unpkg.com/three-globe/example/img/earth-topology.png')
.backgroundImageUrl('https://unpkg.com/three-globe/example/img/night-sky.png')
+ .customLayerData([{
+ lat: -5, <2>
+ lng: 277, <2>
+ alt: 2.5, <3>
+ radius: MOON_RADIUS / EARTH_RADIUS, <4>
+ textures: { <4>
+ map: MOON_TEXTURE,
+ displacementMap: BUMPMOON_TEXTURE,
+ }
+ }])
;
// ...
La déclaration de ces constantes nous permet de calculer la taille de la Lune par rapport à la Terre.
Ces valeurs sont issues des données historiques de l’orbite lunaire.
L’altitude n’est pas à l’échelle, sinon elle serait hors champ de la caméra.
Les clés radius
et textures
nous sont utiles pour l’instanciation du Mesh
de la Lune.
Instanciation de la Lune
Pour créer et positionner la Lune dans la scène, Globe.GL propose deux fonctions :
customThreeObject
: crée l’objet 3D à partir des données fournies.customThreeObjectUpdate
: met à jour la position de l’objet dans la scène.
Voici comment les utiliser pour ajouter la Lune :
// /lib/script.js
import {
TextureLoader,
+ Mesh,
+ SphereGeometry,
+ MeshStandardMaterial,
} from 'https://unpkg.com/three/build/three.module.js';
// ...
displacementMap: BUMPMOON_TEXTURE,
}
}])
+ .customThreeObject(moon => new Mesh(
+ new SphereGeometry(world.getGlobeRadius() * moon.radius),
+ new MeshStandardMaterial(moon.textures),
+ )) <1>
+ .customThreeObjectUpdate((obj, moon) => {
+ Object.assign(obj.position, world.getCoords(moon.lat, moon.lng, moon.alt));
+ }) <2>
+ .pointOfView({ altitude: 7 })
;
// ...
La fonction customThreeObject
prend en paramètre une fonction permettant de créer l’objet 3D à partir d’une donnée du data layer.
La fonction customThreeObjectUpdate
prend en paramètre une fonction permettant de mettre à jour la position de l’objet 3D créé par customThreeObject
.
Ces fonctions permettent d’instancier un objet de type sphère (SphereGeometry
) pour la Lune, auquel sont appliquées les deux textures précédemment téléchargées :
- Une texture d’image (
map
) pour afficher la surface lunaire. - Une texture de relief (
displacementMap
) pour modéliser les cratères et donner du volume.
La fonction customThreeObjectUpdate
place ensuite la Lune à ses coordonnées GPS. Bien que la position soit statique ici, elle pourrait être animée pour simuler une orbite.
En suivant ces étapes, vous avez maintenant une scène 3D affichant la Terre et la Lune, prêtes à être animées ou enrichies avec d’autres objets !
Animer la rotation de la Lune autour de la Terre
Nous avons vu comment ajouter la Lune à notre scène 3D, mais le véritable défi consiste à simuler son mouvement orbital. Heureusement, la fonction customThreeObjectUpdate
est conçue pour cela : elle peut mettre à jour la position de la Lune à chaque rafraîchissement de l’image.
Pour animer la Lune, il suffirait de lui fournir une série de coordonnées GPS correspondant à sa trajectoire orbitale. Ces données permettraient de recalculer dynamiquement sa position dans la scène, créant ainsi l’illusion du mouvement.
Cependant, n’ayant pas accès à un historique fiable des coordonnées GPS de la Lune, notre modèle restera statique pour l’instant. Cette limitation ne change rien à notre objectif final : donner vie à une simulation réaliste du système Terre-Lune.
Pour y parvenir, nous explorerons des solutions alternatives dans un prochain article. En attendant, le travail accompli ici constitue déjà une base solide pour aborder l’animation !