Lumières, ombres et réglages
Éclairer un matériau réaliste, projeter des ombres, tourner autour de la scène avec OrbitControls et régler les valeurs en direct avec lil-gui.
import * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import GUI from "lil-gui";
const scene = new THREE.Scene();
scene.background = new THREE.Color("#038a03");
const camera = new THREE.PerspectiveCamera(
45,
window.innerWidth / window.innerHeight,
0.1,
100,
);
camera.position.set(4, 3, 6);
const cube = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshStandardMaterial({
color: "#ff0000",
}),
);
cube.position.y = 1;
cube.castShadow = true;
const floor = new THREE.Mesh(
new THREE.PlaneGeometry(10, 10),
new THREE.MeshStandardMaterial({ color: "#ffffff" }),
);
floor.rotation.x = -Math.PI / 2;
floor.receiveShadow = true;
scene.add(cube, floor);
const ambientLight = new THREE.AmbientLight("#ffffff", 0.4);
scene.add(ambientLight);
const sunLight = new THREE.DirectionalLight("#ffffff", 2);
sunLight.position.set(3, 5, 2);
sunLight.castShadow = true;
scene.add(sunLight);
const sunHelper = new THREE.DirectionalLightHelper(sunLight);
scene.add(sunHelper, new THREE.AxesHelper(2));
const renderer = new THREE.WebGLRenderer({
antialias: true,
});
renderer.setPixelRatio(Math.min(window.devicePixelRatio, 2));
renderer.setSize(window.innerWidth, window.innerHeight);
renderer.shadowMap.enabled = true;
document.body.appendChild(renderer.domElement);
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
const gui = new GUI();
gui.add(sunLight, "intensity", 0, 5).name("soleil");
gui.addColor(cube.material, "color").name("couleur du cube");
renderer.setAnimationLoop(() => {
controls.update();
renderer.render(scene, camera);
});
window.addEventListener("resize", () => {
camera.aspect = window.innerWidth / window.innerHeight;
camera.updateProjectionMatrix();
renderer.setSize(window.innerWidth, window.innerHeight);
});
Ce qu’on ajoute
Par rapport à la « Première scène », cette démo apporte quatre nouveautés : un matériau qui réagit à la lumière, deux lumières, des ombres, et deux outils de travail (OrbitControls pour tourner autour de la scène, lil-gui pour régler des valeurs sans recharger). Installe d’abord lil-gui, OrbitControls est déjà livré avec three :
npm install lil-guiimport * as THREE from "three";
import { OrbitControls } from "three/addons/controls/OrbitControls.js";
import GUI from "lil-gui";Un matériau qui a besoin de lumière
const cube = new THREE.Mesh(
new THREE.BoxGeometry(1, 1, 1),
new THREE.MeshStandardMaterial({
color: "#ff0000",
}),
);
cube.position.y = 1;MeshStandardMaterial imite un matériau réel : il est sombre sans lumière, et il reçoit les ombres. Le sol est un PlaneGeometry : un plan est vertical à sa création, on le couche en le tournant d’un quart de tour (-Math.PI / 2 radians) autour de l’axe x.
Si tout est noir, c’est presque toujours qu’il manque une lumière dans la scène.
Deux lumières
const ambientLight = new THREE.AmbientLight("#ffffff", 0.4);
scene.add(ambientLight);
const sunLight = new THREE.DirectionalLight("#ffffff", 2);
sunLight.position.set(3, 5, 2);
scene.add(sunLight);AmbientLightéclaire tout, partout, de la même façon : elle débouche les zones d’ombre mais ne dessine aucun relief.DirectionalLightimite le soleil : des rayons parallèles qui viennent de sa position et vont vers le centre de la scène. C’est elle qui donne le relief.
Le deuxième nombre est l’intensité. Pour voir où sont les choses, deux aides se dessinent dans la scène : DirectionalLightHelper montre la lumière, AxesHelper montre les axes (x en rouge, y en vert, z en bleu).
Les ombres
Les ombres coûtent cher à calculer : Three.js les coupe par défaut. Il faut les activer à quatre endroits, sinon rien ne s’affiche :
renderer.shadowMap.enabled = truesur le rendu ;sunLight.castShadow = truesur la lumière qui projette ;cube.castShadow = truesur chaque objet qui fait de l’ombre ;floor.receiveShadow = truesur chaque objet qui la reçoit.
Seules certaines lumières projettent des ombres (DirectionalLight, SpotLight, PointLight). AmbientLight n’en fait jamais.
Tourner autour de la scène
const controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
renderer.setAnimationLoop(() => {
controls.update();
renderer.render(scene, camera);
});Clic gauche pour tourner, molette pour zoomer, clic droit pour se déplacer. enableDamping ajoute de l’inertie : pour qu’elle marche, il faut appeler controls.update() à chaque image.
Régler en direct avec lil-gui
const gui = new GUI();
gui.add(sunLight, "intensity", 0, 5).name("soleil");
gui.addColor(cube.material, "color").name("couleur du cube");gui.add(objet, "propriété", min, max) crée un curseur qui modifie directement la propriété de l’objet. addColor crée un sélecteur de couleur. name() change le libellé affiché. Le panneau apparaît en haut à droite : cherche les bonnes valeurs à la main, puis recopie-les dans ton code.
Pour aller plus loin
- Ajoute
gui.add(sunLight.position, "x", -5, 5)pour déplacer le soleil et voir l’ombre bouger. - Remplace
DirectionalLightpar unePointLight(une ampoule) et compare. - La documentation de lil-gui montre les autres types de réglages (cases à cocher, listes, boutons).