Dans ce nouveau chapitre, nous allons mettre en application les concepts théoriques de l’article précédent.
Je vous conseille vivement de commencer par lire le premier chapitre si ce n’est pas déjà fait, car nous allons aborder de manière pratique les concepts qui y sont détaillés :
Si vous êtes prêts, nous pouvons commencer !
Ainsi, notre objectif du jour consiste à créer un environnement de base Three.js composé d’un simple cube en 3D. Ce dernier pourra être utilisé comme point de départ de n’importe quel tutoriel.
Architecture de base du projet
Commençons ! Dans votre éditeur de code préféré, créons trois fichiers :
- index.html
- script.js
- style.css
Importer la librairie dans le projet
Puis, l’étape suivante consiste à créer un script module
ES6 dans notre code et d’y charger la bibliothèque Three.js.
L’instruction import
est utilisée pour ajouter une bibliothèque type module ES6 au projet :
<script type="module"> import * as THREE from 'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.module.js'; </script>
Notons qu’il est toujours possible d’importer la librairie à la manière d’un script JavaScript classique. Cependant, la méthode module
est recommandée depuis la version r106
de Three.js.
La fonction d’initialisation de notre application
Puis, nous créons une fonction d’initialisation :init
, cette dernière sera appelée à la fin du chargement de notre module JavaScript. Ce sera le point d’entrée de notre code.
import * as THREE from 'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.module.js'; function init() { } init();
L’élément Scene de Three.JS
C’est l’heure d’attaquer le concret ! Dans la fonction init
, initialisons une variable globale de type Scene
Three.js :
import * as THREE from 'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.module.js'; var scene; function init() { scene = new THREE.Scene(); } init();
Le constructeur de cette classe ne requiert aucun paramètre obligatoire ou facultatif.
Le Renderer WebGL de Three.js – La classe WebGLRenderer
Puis, il est nécessaire d’instancier un moteur de rendu dans notre code. La classe WebGLRenderer
permet d’afficher une scène Three.js dans une page WEB grâce à la technologie WebGL.
Pour cela, nous initialisons une variable globale dans la fonction init
comme précédemment :
import * as THREE from 'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.module.js'; var scene; var renderer; function init() { scene = new THREE.Scene(); // ---------------- RENDERER ---------------- renderer = new THREE.WebGLRenderer( { antialias : true } ); renderer.setPixelRatio( window.devicePixelRatio ); renderer.setSize( window.innerWidth, window.innerHeight ); document.body.appendChild( renderer.domElement ); // we add the HTML element to the HTML page } init();
WebGLRenderer – Constructeur
Le constructeur de cette classe accepte un objet JavaScript en paramètre facultatif afin de
pouvoir configurer notre instance de WebGLRenderer
.
Certaines options peuvent ainsi être activées, dans notre cas, c’est l’antialiasing, une fonctionnalité permettant de lisser les contours des objets 3D.
WebGLRenderer – setPixelRatio
Cette méthode est utilisée pour définir un ratio entre la taille de l’écran et le nombre de pixels.
Habituellement et comme dans notre exemple, la valeur définie en paramètres est égale au
ratio natif de la page actuelle de notre navigateur web.
WebGLRenderer – setSize
Cette méthode redimensionne l’élément HTML dans lequel est affiché le rendu 3D en fonction du ratio pixel et de la taille hauteur/largeur donnée en paramètres.
WebGLRenderer – domElement
Cette propriété représente l’entité HTML à ajouter a notre page WEB. Le rendu 3D sera affiché dans cet élément HTML.
Dans notre exemple, nous utilisons une fonction JavaScript pour ajouter cet élément dans notre page.
La Camera de notre projet – PerspectiveCamera
Nous choisissons d’utiliser une caméra de type PerspectiveCamera
. Cette dernière est conçue pour recréer le mode le projection basé sur la perspective de la vision humaine.
Toujours dans la fonction init
:
[...] var camera; function init() { [...] // ---------------- CAMERA ---------------- camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 1, 10000 ); camera.position.set( -500, 400, -500 ); camera.lookAt(new THREE.Vector3(0,0,0)); scene.add( camera ); } init();
PerspectiveCamera – Constructeur
Le constructeur de cette classe accepte quatre paramètres :
- FOV – Field of View (Angle d’ouverture de l’objectif)
- Aspect – Le ratio de projection (généralement Largeur / Hauteur)
- Distance minimale – Distance de vue minimale de la caméra
- Distance maximale – Distance de vue maximale de la caméra
PerspectiveCamera – position.set
Chaque objet de l’univers 3D Three.js possède une position sur trois axes, XYZ. Ces valeurs permettent de positionner un élément dans la scène.
Grace à la méthode set
, il est possible de définir la position de notre caméra dans la scène avec trois arguments – les valeurs X, Y et Z.
PerspectiveCamera – lookAt
Tout comme les valeurs de position sur trois axes, chaque objet de l’univers 3D Three.js possède une valeur de rotation sur les axes X, Y et Z.
Il est possible d’orienter notre camera en modifiant ces valeurs, mais il est beaucoup plus simple d’utiliser la méthode lookAt
.
Cette dernière ne nécessite qu’un seul argument, les coordonnées XYZ vers lesquelles la caméra doit s’orienter.
Ajouter la caméra à notre scène
Dans Three.js, chaque objet de l’univers propose une méthode add
.
Cette méthode permet d’établir une relation parent/enfant entre deux éléments. Ainsi, pour ajouter la caméra à la liste des enfants de notre scène, nous utiliserons cette fonctionnalité.
L’éclairage de notre scène
Un univers Three.js est composé d’éléments qui nécessitent le plus souvent d’être éclairés. Il existe plusieurs éclairages disponibles dans la bibliothèque, nous allons utiliser deux d’entre eux.
Éclairage global – AmbientLight
Cet éclairage illumine de manière égale l’intégralité des objets de la scène. Toujours dans la fonction init
, ajoutons une instance de AmbientLight
dans la scène :
// ---------------- LIGHTS ---------------- var ambientLight = new THREE.AmbientLight( 0xcccccc, 0.2 ); scene.add( ambientLight );
Le constructeur de cette classe prend, dans notre projet, deux paramètres facultatifs :
- Couleur de l’éclairage – Facultatif – 0xFFFFFF par défaut
- Intensité de l’éclairage – Facultatif – 1 par défaut
Éclairage directionnel : DirectionalLight
La plupart du temps, un simple éclairage global AmbientLight
n’est pas suffisant car il ne permet pas de distinguer correctement les polygones de nos objets 3D.
En effet ! Avec AmbientLight
, chaque face des objets 3D est éclairée de manière égale, il est donc impossible de simuler correctement une lumière naturelle.
L’éclairage DirectionalLight
simule une source lumineuse émise dans une direction, et est ainsi capable de créer des effets de lumière.
var directionalLight = new THREE.DirectionalLight( 0xffffff, 0.6 ); scene.add( directionalLight );
Le constructeur de DirectionalLight
fonctionne exactement comme celui de AmbientLight
.
Un Cube en 3D
Dans ce chapitre, notre objectif est de créer une vue 3D d’un cube en rotation. Ainsi, en plus des éléments déjà ajoutés, nous devons instancier une variable de type Mesh
pour créer notre cube.
Comme vous le savez déjà, un Mesh
est composé du combo d’une Geometry
et d’un Material
.
Nous créons une variable globale pour notre cube, et nous l’initialisons dans la fonction init
:
// ---------------- 3D CUBE ---------------- const geometry = new THREE.BoxGeometry( 150, 150, 150 ); const material = new THREE.MeshPhongMaterial( {color: 0x00ffff} ); cube = new THREE.Mesh( geometry, material ); scene.add( cube );
Notre Mesh
est composé d’une BoxGeometry
et d’un MeshPhongMaterial
.
Une Geometry cubique avec BoxGeometry
La première chose à faire est de créer une Geometry
, la forme de notre cube.
Pour cela, nous utilisons la classe BoxGeometry
. Cette dernière permet d’instancier une Geometry
rectangulaire selon trois paramètres :
- Largeur – Taille de la structure sur l’axe X
- Hauteur – Taille de la structure sur l’axe Y
- Profondeur – Taille de la structure sur l’axe Z
Ainsi, en définissant trois valeurs égales, il est possible de créer une Geometry
cubique.
L’aspect visuel de notre Mesh avec MeshPhongMaterial
La prochaine étape consiste a créer le Material
de notre cube. Il existe plusieurs types de Material
disponibles dans Three.js, nous choisissons l’un des plus utilisés, MeshPhongMaterial
.
Ce type de Material
est surtout utilisé pour son aspect brillant, contrairement aux d’autres qui sont principalement mats.
Le constructeur de cette classe accepte un objet JavaScript en paramètre facultatif afin de pouvoir configurer notre instance de MeshPhongMaterial
.
Nous utilisons cette fonctionnalité pour définir une couleur de texture en hexadécimal.
L’objet final Mesh
Notre cube est enfin créé et prêt a l’emploi dans sa variable ! Comme tout objet de la scène, il possède des valeurs de position
et rotation
, que nous choisissons de ne pas modifier pour le moment.
Le cube sera créé par défaut au centre le la scène (0, 0 , 0) XYZ.
Boucle principale et rendu 3D de la scène
Ouf ! Notre fonction d’initialisation est enfin terminée !
Tous les éléments et acteurs de notre univers Three.js sont désormais créés, il ne nous reste qu’une étape : la boucle principale d’animation.
Cette boucle principale nous permettra d’effectuer des actions à chaque tour de boucle (« frame »). L’une de ces actions concerne le rendu 3D, qui consiste à afficher notre scène perçue par une caméra.
Création de la boucle principale
Créons une fonction render
dans notre module JavaScript, cette fonction sera utilisée comme boucle principale et sera chargée d’effectuer des actions à chaque « frame » de notre application.
function render() { [...] }
Mise à jour du rendu 3D
Pour cela, nous utilisons notre objet de type WebGLRenderer
instancié dans la fonction init
.
Cette instance met à disposition une méthode de classe render
( à ne pas confondre avec notre fonction render
!), qui prends deux paramètres :
- Scene – Une scène Three.js
- Camera – Une caméra Three.js
Utilisons cette méthode avec nos variables :
function render() { renderer.render( scene, camera ); // We are rendering the 3D world }
Rotation du cube
Nous souhaitons faire tourner notre cube sur deux axes ( X et Y ).
Pour rappel, chaque objet de la scène possède une valeur de rotation pour chaque axe X, Y et Z.
Nous incrémentons à chaque tour de boucle, la valeur déjà effective sur les axes X et Y, pour faire entrer le cube en rotation
function render() { // rotating the cube each render tick cube.rotation.x += 0.005; cube.rotation.y += 0.01; renderer.render( scene, camera ); // We are rendering the 3D world }
Finalisation de la boucle
La dernière étape de ce projet consiste à finaliser le système de boucle principale.
Notre fonction render
est à présent capable de faire tourner le cube et d’effectuer un rendu 3D de notre scène dans le canvas
du WebGLRenderer
.
Cependant, n’oublions pas que cette fonction n’est pas encore utilisée ! La fonction init
est le point d’entrée de notre module JavaScript. Nous devons exécuter la fonction render
à la fin de init
comme ci-dessous :
[...] function init() { [...] // ---------------- STARTING THE RENDER LOOP ---------------- render(); } function render() { [...] }
Ainsi, lorsque la phase d’initialisation sera terminée, la fonction render
s’exécutera. Pour qu’elle adopte un comportement de boucle nous ajoutons une dernière ligne à la fin de la fonction render
:
function render() { // rotating the cube each render tick cube.rotation.x += 0.005; cube.rotation.y += 0.01; renderer.render( scene, camera ); // We are rendering the 3D world requestAnimationFrame( render ); // we are calling render() again, to loop }
requestAnimationFrame
est une fonction JavaScript adaptée à notre besoin, elle fera en sorte que la fonction render
s’exécute en boucle.
Résultat final et code du projet
See the Pen Hello World by Thomas (@thomassifferlen) on CodePen.
Cet article ne couvre que la surface des concepts de base de Three.js ! Dans le chapitre 2 du guide téléchargeable, vous découvrirez comment configurer en détail les différents concepts que je viens de vous présenter !
Vous pouvez télécharger le guide complet ici :
La prochaine étape de notre aventure en 3D concerne les classes Geometry
, suivez le guide :
[…] Chapitre 2 – Un Hello World avec Three.JS […]
[…] Chapitre 2 – Un Hello World avec Three.JS […]
[…] Chapitre 2 – Un Hello World avec Three.JS Chapitre 3 – Les principaux types de Geometry Three.JS […]
[…] August 3, 2021August 3, 2021 thomassifferlen No comments Disponible en Français […]
[…] Chapitre 2 – Un Hello World avec Three.js […]