Aller au contenu

Première scène

Créer le projet avec Vite, poser une scène, une caméra et un rendu, puis faire tourner un cube qui suit la taille de la fenêtre.

main.js
import * as THREE from "three";

const scene = new THREE.Scene();

const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  100,
);
camera.position.z = 5;

const renderer = new THREE.WebGLRenderer({
  antialias: true,
});
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

const cube = new THREE.Mesh(
  new THREE.BoxGeometry(1, 1, 1),
  new THREE.MeshNormalMaterial(),
);
scene.add(cube);

renderer.setAnimationLoop((time) => {
  cube.rotation.x = time / 1000;
  cube.rotation.y = time / 1500;

  renderer.render(scene, camera);
});

window.addEventListener("resize", () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
});

Créer le projet

On travaille avec Vite : un petit serveur qui recharge la page à chaque enregistrement et qui sait importer three depuis node_modules. Dans un terminal, crée le dossier du projet puis installe les deux paquets :

Terminal
mkdir mon-projet
cd mon-projet
npm init -y
npm install three
npm install --save-dev vite

Ouvre ensuite package.json et ajoute la ligne "type": "module" ainsi qu’un script dev :

package.json
{
  "type": "module",
  "scripts": {
    "dev": "vite"
  }
}

Crée enfin les deux fichiers de la démo, index.html et main.js, à la racine du dossier (leur code complet est juste au-dessus, dans les onglets de la démo), puis lance :

Terminal
npm run dev

Vite affiche une adresse du type http://localhost:5173 : ouvre-la dans le navigateur. Laisse ce terminal ouvert pendant que tu codes.

Le style de index.html enlève la marge du body et passe le canvas en bloc : sans lui, des barres de défilement apparaissent autour de la scène.

Les trois indispensables

Toute scène Three.js repose sur trois objets : la scène (ce qu’on montre), la caméra (d’où on regarde) et le rendu (qui dessine l’image dans un canvas).

La scène

main.js
import * as THREE from "three";

const scene = new THREE.Scene();

La première ligne importe toute la bibliothèque sous le nom THREE. La scène est une boîte vide : on y ajoutera les objets, les lumières et les caméras.

La caméra

main.js
const camera = new THREE.PerspectiveCamera(
  45,
  window.innerWidth / window.innerHeight,
  0.1,
  100,
);
camera.position.z = 5;

Les quatre réglages, dans l’ordre :

  1. l’angle de vue vertical, en degrés (45 donne un rendu naturel) ;
  2. le rapport largeur sur hauteur de l’image, ici celui de la fenêtre ;
  3. la distance minimale à laquelle un objet est encore dessiné ;
  4. la distance maximale.

Tout ce qui est plus près que 0.1 ou plus loin que 100 disparaît. La caméra naît au centre de la scène, comme le cube : on la recule de 5 unités sur l’axe z pour voir le cube de face.

Le rendu

main.js
const renderer = new THREE.WebGLRenderer({
  antialias: true,
});
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(window.innerWidth, window.innerHeight);
document.body.appendChild(renderer.domElement);

antialias lisse les bords des objets. setPixelRatio rend l’image nette sur les écrans Retina, sans dépasser 2 pour ne pas faire chauffer les téléphones. renderer.domElement est le canvas créé par Three.js : on l’ajoute à la page.

Ajouter un objet

Un objet visible s’appelle un mesh : une géométrie (la forme) et un matériau (l’aspect).

main.js
const cube = new THREE.Mesh(
  new THREE.BoxGeometry(1, 1, 1),
  new THREE.MeshNormalMaterial(),
);
scene.add(cube);

MeshNormalMaterial colore chaque face selon son orientation : il n’a pas besoin de lumière, c’est parfait pour vérifier que tout marche. Pour un matériau qui réagit à la lumière, va voir la doc « Lumières, ombres et réglages ».

La boucle d’animation

main.js
renderer.setAnimationLoop((time) => {
  cube.rotation.x = time / 1000;
  cube.rotation.y = time / 1500;

  renderer.render(scene, camera);
});

La fonction passée à setAnimationLoop est appelée à chaque image (60 fois par seconde environ). time donne le nombre de millisecondes depuis le lancement : en le divisant, on obtient une rotation en radians qui avance doucement. Chaque tour de boucle se termine par renderer.render(scene, camera), qui dessine l’image.

Suivre la taille de la fenêtre

main.js
window.addEventListener("resize", () => {
  camera.aspect = window.innerWidth / window.innerHeight;
  camera.updateProjectionMatrix();

  renderer.setSize(window.innerWidth, window.innerHeight);
});

Quand la fenêtre change de taille, on met à jour le rapport de la caméra puis on recalcule sa projection avec updateProjectionMatrix() (sans cet appel, le changement n’est pas pris en compte), et on redimensionne le canvas.

Si l’écran reste noir, ouvre la console du navigateur (clic droit, Inspecter, onglet Console) : une faute de frappe dans un import ou un nom de classe y est toujours signalée.

Pour aller plus loin

  • Remplace BoxGeometry par SphereGeometry(0.7, 32, 16) ou TorusKnotGeometry(0.5, 0.18, 128, 16).
  • Change camera.position.z et regarde ce que ça fait.
  • La documentation de Three.js liste toutes les géométries et tous les matériaux.

Mise à jour : ven. 30 oct. à 17:05