You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

444 lines
30 KiB

2 years ago
<!DOCTYPE html><html lang="fr"><head>
<meta charset="utf-8">
<title>principes de base</title>
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:site" content="@threejs">
<meta name="twitter:title" content="Three.js – principes de base">
<meta property="og:image" content="https://threejs.org/files/share.png">
<link rel="shortcut icon" href="/files/favicon_white.ico" media="(prefers-color-scheme: dark)">
<link rel="shortcut icon" href="/files/favicon.ico" media="(prefers-color-scheme: light)">
<link rel="stylesheet" href="/manual/resources/lesson.css">
<link rel="stylesheet" href="/manual/resources/lang.css">
<!-- Import maps polyfill -->
<!-- Remove this when import maps will be widely supported -->
<script async src="https://unpkg.com/es-module-shims@1.3.6/dist/es-module-shims.js"></script>
<script type="importmap">
{
"imports": {
"three": "../../build/three.module.js"
}
}
</script>
</head>
<body>
<div class="container">
<div class="lesson-title">
<h1>principes de base</h1>
</div>
<div class="lesson">
<div class="lesson-main">
<p>Ceci est le premier article d'une série consacrée à Three.js.
<a href="https://threejs.org">Three.js</a> est une bibliothèque 3D qui a pour objectif
de rendre aussi facile que possible l'inclusion de contenu 3D dans une page web.</p>
<p>Three.js est souvent confondu avec WebGL puisque la plupart du temps, mais
pas toujours, elle exploite WebGL pour dessiner en 3D.
<a href="https://webglfundamentals.org">WebGL est un système très bas niveau qui ne dessine que des points, des lignes et des triangles</a>.
Faire quelque chose d'exploitable avec WebGL requiert une certaine quantité de code
et c'est là que Three.js intervient. Elle prend en charge des choses
telles que les scènes, lumières, ombres, matériaux, textures, mathématiques 3D, en bref,
tout ce que vous avez à écrire par vous même si vous aviez à utiliser WebGL directement.</p>
<p>Ces tutoriels supposent que JavaScript vous est connu et, pour grande partie,
se conforment au style ES6. <a href="prerequisites.html">Consultez ici une brève liste des choses que vous êtes
déjà censés connaître</a>.</p>
<p>La plupart des navigateurs qui supportent three.js se mettent à jour automatiquement
donc la plupart des utilisateurs devraient être capables d'exécuter ce code.
Si vous souhaitez exécuter ce code sur un très vieux navigateur, nous vous recommandons
un transpileur tel que <a href="https://babeljs.io">Babel</a>.
Bien sûr, les utilisateurs exécutant de très vieux navigateurs ont probablement
des machines incapables de faire tourner Three.js.</p>
<p>Lors de l'apprentissage de la plupart des langages de programmation,
la première tâche que les gens font est de faire afficher à l'ordinateur
<code class="notranslate" translate="no">"Hello World!"</code>. Pour la programmation 3D, l'équivalent est de faire afficher
un cube en 3D. Donc, nous commencerons par "Hello Cube!".</p>
<p>Avant de débuter, nous allons tenter de vous donner un idée de la structure
d'une application Three.js. Elle requiert de créer un ensemble d'objets
et de les connecter. Voici un diagramme qui représente une application
Three.js de petite taille:</p>
<div class="threejs_center"><img src="../resources/images/threejs-structure.svg" style="width: 768px;"></div>
<p>Voici ce qui est à remarquer dans le diagramme ci-dessus :</p>
<ul>
<li><p>Il y a un <a href="/docs/#api/en/constants/Renderer"><code class="notranslate" translate="no">Renderer</code></a>. C'est sans doute l'objet principal de Three.js. Vous passez
une <a href="/docs/#api/en/scenes/Scene"><code class="notranslate" translate="no">Scene</code></a> et une <a href="/docs/#api/en/cameras/Camera"><code class="notranslate" translate="no">Camera</code></a> à un <a href="/docs/#api/en/constants/Renderer"><code class="notranslate" translate="no">Renderer</code></a> et il effectue le rendu (dessine) de la
partie de la scène 3D qui est à l'intérieur de l'espace visible (en réalité une pyramide tronquée ou <em>frustum</em>)
de la caméra dans une image 2D affichée dans un canevas (<em>canvas</em>).</p>
</li>
<li><p>Il y a un <a href="scenegraph.html">graphe de scène</a> qui est une structure arborescente,
constituée de divers objets tel qu'un objet <a href="/docs/#api/en/scenes/Scene"><code class="notranslate" translate="no">Scene</code></a>, de multiple maillages (<a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a>),
des lumières (<a href="/docs/#api/en/lights/Light"><code class="notranslate" translate="no">Light</code></a>), des groupes (<a href="/docs/#api/en/objects/Group"><code class="notranslate" translate="no">Group</code></a>), des objets 3D <a href="/docs/#api/en/core/Object3D"><code class="notranslate" translate="no">Object3D</code></a> et des objets <a href="/docs/#api/en/cameras/Camera"><code class="notranslate" translate="no">Camera</code></a>.
Un objet <a href="/docs/#api/en/scenes/Scene"><code class="notranslate" translate="no">Scene</code></a> définit la racine d'un graphe de scène et contient des propriétés telles que
la couleur d'arrière plan et le brouillard. L'ensemble de ces objets définissent une structure
hiérarchique de type parent/enfant, arborescente, et indique où les objets apparaissent et
comment ils sont orientés. Les enfants sont positionnés et orientés par rapport à leur parent.
Par exemple, les roues d'une voiture sont les enfants du châssis impliquant que si l'on déplace
ou oriente la voiture, les roues suivront automatiquement son déplacement. Plus de
détails sont donnés dans <a href="scenegraph.html">l'article sur les graphes de scène</a>.</p>
<p>Il est à noter sur que ce diagramme <a href="/docs/#api/en/cameras/Camera"><code class="notranslate" translate="no">Camera</code></a> est patiellement placé dans le graphe de scène.
Cela permet d'attirer l'attention qu'en Three.js, contrairement aux autres objets, une <a href="/docs/#api/en/cameras/Camera"><code class="notranslate" translate="no">Camera</code></a> ne doit
pas forcément faire partie du graphe de scène pour être opérationnelle. Une <a href="/docs/#api/en/cameras/Camera"><code class="notranslate" translate="no">Camera</code></a>, de la même
façon que les autres objets, enfant d'un autre objet, se déplace et s'oriente par rapport à son
objet parent. A la fin de <a href="scenegraph.html">l'article sur les graphes de scène</a>, l'inclusion
de multiples objets <a href="/docs/#api/en/cameras/Camera"><code class="notranslate" translate="no">Camera</code></a> dans un unique graphe de scène est donné en exemple.</p>
</li>
<li><p>Les objets de type <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a> représentent une géométrie (<code class="notranslate" translate="no">Geometry</code>) liée à un matériau (<a href="/docs/#api/en/materials/Material"><code class="notranslate" translate="no">Material</code></a>)
spécifique. Les objets <a href="/docs/#api/en/materials/Material"><code class="notranslate" translate="no">Material</code></a> et <code class="notranslate" translate="no">Geometry</code> peuvent être liés à plusieurs objets <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a>
simultanément. Par exemple, pour dessiner deux cubes bleus à des positions différentes, nous
pouvons soit utiliser deux objets <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a> pour spécifier les positions et orientations de
chaque cube; soit nous pouvons utiliser seulement une géométrie unique (<code class="notranslate" translate="no">Geometry</code>) pour décrire les
données spatiales du cube et un matériau unique (<a href="/docs/#api/en/materials/Material"><code class="notranslate" translate="no">Material</code></a>) pour spécifier la couleur bleue.
Les deux objets <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a> peuvent ainsi référencer les mêmes objets <code class="notranslate" translate="no">Geometry</code> et <a href="/docs/#api/en/materials/Material"><code class="notranslate" translate="no">Material</code></a>.</p>
</li>
<li><p>Les objets <code class="notranslate" translate="no">Geometry</code> représentent les données associées aux sommets d'une géométrie telle qu'une
sphère, un cube, un avion, un chien, un chat, un humain, un arbre, un bâtiment, etc...
Three.js fournit plusieurs types intégrés de <a href="primitives.html">primitives géométriques</a>.
Vous pouvez aussi <a href="custom-buffergeometry.html">créer vos propres géométries</a> ou
<a href="load-obj.html">charger des géométries à partir d'un fichier</a>.</p>
</li>
<li><p>Les objets <a href="/docs/#api/en/materials/Material"><code class="notranslate" translate="no">Material</code></a> représentent les
<a href="materials.html">propriétés de surface utilisées pour dessiner la géométrie</a>
telles que la couleur à utiliser ou le pouvoir réfléchissant (brillance). Un matériau (<a href="/docs/#api/en/materials/Material"><code class="notranslate" translate="no">Material</code></a>)
peut aussi se référer à un ou plusieurs objets <a href="/docs/#api/en/textures/Texture"><code class="notranslate" translate="no">Texture</code></a> dont l'utilité est, par exemple, de plaquer
une image sur la surface d'une géométrie.</p>
</li>
<li><p>Les objets <a href="/docs/#api/en/textures/Texture"><code class="notranslate" translate="no">Texture</code></a> représentent généralement des images soit <a href="textures.html">chargées de fichiers image</a>,
soit <a href="canvas-textures.html">générées par le biais d'un canevas</a> ou
<a href="rendertargets.html">résultant du rendu d'une autre scène</a>.</p>
</li>
<li><p>Les objets <a href="/docs/#api/en/lights/Light"><code class="notranslate" translate="no">Light</code></a> représentent <a href="lights.html">différentes sortent de lumière</a>.</p>
</li>
</ul>
<p>Maintenant que tout cela a été défini, nous allons présenter un exemple de type <em>"Hello Cube"</em> utilisant un
nombre minimum d'élements Three.js :</p>
<div class="threejs_center"><img src="../resources/images/threejs-1cube-no-light-scene.svg" style="width: 500px;"></div>
<p>Tout d'abord, chargeons Three.js :</p>
<pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;script type="module"&gt;
import * as THREE from 'three';
&lt;/script&gt;
</pre>
<p>Il est important d'écrire <code class="notranslate" translate="no">type="module"</code> dans la balise script.
Cela nous autorise l'utilisation du mot-clé <code class="notranslate" translate="no">import</code> pour charger Three.js.
Il y a d'autres manières de le réaliser, mais depuis la version 106 (r106),
l'utilisation des modules est recommandée. Ils ont l'avantage de pouvoir
facilement importer les autres modules dont ils ont besoin. Cela nous
épargne d'avoir à charger à la main les scripts supplémentaires dont ils dépendent.</p>
<p>Ensuite, nous avons besoin d'une balise <code class="notranslate" translate="no">&lt;canvas&gt;</code> :</p>
<pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;body&gt;
&lt;canvas id="c"&gt;&lt;/canvas&gt;
&lt;/body&gt;
</pre>
<p>Nous allons demander à Three.js de dessiner dans ce canevas donc nous devons le rechercher
dans le document html :</p>
<pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;script type="module"&gt;
import * as THREE from 'three';
+function main() {
+ const canvas = document.querySelector('#c');
+ const renderer = new THREE.WebGLRenderer({canvas});
+ ...
&lt;/script&gt;
</pre>
<p>Après la recherche du canevas, nous créons un <a href="/docs/#api/en/renderers/WebGLRenderer"><code class="notranslate" translate="no">WebGLRenderer</code></a>. Le <em>renderer</em>
a pour mission de charger les données fournies et d'en effectuer le rendu
dans le canevas. Par le passé, il y a eu aussi d'autre <em>renderers</em> tels que
<code class="notranslate" translate="no">CSSRenderer</code> ou <code class="notranslate" translate="no">CanvasRenderer</code> et, dans le futur, il pourrait y avoir un
<code class="notranslate" translate="no">WebGL2Renderer</code> ou <code class="notranslate" translate="no">WebGPURenderer</code>. Pour le moment, il y a un <a href="/docs/#api/en/renderers/WebGLRenderer"><code class="notranslate" translate="no">WebGLRenderer</code></a>
qui utiliser WebGL pour effectuer une rendu 3D dans le canevas.</p>
<p>Notez qu'il y a quelques détails ésotériques ici. Si vous ne passez pas un
canevas à Three.js, il va en créer un pour vous mais vous aurez à l'ajouter
au document. Où l'ajouter peut dépendre du contexte d'utilisation et vous aurez
à modifier votre code en conséquence. Passer un canevas à Three.js nous apparaît donc
plus flexible. Nous pouvons mettre le canevas n'importe où et le code le retrouvera.
Dans le cas contraire, nous aurons à coder où insérer le canevas, ce qui amènera
probablement à changer le code si le contexte d'utilisation change.</p>
<p>Ensuite, nous avons besoin d'une caméra. Nous créons une <a href="/docs/#api/en/cameras/PerspectiveCamera"><code class="notranslate" translate="no">PerspectiveCamera</code></a>.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const fov = 75;
const aspect = 2; // valeur par défaut du canevas
const near = 0.1;
const far = 5;
const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
</pre>
<p><code class="notranslate" translate="no">fov</code> est le raccourci pour <code class="notranslate" translate="no">field of view</code> ou champ de vision.
Dans ce cas, 75 degrés d'ouverture verticale. Il est à noter que
la plupart des angles dans Three.js sont exprimés en radians à l'exception
de la caméra perspective.</p>
<p><code class="notranslate" translate="no">aspect</code> est l'aspect de l'affichage dans le canevas. Cela sera détaillé
<a href="responsive.html">dans un autre article</a>. Toutefois, par défaut,
un canevas est de taille 300x150 pixels ce qui lui confère l'aspect 300/150 ou 2.</p>
<p><code class="notranslate" translate="no">near</code> et <code class="notranslate" translate="no">far</code> délimitent la portion de l'espace devant la caméra dont
le rendu est effectué. Tout ce qui est avant ou après est découpé (<em>clipped</em>),
donc non dessiné.</p>
<p>Ces 4 paramètres définissent une pyramide tronquée ou <em>"frustum"</em>.
En d'autres termes, il s'agit d'une autre forme 3D à l'instar des sphères,
cubes et prismes.</p>
<p><img src="../resources/frustum-3d.svg" width="500" class="threejs_center"></p>
<p>L'espacement entre les plans <em>near</em> et <em>far</em> est déterminé
par le champ de vision. La largeur est fixée par le champ de vision et l'aspect.</p>
<p>Tout ce qui est dans le <em>frustum</em> est dessiné. Ce qui est à l'extérieur ne l'est pas.</p>
<p>La caméra regarde par défaut suivant l'axe -Z, +Y pointant le haut.
Nous mettons notre cube à l'origine donc nous devons déplacer la caméra de l'origine légèrement vers son arrière
pour voir quelque chose.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">camera.position.z = 2;
</pre>
<p>Voici ce que nous voudrions voir :</p>
<p><img src="../resources/scene-down.svg" width="500" class="threejs_center"></p>
<p>Dans le schéma ci-dessus, nous pouvons voir que notre caméra est placée
en <code class="notranslate" translate="no">z = 2</code>. Elle regarde le long de la direction -Z.
Notre <em>frustum</em> démarre à 0.1 unités de la caméra et s'étend jusqu'à 5 unités devant elle.
Comme le schéma est vu du haut, le champ de vue est affecté par l'aspect.
Notre canvas est deux fois plus large que haut donc le champ de vue horizontal
est plus grand que les 75 degrés spécifié pour le champ vertical.</p>
<p>Ensuite, nous créons une <a href="/docs/#api/en/scenes/Scene"><code class="notranslate" translate="no">Scene</code></a>. Dans Three.js, une <a href="/docs/#api/en/scenes/Scene"><code class="notranslate" translate="no">Scene</code></a> est la racine
du graphe de scène. Tout ce que nous voulons que Three.js dessine doit être ajouté
à la scène. Cela sera davantage détaillé dans <a href="scenegraph.html">un futur article sur le fonctionnement des scènes</a>.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const scene = new THREE.Scene();
</pre>
<p>Ensuite nous créons une géométrie de type <a href="/docs/#api/en/geometries/BoxGeometry"><code class="notranslate" translate="no">BoxGeometry</code></a> qui contient les données pour un parallélépipède.
Quasiment tout ce que nous souhaitons afficher avec Three.js nécessite une
géométrie qui définit les sommets qui composent nos objets 3D.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const boxWidth = 1;
const boxHeight = 1;
const boxDepth = 1;
const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
</pre>
<p>Puis nous créons un matériau basique et fixons sa couleur, qui peut être spécifiée au format hexadécimal (6 chiffres) du standard CSS.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const material = new THREE.MeshBasicMaterial({color: 0x44aa88});
</pre>
<p>Nous créons ensuite un maillage (<a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a>). Dans Three.js, il représente la combinaison
d'une <code class="notranslate" translate="no">Geometry</code> (forme de l'objet) et d'un matériau (<a href="/docs/#api/en/materials/Material"><code class="notranslate" translate="no">Material</code></a> - aspect
d'un objet, brillant ou plat, quelle couleur, quelle texture appliquer, etc.)
ainsi que la position, l'orientation et l'échelle de l'objet dans la scène.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const cube = new THREE.Mesh(geometry, material);
</pre>
<p>Finalement, nous ajoutons le maillage à la scène.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">scene.add(cube);
</pre>
<p>Nous pouvons, maintenant, effectuer le rendu de la scène en appelant la fonction <em>render</em> du <em>renderer</em>
et en lui passant la scène et la caméra.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">renderer.render(scene, camera);
</pre>
<p>Voici un exemple fonctionnel :</p>
<p></p><div translate="no" class="threejs_example_container notranslate">
<div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/fundamentals.html"></iframe></div>
<a class="threejs_center" href="/manual/examples/fundamentals.html" target="_blank">Cliquer ici pour ouvrir dans une fenêtre séparée</a>
</div>
<p></p>
<p>Il est difficile de déterminer s'il s'agit d'un cube 3D puisque nous
l'observons suivant l'axe -Z sur lequel le cube est lui même aligné.
Nous n'en voyons donc qu'une face.</p>
<p>Animons notre cube en le faisant tourner et cela fera clairement
apparaître qu'il est dessiné en 3D. Pour l'animation, nous effectuerons son rendu
dans une boucle de rendu en utilisant
<a href="https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame"><code class="notranslate" translate="no">requestAnimationFrame</code></a>.</p>
<p>Voici notre boucle :</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">function render(time) {
time *= 0.001; // convertis le temps en secondes
cube.rotation.x = time;
cube.rotation.y = time;
renderer.render(scene, camera);
requestAnimationFrame(render);
}
requestAnimationFrame(render);
</pre>
<p><code class="notranslate" translate="no">requestAnimationFrame</code> est une requête auprès du navigateur dans le cas où vous
voulez animer quelque chose. Nous lui passons une fonction à appeler.
Dans notre cas, c'est la fonction <code class="notranslate" translate="no">render</code>. Le navigateur appellera cette fonction
et, si nous mettons à jour l'affichage de la page, le navigateur refera le rendu
de la page. Dans notre cas, nous appelons la fonction <code class="notranslate" translate="no">renderer.render</code> de Three.js
qui dessinera notre scène.</p>
<p><code class="notranslate" translate="no">requestAnimationFrame</code> passe à notre fonction le temps depuis lequel la page est chargée.
Il est mesuré en millisecondes. Il est parfois plus facile de travailler
avec des secondes. C'est pourquoi, nous l'avons converti.</p>
<p>A présent, nous appliquons sur le cube des rotations le long des axes X et Y en fonction du temps écoulé.
Les angles de rotation sont exprimés en <a href="https://en.wikipedia.org/wiki/Radian">radians</a>.
Sachant que 2 PI radians fait faire un tour complet, notre cube effectuera une rotation complète
sur chaque axe en, à peu près, 6,28 secondes.</p>
<p>Nous effectuons alors le rendu de la scène et
demandons une autre image pour l'animation afin de poursuivre notre boucle.</p>
<p>A l'extérieur de la boucle, nous appelons <code class="notranslate" translate="no">requestAnimationFrame</code> une première fois pour activer la boucle.</p>
<p></p><div translate="no" class="threejs_example_container notranslate">
<div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/fundamentals-with-animation.html"></iframe></div>
<a class="threejs_center" href="/manual/examples/fundamentals-with-animation.html" target="_blank">Cliquer ici pour ouvrir dans une fenêtre séparée</a>
</div>
<p></p>
<p>C'est un peu mieux mais il est toujours difficile de percevoir la 3D.
Ce qui aiderait serait d'ajouter de la lumière.
Three.js propose plusieurs type de lumière que nous détaillerons dans
<a href="lights.html">un futur article</a>. Pour le moment, créons une lumière directionnelle.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">{
const color = 0xFFFFFF;
const intensity = 1;
const light = new THREE.DirectionalLight(color, intensity);
light.position.set(-1, 2, 4);
scene.add(light);
}
</pre>
<p>Les lumières directionnelles ont une position et une cible. Les deux sont par défaut en 0, 0, 0.
Dans notre cas, nous positionnons la lumière en -1, 2, 4, de manière à ce qu'elle soit légèrement
sur la gauche, au dessus et derrière notre caméra. La cible est toujours 0, 0, 0 donc elle va
éclairer vers l'origine.</p>
<p>Nous avons également besoin de changer le matériau car <a href="/docs/#api/en/materials/MeshBasicMaterial"><code class="notranslate" translate="no">MeshBasicMaterial</code></a> ne s'applique pas aux
lumières. Nous le remplaçons par un <a href="/docs/#api/en/materials/MeshPhongMaterial"><code class="notranslate" translate="no">MeshPhongMaterial</code></a> qui est affecté par les sources lumineuses.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">-const material = new THREE.MeshBasicMaterial({color: 0x44aa88}); // cyan
+const material = new THREE.MeshPhongMaterial({color: 0x44aa88}); // cyan
</pre>
<p>Voici à présent la nouvelle structure de notre programme :</p>
<div class="threejs_center"><img src="../resources/images/threejs-1cube-with-directionallight.svg" style="width: 500px;"></div>
<p>Et voici son fonctionnement :</p>
<p></p><div translate="no" class="threejs_example_container notranslate">
<div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/fundamentals-with-light.html"></iframe></div>
<a class="threejs_center" href="/manual/examples/fundamentals-with-light.html" target="_blank">Cliquer ici pour ouvrir dans une fenêtre séparée</a>
</div>
<p></p>
<p>Cela devrait à présent apparaître très clairement en 3D.</p>
<p>Pour le sport, ajoutons 2 cubes supplémentaires.</p>
<p>Nous partageons la même géométrie pour chaque cube mais un matériau différent par cube
afin qu'ils aient une couleur différente.</p>
<p>Tout d'abord, nous définissons une fonction qui crée un nouveau matériau
avec la couleur spécifiée. Ensuite, elle créé un maillage à partir de la
géométrie spécifiée, l'ajoute à la scène et change sa position en X.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">function makeInstance(geometry, color, x) {
const material = new THREE.MeshPhongMaterial({color});
const cube = new THREE.Mesh(geometry, material);
scene.add(cube);
cube.position.x = x;
return cube;
}
</pre>
<p>Ensuite, nous l'appellons à 3 reprises avec 3 différentes couleurs
et positions en X, puis nous conservons ces instances de <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a> dans un tableau.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const cubes = [
makeInstance(geometry, 0x44aa88, 0),
makeInstance(geometry, 0x8844aa, -2),
makeInstance(geometry, 0xaa8844, 2),
];
</pre>
<p>Enfin, nous faisons tourner ces 3 cubes dans notre fonction de rendu.
Nous calculons une rotation légèrement différente pour chacun d'eux.</p>
<pre class="prettyprint showlinemods notranslate lang-js" translate="no">function render(time) {
time *= 0.001; // conversion du temps en secondes
cubes.forEach((cube, ndx) =&gt; {
const speed = 1 + ndx * .1;
const rot = time * speed;
cube.rotation.x = rot;
cube.rotation.y = rot;
});
...
</pre>
<p>et voilà le résultat.</p>
<p></p><div translate="no" class="threejs_example_container notranslate">
<div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/fundamentals-3-cubes.html"></iframe></div>
<a class="threejs_center" href="/manual/examples/fundamentals-3-cubes.html" target="_blank">Cliquer ici pour ouvrir dans une fenêtre séparée</a>
</div>
<p></p>
<p>Si nous le comparons au schéma précédent, nous constatons qu'il
est conforme à nos attentes. Les cubes en X = -2 et X = +2
sont partiellement en dehors du <em>frustum</em>. Ils sont, de plus,
exagérément déformés puisque le champ de vision dépeint au travers du
canevas est extrême.</p>
<p>A présent, notre programme est schématisé par la figure suivante :</p>
<div class="threejs_center"><img src="../resources/images/threejs-3cubes-scene.svg" style="width: 610px;"></div>
<p>Comme nous pouvons le constater, nous avons 3 objets de type <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a>, chacun référençant
la même <a href="/docs/#api/en/geometries/BoxGeometry"><code class="notranslate" translate="no">BoxGeometry</code></a>. Chaque <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a> référence également un <a href="/docs/#api/en/materials/MeshPhongMaterial"><code class="notranslate" translate="no">MeshPhongMaterial</code></a> unique
de sorte que chaque cube possède une couleur différente.</p>
<p>Nous espérons que cette courte introduction vous aide à débuter.
<a href="responsive.html">La prochaine étape consiste à rendre notre code réactif et donc adaptable à de multiples situations</a>.</p>
<div class="threejs_bottombar">
<h3>es6 modules, Three.js et structure de dossiers</h3>
<p>Depuis la version 106 (r106), l'utilisation de Three.js privilégie les <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import">modules es6</a>.</p>
<p>
Ils sont chargés via le mot-clé <code class="notranslate" translate="no">import</code> dans un script ou en ligne
par le biais d'une balise <code class="notranslate" translate="no">&lt;script type="module"&gt;</code>. Voici un exemple d'utilisation avec les deux :
</p>
<pre class="prettyprint">&lt;script type="module"&gt;
import * as THREE from 'three';
...
&lt;/script&gt;
</pre>
<p>
Les chemins doivent être absolus ou relatifs. Un chemin relatif commencent toujours par
<code class="notranslate" translate="no">./</code> ou par <code class="notranslate" translate="no">../</code>,
ce qui est différent des autres balises telles que <code class="notranslate" translate="no">&lt;img&gt;</code> et <code class="notranslate" translate="no">&lt;a&gt;</code>.
</p>
<p>
Les références à un même script ne seront chargées qu'une seule fois à partir du
moment où leur chemin absolu est exactement identique. Pour Three.js, cela veut
dire qu'il est nécessaire de mettre toutes les bibliothèques d'exemples dans une
structure correcte pour les dossiers :
</p>
<pre class="dos">unDossier
|
├-build
| |
| +-three.module.js
|
+-examples
|
+-jsm
|
+-controls
| |
| +-OrbitControls.js
| +-TrackballControls.js
| +-...
|
+-loaders
| |
| +-GLTFLoader.js
| +-...
|
...
</pre>
<p>
La raison nécessitant cette structuration des dossiers est parce que les scripts
des exemples tels que <a href="https://github.com/mrdoob/three.js/blob/master/examples/jsm/controls/OrbitControls.js"><code class="notranslate" translate="no">OrbitControls.js</code></a>
ont des chemins relatifs tels que :
</p>
<pre class="prettyprint">import * as THREE from '../../../build/three.module.js';
</pre>
<p>
Utiliser la même structure permet de s'assurer, lors de l'importation de
Three.js et d'une autre bibliothèque d'exemple, qu'ils référenceront le même fichier
three.module.js.
</p>
<pre class="prettyprint">import * as THREE from './someFolder/build/three.module.js';
import {OrbitControls} from './someFolder/addons/controls/OrbitControls.js';
</pre>
<p>Cela est valable aussi lors de l'utilisation d'un CDN. Assurez vous que vos chemins versThis includes when using a CDN. Be <code class="notranslate" translate="no">three.modules.js</code> terminent par
<code class="notranslate" translate="no">/build/three.modules.js</code>. Par exemple :</p>
<pre class="prettyprint">import * as THREE from 'https://unpkg.com/three@0.108.0/<b>build/three.module.js</b>';
import {OrbitControls} from 'https://unpkg.com/three@0.108.0/addons/controls/OrbitControls.js';
</pre>
</div>
</div>
</div>
</div>
<script src="/manual/resources/prettify.js"></script>
<script src="/manual/resources/lesson.js"></script>
</body></html>