Créer de la 3D dans le navigateur de zéro : scène, modèles STL/GLTF, animation au scroll, shaders, post-processing et portfolio 3D animé complet.
Three.js a des dizaines de géométries et matériaux intégrés. Comprendre quand utiliser lequel — et comment les lumières interagissent — permet de construire des scènes rapidement sans aller chercher des modèles 3D pour chaque élément.
Toutes les géométries Three.js héritent de BufferGeometry. Elles stockent les positions des vertices, les normales (direction des surfaces pour l'éclairage), les UV (coordonnées de texture) et les indices (triangles) dans des buffers GPU.
// Cube
new THREE.BoxGeometry(1, 1, 1)
// BoxGeometry(width, height, depth, widthSegments, heightSegments, depthSegments)
// Les segments divisent les faces — utile pour les déformations
// Sphère
new THREE.SphereGeometry(0.5, 32, 32)
// SphereGeometry(radius, widthSegments, heightSegments)
// Plus de segments = plus rond, plus coûteux
// Plan
new THREE.PlaneGeometry(2, 2, 1, 1)
// Cylindre
new THREE.CylinderGeometry(0.5, 0.5, 1, 32)
// CylinderGeometry(radiusTop, radiusBottom, height, radialSegments)
// Tore (donut)
new THREE.TorusGeometry(0.4, 0.15, 16, 100)
// Tore noué
new THREE.TorusKnotGeometry(0.4, 0.1, 100, 16)
// Icosaèdre — base pour les sphères low-poly
new THREE.IcosahedronGeometry(0.5, 0) // detail = 0 → low poly
new THREE.IcosahedronGeometry(0.5, 4) // detail = 4 → quasi-sphèrePour des formes personnalisées, on construit la géométrie à partir de vertices.
const geometry = new THREE.BufferGeometry()
// 3 vertices = 1 triangle
const vertices = new Float32Array([
-1, -1, 0, // vertex 0 : x, y, z
1, -1, 0, // vertex 1
0, 1, 0, // vertex 2
])
geometry.setAttribute(
'position',
new THREE.BufferAttribute(vertices, 3) // 3 valeurs par vertex
)
geometry.computeVertexNormals() // calculer les normales pour l'éclairagePour des milliers de triangles, Float32Array est directement transféré au GPU — pas de conversion.
Pas d'éclairage. La couleur est constante quelle que soit la lumière. Utile pour les wireframes et les éléments qui ne doivent pas être affectés par la lumière.
const mat = new THREE.MeshBasicMaterial({
color: '#ff0000',
wireframe: true, // afficher seulement les arêtes
})Le matériau par défaut pour la plupart des cas. PBR — réagit aux lumières de façon physiquement correcte.
const mat = new THREE.MeshStandardMaterial({
color: '#888888',
roughness: 0.5, // 0 = miroir, 1 = totalement mat
metalness: 0.0, // 0 = non-métallique, 1 = métal pur
envMapIntensity: 1, // intensité du reflet d'environnement
})Extension de MeshStandardMaterial avec des propriétés supplémentaires pour des matériaux complexes.
const glass = new THREE.MeshPhysicalMaterial({
color: '#ffffff',
roughness: 0,
metalness: 0,
transmission: 1.0, // transparence physique (verre)
thickness: 0.5, // épaisseur pour la réfraction
ior: 1.5, // index of refraction (verre = 1.5)
transparent: true,
})
const clearcoat = new THREE.MeshPhysicalMaterial({
color: '#cc0000',
roughness: 0.3,
metalness: 0.8,
clearcoat: 1.0, // vernis brillant par-dessus
clearcoatRoughness: 0.1,
})Affiche les normales des surfaces en couleur — rouge = X, vert = Y, bleu = Z. Utile pour déboguer.
const mat = new THREE.MeshNormalMaterial()Shaders GLSL entièrement custom. Couvert au chapitre 6.
const textureLoader = new THREE.TextureLoader()
const colorMap = textureLoader.load('/textures/wood_color.jpg')
const roughnessMap = textureLoader.load('/textures/wood_roughness.jpg')
const normalMap = textureLoader.load('/textures/wood_normal.jpg')
const mat = new THREE.MeshStandardMaterial({
map: colorMap, // texture de couleur (albedo)
roughnessMap: roughnessMap, // rugosité par zone
normalMap: normalMap, // simulation de relief (sans polygones)
normalScale: new THREE.Vector2(1, 1),
})colorMap.wrapS = THREE.RepeatWrapping // axe horizontal
colorMap.wrapT = THREE.RepeatWrapping // axe vertical
colorMap.repeat.set(4, 4) // répéter 4x dans chaque directionUn HDRI (image 360° haute dynamique) sert de source de lumière et de reflet pour les matériaux PBR.
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js'
const rgbeLoader = new RGBELoader()
rgbeLoader.load('/hdri/studio.hdr', (texture) => {
texture.mapping = THREE.EquirectangularReflectionMapping
scene.environment = texture // utilisé pour les reflets de TOUS les matériaux
scene.background = texture // aussi comme arrière-plan (optionnel)
})Avec un HDRI, même une sphère métallique sans lumières directionnelles est visuellement convaincante — les reflets de l'environnement font tout le travail.
Éclairage de base sans direction. Éclaire uniformément tout dans la scène.
const ambient = new THREE.AmbientLight('#ffffff', 0.3)
scene.add(ambient)Ne pas mettre trop fort — ça "aplatit" la scène en annulant les ombres et contrastes.
Simule le soleil — rayons parallèles depuis une direction.
const dirLight = new THREE.DirectionalLight('#ffffff', 2)
dirLight.position.set(5, 10, 5) // direction = de cette position vers l'origine
// Ombres
dirLight.castShadow = true
dirLight.shadow.mapSize.width = 2048 // résolution de la shadow map
dirLight.shadow.mapSize.height = 2048
dirLight.shadow.camera.near = 0.1
dirLight.shadow.camera.far = 50
dirLight.shadow.camera.left = -10
dirLight.shadow.camera.right = 10
dirLight.shadow.camera.top = 10
dirLight.shadow.camera.bottom = -10
dirLight.shadow.bias = -0.001 // évite le "shadow acne" (artefacts)
scene.add(dirLight)Pour les ombres : renderer.shadowMap.enabled = true, mesh.castShadow = true, planeSol.receiveShadow = true.
Lumière en point — comme une ampoule. Rayonne dans toutes les directions, s'atténue avec la distance.
const pointLight = new THREE.PointLight('#ff6600', 5, 10)
// PointLight(color, intensity, distance)
pointLight.position.set(2, 3, 2)
scene.add(pointLight)Cone de lumière avec angle et pénombre.
const spot = new THREE.SpotLight('#ffffff', 10)
spot.position.set(0, 10, 0)
spot.angle = Math.PI / 6 // angle du cone (30°)
spot.penumbra = 0.3 // douceur du bord (0 = dur, 1 = très doux)
spot.target.position.set(0, 0, 0)
scene.add(spot)
scene.add(spot.target) // le target doit aussi être dans la scèneSurface lumineuse rectangulaire — comme un panneau lumineux ou une fenêtre.
import { RectAreaLightHelper } from 'three/examples/jsm/helpers/RectAreaLightHelper.js'
import { RectAreaLightUniformsLib } from 'three/examples/jsm/lights/RectAreaLightUniformsLib.js'
RectAreaLightUniformsLib.init() // obligatoire pour RectAreaLight
const rectLight = new THREE.RectAreaLight('#ffffff', 5, 4, 2)
// RectAreaLight(color, intensity, width, height)
rectLight.position.set(0, 5, -5)
rectLight.lookAt(0, 0, 0)
scene.add(rectLight)RectAreaLight fonctionne uniquement avec MeshStandardMaterial et MeshPhysicalMaterial. Elle ne supporte pas les ombres (limitation WebGL).
Pendant le développement, les helpers visualisent les éléments invisibles.
import { DirectionalLightHelper } from 'three'
import { CameraHelper } from 'three'
// Voir la position et direction d'une lumière
const lightHelper = new THREE.DirectionalLightHelper(dirLight, 1)
scene.add(lightHelper)
// Voir le frustum de la shadow camera
const shadowHelper = new THREE.CameraHelper(dirLight.shadow.camera)
scene.add(shadowHelper)
// Axes X Y Z
const axesHelper = new THREE.AxesHelper(5)
scene.add(axesHelper)
// Grille au sol
const gridHelper = new THREE.GridHelper(20, 20)
scene.add(gridHelper)Toujours les retirer avant la mise en production.
Une géométrie et un matériau peuvent être partagés par plusieurs meshes — le GPU charge les données une seule fois.
const sharedGeo = new THREE.SphereGeometry(0.2, 16, 16)
const sharedMat = new THREE.MeshStandardMaterial({ color: '#cdff4f' })
// 100 sphères avec la même géo et le même mat
for (let i = 0; i < 100; i++) {
const mesh = new THREE.Mesh(sharedGeo, sharedMat)
mesh.position.set(
(Math.random() - 0.5) * 20,
(Math.random() - 0.5) * 20,
(Math.random() - 0.5) * 20
)
scene.add(mesh)
}Pour des centaines ou milliers d'instances identiques, InstancedMesh est encore plus performant — un seul draw call pour toutes les instances.
Géométries, matériaux, textures, lumières — la boîte à outils est complète. Le chapitre suivant couvre le point crucial du cours : charger des modèles 3D réels (STL, GLTF) et les intégrer dans la scène.