Avec l’avènement du HTML5 et la montée en puissance de WebGL, les applications 3D ont désormais leur place sur le web. Ubisoft, Microsoft, Google et d’autres grands noms de l’informatique placent beaucoup d’espoir dans WebGL et chaque jour voit la naissance de nouvelles expérimentations, voire d’un nouveau projet dans le domaine de la 3D web. Si vous avez déjà tenté l’expérience WebGL, vous vous êtes sûrement cassé les dents sur la complexité de cette technologie, c’est là qu’intervient BabylonJS.
BabylonJS est une bibliothèque JavaScript qui agit comme une surcouche à WebGL. Les programmes 3D sont souvent très verbeux, à l’image des programmes OpenGL ou Direct3D, car l’on discute directement avec le GPU. BabylonJS va nous faciliter la vie en encapsulant cette partie verbeuse dans un ensemble de classes et de méthodes. La bibliothèque a été créée par David Catuhe et David Rousset (deux ingénieurs spécialisés dans le web chez Microsoft) et présente des avantages indéniables pour le développement d’applications 3D dans le navigateur. Maintenant que j’ai piqué votre curiosité, je vous invite à créer votre première scène 3D.
Pour profiter de certaines fonctionnalités de BabylonJS, il faudra placer votre code sur un serveur web. Un serveur Apache en local fera parfaitement l’affaire.
Nous allons faire simple pour cette première scène : un sol avec quelques cubes, quelques textures et la possibilité de s’y déplacer. Pour commencer, préparez l’architecture suivante :
.
+-- index.html
+-- js/
| +-- app.js
+-- css/
| +-- global.css
+-- img/
Le fichier index.html
sera initialisé de la manière suivante
(ce fichier ne changera pas lors de la suite du développement) :
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html" charset="utf-8" />
<title>Babylon - My First 3D Scene</title>
<!-- Pour simplifier, nous obtenons BabylonJS via un CDN -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/babylonjs/2.4.1/babylon.js"></script>
<script src="js/app.js"></script>
<link href="css/global.css" rel="stylesheet"/>
</head>
<body>
<canvas id="renderCanvas"></canvas>
</body>
</html>
Vous noterez la présence de la balise canvas
, c’est grâce à cette dernière,
entre autres, que ce genre de programme est possible. Nous passons donc par elle
pour effectuer le rendu de l’application.
Le fichier global.css
est là pour faire en sorte que notre application
3D occupe toute la place allouée au navigateur.
html, body {
overflow: hidden;
width : 100%;
height : 100%;
margin : 0;
padding : 0;
}
#renderCanvas {
width : 100%;
height : 100%;
}
C’est maintenant dans notre fichier app.js
que tout va se passer.
Premièrement, nous devons attendre que le DOM soit parfaitement chargé avant
de faire quoi que ce soit :
window.addEventListener('DOMContentLoaded', function() {
// ...
});
Maintenant, nous pouvons initialiser le moteur 3D. Ceci se fait en deux temps :
on récupère le canvas
puis on crée une instance du moteur en lui passant
le canvas
en paramètre.
const canvas = document.getElementById('renderCanvas');
const engine = new BABYLON.Engine(canvas, true); // true est là pour activer/désactiver l'anti-aliasing
Le moteur est prêt, passons à la construction de la scène qui sera implémentée dans une fonction dédiée :
const createScene = function() {
// ...
return scene;
};
Une application 3D est composée de trois éléments fondamentaux :
Commençons par la création du conteneur : la scène.
let scene = new BABYLON.Scene(engine);
scene.gravity = new BABYLON.Vector3(0, -9.81, 0);
scene.collisionsEnabled = true;
Cela vous donne déjà un aperçu de la simplicité de BabylonJS, la création de la
scène est un simple appel au constructeur BABYLON.Scene()
qui prend le
moteur en paramètre. Pour appliquer une gravité semblable à la gravité
terrestre, on déclare une direction négative sur l’axe Y via un Vector3
.
La dernière ligne va activer le moteur de collisions pour notre scène. Cette
dernière prête, nous pouvons lui ajouter une caméra.
let camera = new BABYLON.FreeCamera("MainCamera", new BABYLON.Vector3(0, 2.5, 5), scene);
camera.applyGravity = true;
camera.checkCollisions = true;
camera.speed = 0.5;
camera.angularSensibility = 1000;
camera.keysUp = [90]; // Z
camera.keysDown = [83]; // S
camera.keysLeft = [81]; // Q
camera.keysRight = [68]; // D
scene.activeCamera.attachControl(canvas);
Ce code représente également un bon exemple de simplicité, si vous êtes familier avec JavaScript ou la programmation orientée objet en général, tout ceci devrait être limpide. Après avoir instancié une caméra, nous lui indiquons qu’elle est sensible à la gravité ainsi qu’aux collisions. Nous définissons sa vitesse de déplacement, la sensibilité de la souris puis nous mappons les touches de contrôle sur les classiques du jeu vidéo : ZQSD. La dernière ligne permet d’appliquer tous ces contrôles afin que l’utilisateur puisse en profiter.
Si vous avez été attentif, vous avez dû vous rendre compte qu’il ne nous manque qu’un seul élément : la lumière.
let light = new BABYLON.PointLight("DirLight", new BABYLON.Vector3(0, 10, 0), scene);
light.diffuse = new BABYLON.Color3(1, 1, 1);
light.specular = new BABYLON.Color3(0.6, 0.6, 0.6);
light.intensity = 1.5;
On distinguera plusieurs types de lumière, celle qui nous intéresse ici est la
PointLight
qui va simuler une source lumineuse similaire à celle du soleil.
On définit une couleur pour les propriétés diffuse
et specular
afin d’avoir
quelques reflets. On termine avec un ajustement de l’intensité de la lumière.
Nos trois éléments sont donc en place. Avant de pouvoir lancer l’application,
ajoutez les instructions suivantes après la méthode createScene
:
const scene = createScene();
engine.runRenderLoop(function() {
scene.render();
});
window.addEventListener('resize', function() {
engine.resize();
});
Nous avons donc une renderLoop
chargée d’exécuter notre code le plus de
fois possible par seconde, le Graal étant les 16ms entre chaque frame (le
fameux 60 FPS). Vous pouvez maintenant lancer l’application dans votre navigateur.
Je vous recommande Chrome et Edge qui sont les plus adaptés pour cette bibliothèque
javascript (BabylonJS étant principalement testé avec Chackra et V8).
Normalement, vous devriez voir une scène… vide. En effet pour l’instant
vous n’avez placé aucun objet 3D dans votre scène, uniquement les fondations.
Continuons en ajoutant un sol sur lequel nous pourrons nous déplacer.
let ground = BABYLON.Mesh.CreatePlane("ground", 50, scene);
ground.rotation.x = Math.PI / 2;
ground.checkCollisions = true;
On instancie un objet Plane
que l’on va orienter de manière à simuler
un sol. N’oublions pas de le rendre sensible aux collisions, le cas échéant
notre caméra passera à travers. Si vous relancez votre application maintenant,
vous pourrez désormais vous balader dans votre premier monde en 3D.
Ce niveau semble bien vide pour l’instant, ajoutons quelques caisses :
const cubeSize = 2;
for (var i = 0; i < 4; i++) {
let box = BABYLON.Mesh.CreateBox("box", cubeSize, scene);
const randomX = Math.floor(Math.random() * 31) - 15;
const randomZ = Math.floor(Math.random() * 31) - 15;
box.position = new BABYLON.Vector3(randomX, cubeSize / 2, randomZ);
box.checkCollisions = true;
}
Et voici les premiers éléments de votre nouveau monde créé en 3D. Pour finaliser, je vous invite à ajouter quelques textures. Pour cela, il vous faut d’abord sélectionner des images. Un tour rapide sur votre navigateur favori et vous devriez trouver une image pour le sol et une pour les caisses.
En manque d’inspiration ? Faites donc un tour sur OpenGameArt.
Commençons par appliquer une texture au sol :
// La création de notre sol
let ground = BABYLON.Mesh.CreatePlane("ground", 50, scene);
ground.rotation.x = Math.PI / 2;
ground.checkCollisions = true
ground.material = new BABYLON.StandardMaterial("gMaterial", scene);
// Ajout d'une texture (on adapte sa taille pour un effet mosaïque).
ground.material.diffuseTexture = new BABYLON.Texture("img/ground.jpg", scene);
ground.material.diffuseTexture.uScale = 30;
ground.material.diffuseTexture.vScale = 30;
Pour les caisses, nous allons créer un objet Material
commun à chaque box :
let boxMaterial = new BABYLON.StandardMaterial("bMaterial", scene);
boxMaterial.diffuseTexture = new BABYLON.Texture("img/box.jpg", scene);
Puis, nous retournons dans la boucle de création de boxes pour appliquer la texture :
for (var i = 0; i < 4; i++) {
// ...
box.material = boxMaterial;
}
Vous venez de faire vos premiers pas dans le monde de la 3D web et je vous en félicite ! Si vous poursuivez votre apprentissage, vous découvrirez rapidement que BabylonJS a beaucoup à offrir et est capable de réduire des notions complexes à de simples appels de méthodes. Si vous souhaitez avoir un aperçu des cas d’utilisation du moteur, vous pouvez consulter un showcase sur le site officiel.
L’équipe Synbioz. Libres d’être ensemble.