scenegraph.html 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. <!DOCTYPE html><html lang="fr"><head>
  2. <meta charset="utf-8">
  3. <title>Graphe de scène</title>
  4. <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
  5. <meta name="twitter:card" content="summary_large_image">
  6. <meta name="twitter:site" content="@threejs">
  7. <meta name="twitter:title" content="Three.js – Graphe de scène">
  8. <meta property="og:image" content="https://threejs.org/files/share.png">
  9. <link rel="shortcut icon" href="../../files/favicon_white.ico" media="(prefers-color-scheme: dark)">
  10. <link rel="shortcut icon" href="../../files/favicon.ico" media="(prefers-color-scheme: light)">
  11. <link rel="stylesheet" href="../resources/lesson.css">
  12. <link rel="stylesheet" href="../resources/lang.css">
  13. <script type="importmap">
  14. {
  15. "imports": {
  16. "three": "../../build/three.module.js"
  17. }
  18. }
  19. </script>
  20. </head>
  21. <body>
  22. <div class="container">
  23. <div class="lesson-title">
  24. <h1>Graphe de scène</h1>
  25. </div>
  26. <div class="lesson">
  27. <div class="lesson-main">
  28. <p>Cet article fait partie d'une série d'articles sur three.js. Le
  29. premier article est <a href="fundamentals.html">les bases de three.js</a>. Si
  30. vous ne l'avez pas encore lu, vous pourriez envisager de commencer par là.</p>
  31. <p>Le cœur de Three.js est sans doute son graphe de scène. Un graphe de scène dans un moteur 3D
  32. est une hiérarchie de nœuds dans un graphe où chaque nœud représente
  33. un espace local.</p>
  34. <p><img src="../resources/images/scenegraph-generic.svg" align="center"></p>
  35. <p>C'est un peu abstrait, alors essayons de donner quelques exemples.</p>
  36. <p>Un exemple pourrait être le système solaire : soleil, terre, lune.</p>
  37. <p><img src="../resources/images/scenegraph-solarsystem.svg" align="center"></p>
  38. <p>La Terre tourne autour du Soleil. La Lune tourne autour de la Terre. La Lune
  39. se déplace en cercle autour de la Terre. Du point de
  40. vue de la Lune, elle tourne dans l'« espace local » de la Terre. Même si
  41. son mouvement par rapport au Soleil est une courbe folle ressemblant à un spirographe, du point de vue de la Lune, elle n'a qu'à se soucier de tourner
  42. autour de l'espace local de la Terre.</p>
  43. <p></p><div class="threejs_diagram_container">
  44. <iframe class="threejs_diagram " style="width: 400px; height: 300px;" src="/manual/foo/../resources/moon-orbit.html"></iframe>
  45. </div>
  46. <p></p>
  47. <p>Pour le voir autrement, vous qui vivez sur Terre n'avez pas à penser
  48. à la rotation de la Terre sur son axe ni à sa rotation autour du
  49. Soleil. Vous marchez, conduisez, nagez ou courez comme si la Terre
  50. ne bougeait ni ne tournait pas du tout. Vous marchez, conduisez, nagez, courez et vivez
  51. dans l'« espace local » de la Terre, même si, par rapport au Soleil, vous tournez
  52. autour de la Terre à environ 1600 kilomètres par heure et autour
  53. du Soleil à environ 108 000 kilomètres par heure. Votre position dans le système solaire
  54. est similaire à celle de la Lune ci-dessus, mais vous n'avez pas à vous en soucier.
  55. Vous vous préoccupez simplement de votre position par rapport à la Terre dans son
  56. « espace local ».</p>
  57. <p>Prenons les choses étape par étape. Imaginez que nous voulions faire
  58. un diagramme du soleil, de la terre et de la lune. Nous commencerons par le soleil en
  59. créant simplement une sphère et en la plaçant à l'origine. Remarque : Nous utilisons
  60. le soleil, la terre, la lune pour illustrer comment utiliser un graphe de scène. Bien sûr,
  61. le vrai soleil, la terre et la lune utilisent la physique, mais pour nos besoins, nous allons
  62. simuler cela avec un graphe de scène.</p>
  63. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">// un tableau d'objets dont la rotation doit être mise à jour
  64. const objects = [];
  65. // utiliser une seule sphère pour tout
  66. const radius = 1;
  67. const widthSegments = 6;
  68. const heightSegments = 6;
  69. const sphereGeometry = new THREE.SphereGeometry(
  70. radius, widthSegments, heightSegments);
  71. const sunMaterial = new THREE.MeshPhongMaterial({emissive: 0xFFFF00});
  72. const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
  73. sunMesh.scale.set(5, 5, 5); // agrandir le soleil
  74. scene.add(sunMesh);
  75. objects.push(sunMesh);
  76. </pre>
  77. <p>Nous utilisons une sphère avec très peu de polygones. Seulement 6 subdivisions autour de son équateur.
  78. C'est pour qu'il soit facile de voir la rotation.</p>
  79. <p>Nous allons réutiliser la même sphère pour tout, nous allons donc définir une échelle
  80. de 5x pour le maillage du soleil.</p>
  81. <p>Nous définissons également la propriété <code class="notranslate" translate="no">emissive</code> du matériau phong en jaune. La propriété emissive d'un matériau phong est essentiellement la couleur qui sera dessinée sans lumière frappant
  82. la surface. La lumière est ajoutée à cette couleur.</p>
  83. <p>Plaçons également une seule lumière ponctuelle au centre de la scène. Nous reviendrons plus tard sur
  84. les détails des lumières ponctuelles, mais pour l'instant, la version simple est qu'une lumière ponctuelle
  85. représente la lumière qui émane d'un point unique.</p>
  86. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">{
  87. const color = 0xFFFFFF;
  88. const intensity = 500;
  89. const light = new THREE.PointLight(color, intensity);
  90. scene.add(light);
  91. }
  92. </pre>
  93. <p>Pour faciliter la visualisation, nous allons placer la caméra juste au-dessus de l'origine,
  94. regardant vers le bas. La façon la plus simple de faire cela est d'utiliser la fonction <code class="notranslate" translate="no">lookAt</code>. La fonction <code class="notranslate" translate="no">lookAt</code>
  95. orientera la caméra depuis sa position pour « regarder » la position
  96. que nous lui passons. Cependant, avant de faire cela, nous devons indiquer à la caméra
  97. dans quelle direction se trouve le haut de la caméra, ou plutôt quelle direction est le « haut » pour la
  98. caméra. Dans la plupart des situations, Y positif vers le haut est suffisant, mais puisque
  99. nous regardons directement vers le bas, nous devons indiquer à la caméra que Z positif est vers le haut.</p>
  100. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  101. camera.position.set(0, 50, 0);
  102. camera.up.set(0, 0, 1);
  103. camera.lookAt(0, 0, 0);
  104. </pre>
  105. <p>Dans la boucle de rendu, adaptée des exemples précédents, nous faisons pivoter tous
  106. les objets de notre tableau <code class="notranslate" translate="no">objects</code> avec ce code.</p>
  107. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">objects.forEach((obj) =&gt; {
  108. obj.rotation.y = time;
  109. });
  110. </pre>
  111. <p>Comme nous avons ajouté le <code class="notranslate" translate="no">sunMesh</code> au tableau <code class="notranslate" translate="no">objects</code>, il va tourner.</p>
  112. <p></p><div translate="no" class="threejs_example_container notranslate">
  113. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/scenegraph-sun.html"></iframe></div>
  114. <a class="threejs_center" href="/manual/examples/scenegraph-sun.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
  115. </div>
  116. <p></p>
  117. <p>Maintenant, ajoutons la Terre.</p>
  118. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const earthMaterial = new THREE.MeshPhongMaterial({color: 0x2233FF, emissive: 0x112244});
  119. const earthMesh = new THREE.Mesh(sphereGeometry, earthMaterial);
  120. earthMesh.position.x = 10;
  121. scene.add(earthMesh);
  122. objects.push(earthMesh);
  123. </pre>
  124. <p>Nous créons un matériau bleu, mais nous lui donnons une petite quantité de bleu <em>émissif</em>
  125. afin qu'il ressorte sur notre fond noir.</p>
  126. <p>Nous utilisons la même <code class="notranslate" translate="no">sphereGeometry</code> avec notre nouveau <code class="notranslate" translate="no">earthMaterial</code> bleu pour créer
  127. un <code class="notranslate" translate="no">earthMesh</code>. Nous le positionnons à 10 unités à gauche du soleil
  128. et l'ajoutons à la scène. Comme nous l'avons ajouté à notre tableau <code class="notranslate" translate="no">objects</code>, il tournera aussi.</p>
  129. <p></p><div translate="no" class="threejs_example_container notranslate">
  130. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/scenegraph-sun-earth.html"></iframe></div>
  131. <a class="threejs_center" href="/manual/examples/scenegraph-sun-earth.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
  132. </div>
  133. <p></p>
  134. <p>Vous pouvez voir que le soleil et la terre tournent, mais la terre ne
  135. tourne pas autour du soleil. Faisons de la terre un enfant du soleil</p>
  136. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">-scene.add(earthMesh);
  137. +sunMesh.add(earthMesh);
  138. </pre>
  139. <p>et...</p>
  140. <p></p><div translate="no" class="threejs_example_container notranslate">
  141. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/scenegraph-sun-earth-orbit.html"></iframe></div>
  142. <a class="threejs_center" href="/manual/examples/scenegraph-sun-earth-orbit.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
  143. </div>
  144. <p></p>
  145. <p>Que s'est-il passé ? Pourquoi la Terre a-t-elle la même taille que le Soleil et pourquoi est-elle si loin ?
  146. J'ai en fait dû déplacer la caméra de 50 unités au-dessus à 150 unités au-dessus pour voir la Terre.</p>
  147. <p>Nous avons fait du <code class="notranslate" translate="no">earthMesh</code> un enfant du <code class="notranslate" translate="no">sunMesh</code>. L'échelle du <code class="notranslate" translate="no">sunMesh</code> est
  148. réglée à 5x avec <code class="notranslate" translate="no">sunMesh.scale.set(5, 5, 5)</code>. Cela signifie que
  149. l'espace local du <code class="notranslate" translate="no">sunMesh</code> est 5 fois plus grand. Tout ce qui est placé dans cet espace
  150. sera multiplié par 5. Cela signifie que la terre est maintenant 5 fois plus grande et
  151. que sa distance par rapport au soleil (<code class="notranslate" translate="no">earthMesh.position.x = 10</code>) est également
  152. multipliée par 5.</p>
  153. <p> Notre graphe de scène ressemble actuellement à ceci</p>
  154. <p><img src="../resources/images/scenegraph-sun-earth.svg" align="center"></p>
  155. <p>Pour corriger cela, ajoutons un nœud de graphe de scène vide. Nous allons rendre le soleil et la terre
  156. enfants de ce nœud.</p>
  157. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const solarSystem = new THREE.Object3D();
  158. +scene.add(solarSystem);
  159. +objects.push(solarSystem);
  160. const sunMaterial = new THREE.MeshPhongMaterial({emissive: 0xFFFF00});
  161. const sunMesh = new THREE.Mesh(sphereGeometry, sunMaterial);
  162. sunMesh.scale.set(5, 5, 5);
  163. -scene.add(sunMesh);
  164. +solarSystem.add(sunMesh);
  165. objects.push(sunMesh);
  166. const earthMaterial = new THREE.MeshPhongMaterial({color: 0x2233FF, emissive: 0x112244});
  167. const earthMesh = new THREE.Mesh(sphereGeometry, earthMaterial);
  168. earthMesh.position.x = 10;
  169. -sunMesh.add(earthMesh);
  170. +solarSystem.add(earthMesh);
  171. objects.push(earthMesh);
  172. </pre>
  173. <p>Ici, nous avons créé un <a href="/docs/#api/en/core/Object3D"><code class="notranslate" translate="no">Object3D</code></a>. Comme un <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a>, c'est aussi un nœud dans le graphe de scène,
  174. mais contrairement à un <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a>, il n'a ni matériau ni géométrie. Il représente simplement un espace local.</p>
  175. <p>Notre nouveau graphe de scène ressemble à ceci</p>
  176. <p><img src="../resources/images/scenegraph-sun-earth-fixed.svg" align="center"></p>
  177. <p>Le <code class="notranslate" translate="no">sunMesh</code> et le <code class="notranslate" translate="no">earthMesh</code> sont tous deux enfants du <code class="notranslate" translate="no">solarSystem</code>. Les 3
  178. tournent et maintenant, parce que le <code class="notranslate" translate="no">earthMesh</code> n'est pas un enfant du <code class="notranslate" translate="no">sunMesh</code>,
  179. il n'est plus mis à l'échelle par 5x.</p>
  180. <p></p><div translate="no" class="threejs_example_container notranslate">
  181. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/scenegraph-sun-earth-orbit-fixed.html"></iframe></div>
  182. <a class="threejs_center" href="/manual/examples/scenegraph-sun-earth-orbit-fixed.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
  183. </div>
  184. <p></p>
  185. <p>Bien mieux. La Terre est plus petite que le soleil et elle tourne autour du soleil
  186. tout en tournant sur elle-même.</p>
  187. <p>En continuant sur ce même schéma, ajoutons une lune.</p>
  188. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const earthOrbit = new THREE.Object3D();
  189. +earthOrbit.position.x = 10;
  190. +solarSystem.add(earthOrbit);
  191. +objects.push(earthOrbit);
  192. const earthMaterial = new THREE.MeshPhongMaterial({color: 0x2233FF, emissive: 0x112244});
  193. const earthMesh = new THREE.Mesh(sphereGeometry, earthMaterial);
  194. -earthMesh.position.x = 10; // notez que ce décalage est déjà défini dans l'objet THREE.Object3D parent "earthOrbit"
  195. -solarSystem.add(earthMesh);
  196. +earthOrbit.add(earthMesh);
  197. objects.push(earthMesh);
  198. +const moonOrbit = new THREE.Object3D();
  199. +moonOrbit.position.x = 2;
  200. +earthOrbit.add(moonOrbit);
  201. +const moonMaterial = new THREE.MeshPhongMaterial({color: 0x888888, emissive: 0x222222});
  202. +const moonMesh = new THREE.Mesh(sphereGeometry, moonMaterial);
  203. +moonMesh.scale.set(.5, .5, .5);
  204. +moonOrbit.add(moonMesh);
  205. +objects.push(moonMesh);
  206. </pre>
  207. <p>Encore une fois, nous avons ajouté d'autres nœuds de graphe de scène invisibles. Le premier, un <a href="/docs/#api/en/core/Object3D"><code class="notranslate" translate="no">Object3D</code></a> appelé <code class="notranslate" translate="no">earthOrbit</code>
  208. et auquel nous avons ajouté le <code class="notranslate" translate="no">earthMesh</code> et le <code class="notranslate" translate="no">moonOrbit</code>, également nouveau. Nous avons ensuite ajouté le <code class="notranslate" translate="no">moonMesh</code>
  209. au <code class="notranslate" translate="no">moonOrbit</code>. Le nouveau graphe de scène ressemble à ceci.</p>
  210. <p><img src="../resources/images/scenegraph-sun-earth-moon.svg" align="center"></p>
  211. <p>et voici le résultat</p>
  212. <p></p><div translate="no" class="threejs_example_container notranslate">
  213. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/scenegraph-sun-earth-moon.html"></iframe></div>
  214. <a class="threejs_center" href="/manual/examples/scenegraph-sun-earth-moon.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
  215. </div>
  216. <p></p>
  217. <p>Vous pouvez voir que la lune suit le motif spirographe montré en haut
  218. de cet article, mais nous n'avons pas eu à le calculer manuellement. Nous avons simplement
  219. configuré notre graphe de scène pour qu'il le fasse pour nous.</p>
  220. <p>Il est souvent utile de dessiner quelque chose pour visualiser les nœuds dans le graphe de scène.
  221. Three.js dispose de quelques ummmm, helpers utiles pour ummm, ... aider à cela.</p>
  222. <p>L'un s'appelle <a href="/docs/#api/en/helpers/AxesHelper"><code class="notranslate" translate="no">AxesHelper</code></a>. Il dessine 3 lignes représentant les axes
  223. locaux <span style="color:red">X</span>,
  224. <span style="color:green">Y</span> et
  225. <span style="color:blue">Z</span>. Ajoutons-en un à chaque nœud que nous
  226. avons créé.</p>
  227. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">// ajouter un AxesHelper à chaque nœud
  228. objects.forEach((node) =&gt; {
  229. const axes = new THREE.AxesHelper();
  230. axes.material.depthTest = false;
  231. axes.renderOrder = 1;
  232. node.add(axes);
  233. });
  234. </pre>
  235. <p>Dans notre cas, nous voulons que les axes apparaissent même s'ils sont à l'intérieur des sphères.
  236. Pour ce faire, nous réglons la propriété <code class="notranslate" translate="no">depthTest</code> de leur matériau sur false, ce qui signifie qu'ils ne
  237. vérifieront pas s'ils dessinent derrière quelque chose d'autre. Nous réglons également
  238. leur <code class="notranslate" translate="no">renderOrder</code> à 1 (la valeur par défaut est 0) afin qu'ils soient dessinés après
  239. toutes les sphères. Sinon, une sphère pourrait dessiner par-dessus et les masquer.</p>
  240. <p></p><div translate="no" class="threejs_example_container notranslate">
  241. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/scenegraph-sun-earth-moon-axes.html"></iframe></div>
  242. <a class="threejs_center" href="/manual/examples/scenegraph-sun-earth-moon-axes.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
  243. </div>
  244. <p></p>
  245. <p>Nous pouvons voir les axes
  246. <span style="color:red">x (rouge)</span> et
  247. <span style="color:blue">z (bleu)</span>. Comme nous regardons
  248. directement vers le bas et que chacun de nos objets ne tourne que autour de son
  249. axe y, nous ne voyons pas beaucoup les axes <span style="color:green">y (vert)</span>.</p>
  250. <p>Il peut être difficile d'en voir certains car il y a 2 paires d'axes qui se chevauchent. Le <code class="notranslate" translate="no">sunMesh</code>
  251. et le <code class="notranslate" translate="no">solarSystem</code> sont tous deux à la même position. De même, le <code class="notranslate" translate="no">earthMesh</code> et
  252. le <code class="notranslate" translate="no">earthOrbit</code> sont à la même position. Ajoutons quelques contrôles simples pour nous permettre
  253. de les activer/désactiver pour chaque nœud.
  254. Tant qu'on y est, ajoutons également un autre helper appelé <a href="/docs/#api/en/helpers/GridHelper"><code class="notranslate" translate="no">GridHelper</code></a>. Il
  255. crée une grille 2D sur le plan XZ. Par défaut, la grille est de 10x10 unités.</p>
  256. <p>Nous allons également utiliser <a href="https://github.com/georgealways/lil-gui">lil-gui</a>, une bibliothèque d'interface utilisateur
  257. très populaire dans les projets three.js. lil-gui prend un
  258. objet et le nom d'une propriété sur cet objet et, en fonction du type de la propriété,
  259. crée automatiquement une interface utilisateur pour manipuler cette propriété.</p>
  260. <p>Nous voulons créer à la fois un <a href="/docs/#api/en/helpers/GridHelper"><code class="notranslate" translate="no">GridHelper</code></a> et un <a href="/docs/#api/en/helpers/AxesHelper"><code class="notranslate" translate="no">AxesHelper</code></a> pour chaque nœud. Nous avons besoin
  261. d'une étiquette pour chaque nœud, nous allons donc nous débarrasser de l'ancienne boucle et passer à l'appel
  262. d'une fonction pour ajouter les helpers pour chaque nœud</p>
  263. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">-// ajouter un AxesHelper à chaque nœud
  264. -objects.forEach((node) =&gt; {
  265. - const axes = new THREE.AxesHelper();
  266. - axes.material.depthTest = false;
  267. - axes.renderOrder = 1;
  268. - node.add(axes);
  269. -});
  270. +function makeAxisGrid(node, label, units) {
  271. + const helper = new AxisGridHelper(node, units);
  272. + gui.add(helper, 'visible').name(label);
  273. +}
  274. +
  275. +makeAxisGrid(solarSystem, 'solarSystem', 25);
  276. +makeAxisGrid(sunMesh, 'sunMesh');
  277. +makeAxisGrid(earthOrbit, 'earthOrbit');
  278. +makeAxisGrid(earthMesh, 'earthMesh');
  279. +makeAxisGrid(moonOrbit, 'moonOrbit');
  280. +makeAxisGrid(moonMesh, 'moonMesh');
  281. </pre>
  282. <p><code class="notranslate" translate="no">makeAxisGrid</code> crée un <code class="notranslate" translate="no">AxisGridHelper</code>, une classe que nous allons créer
  283. pour rendre lil-gui heureux. Comme indiqué ci-dessus, lil-gui
  284. créera automatiquement une interface utilisateur qui manipule la propriété nommée
  285. de certains objets. Il créera une interface utilisateur différente en fonction du type
  286. de propriété. Nous voulons qu'il crée une case à cocher, nous devons donc spécifier
  287. une propriété <code class="notranslate" translate="no">bool</code>. Mais, nous voulons que les axes et la grille
  288. apparaissent/disparaissent en fonction d'une seule propriété, nous allons donc créer une classe
  289. qui a un getter et un setter pour une propriété. De cette façon, nous pouvons laisser lil-gui
  290. penser qu'il manipule une seule propriété, mais en interne, nous pouvons définir
  291. la propriété visible à la fois de l'<a href="/docs/#api/en/helpers/AxesHelper"><code class="notranslate" translate="no">AxesHelper</code></a> et du <a href="/docs/#api/en/helpers/GridHelper"><code class="notranslate" translate="no">GridHelper</code></a> pour un nœud.</p>
  292. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">// Active/désactive la visibilité des axes et de la grille
  293. // lil-gui nécessite une propriété qui renvoie un booléen
  294. // pour décider de créer une case à cocher, nous créons donc un setter
  295. // et un getter pour `visible` que nous pouvons dire à lil-gui
  296. // de regarder.
  297. class AxisGridHelper {
  298. constructor(node, units = 10) {
  299. const axes = new THREE.AxesHelper();
  300. axes.material.depthTest = false;
  301. axes.renderOrder = 2; // après la grille
  302. node.add(axes);
  303. const grid = new THREE.GridHelper(units, units);
  304. grid.material.depthTest = false;
  305. grid.renderOrder = 1;
  306. node.add(grid);
  307. this.grid = grid;
  308. this.axes = axes;
  309. this.visible = false;
  310. }
  311. get visible() {
  312. return this._visible;
  313. }
  314. set visible(v) {
  315. this._visible = v;
  316. this.grid.visible = v;
  317. this.axes.visible = v;
  318. }
  319. }
  320. </pre>
  321. <p>Une chose à noter est que nous avons défini le <code class="notranslate" translate="no">renderOrder</code> de l'<a href="/docs/#api/en/helpers/AxesHelper"><code class="notranslate" translate="no">AxesHelper</code></a>
  322. à 2 et celui du <a href="/docs/#api/en/helpers/GridHelper"><code class="notranslate" translate="no">GridHelper</code></a> à 1 afin que les axes soient dessinés après la grille.
  323. Sinon, la grille pourrait écraser les axes.</p>
  324. <p></p><div translate="no" class="threejs_example_container notranslate">
  325. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/scenegraph-sun-earth-moon-axes-grids.html"></iframe></div>
  326. <a class="threejs_center" href="/manual/examples/scenegraph-sun-earth-moon-axes-grids.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
  327. </div>
  328. <p></p>
  329. <p>Activez le <code class="notranslate" translate="no">solarSystem</code> et vous verrez que la terre se trouve exactement à 10
  330. unités du centre, comme nous l'avons réglé ci-dessus. Vous pouvez voir comment la
  331. terre se trouve dans l'<em>espace local</em> du <code class="notranslate" translate="no">solarSystem</code>. De même, si vous
  332. activez l'<code class="notranslate" translate="no">earthOrbit</code>, vous verrez que la lune se trouve exactement à 2 unités
  333. du centre de l'<em>espace local</em> de l'<code class="notranslate" translate="no">earthOrbit</code>.</p>
  334. <p>Quelques autres exemples de graphes de scène. Une automobile dans un monde de jeu simple pourrait avoir un graphe de scène comme celui-ci</p>
  335. <p><img src="../resources/images/scenegraph-car.svg" align="center"></p>
  336. <p>Si vous déplacez la carrosserie de la voiture, toutes les roues bougeront avec elle. Si vous vouliez que la carrosserie
  337. rebondisse séparément des roues, vous pourriez rendre la carrosserie et les roues enfants d'un nœud « châssis »
  338. qui représente le châssis de la voiture.</p>
  339. <p>Un autre exemple est un humain dans un monde de jeu.</p>
  340. <p><img src="../resources/images/scenegraph-human.svg" align="center"></p>
  341. <p>Vous pouvez voir que le graphe de scène devient assez complexe pour un humain. En fait,
  342. le graphe de scène ci-dessus est simplifié. Par exemple, vous pourriez l'étendre
  343. pour couvrir chaque doigt (au moins 28 nœuds supplémentaires) et chaque orteil
  344. (encore 28 nœuds) plus ceux pour le visage et la mâchoire, les yeux et peut-être plus.</p>
  345. <p>Créons un graphe de scène semi-complexe. Nous allons faire un char. Le char aura
  346. 6 roues et une tourelle. Le char suivra un chemin. Il y aura une sphère qui
  347. se déplacera et le char ciblera la sphère.</p>
  348. <p>Voici le graphe de scène. Les maillages sont colorés en vert, les <a href="/docs/#api/en/core/Object3D"><code class="notranslate" translate="no">Object3D</code></a> en bleu,
  349. les lumières en or et les caméras en violet. Une caméra n'a pas été ajoutée
  350. au graphe de scène.</p>
  351. <div class="threejs_center"><img src="../resources/images/scenegraph-tank.svg" style="width: 800px;"></div>
  352. <p>Regardez le code pour voir la configuration de tous ces nœuds.</p>
  353. <p>Pour la cible, la chose que le char vise, il y a un <code class="notranslate" translate="no">targetOrbit</code>
  354. (<a href="/docs/#api/en/core/Object3D"><code class="notranslate" translate="no">Object3D</code></a>) qui tourne simplement comme l'<code class="notranslate" translate="no">earthOrbit</code> ci-dessus. Un
  355. <code class="notranslate" translate="no">targetElevation</code> (<a href="/docs/#api/en/core/Object3D"><code class="notranslate" translate="no">Object3D</code></a>), qui est un enfant du <code class="notranslate" translate="no">targetOrbit</code>, fournit un
  356. décalage par rapport au <code class="notranslate" translate="no">targetOrbit</code> et une élévation de base. Un autre
  357. <a href="/docs/#api/en/core/Object3D"><code class="notranslate" translate="no">Object3D</code></a> appelé <code class="notranslate" translate="no">targetBob</code> est enfant de celui-ci et il monte et descend simplement
  358. par rapport au <code class="notranslate" translate="no">targetElevation</code>. Enfin, il y a le <code class="notranslate" translate="no">targetMesh</code> qui est juste un cube que nous
  359. faisons pivoter et dont nous changeons les couleurs</p>
  360. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">// déplacer la cible
  361. targetOrbit.rotation.y = time * .27;
  362. targetBob.position.y = Math.sin(time * 2) * 4;
  363. targetMesh.rotation.x = time * 7;
  364. targetMesh.rotation.y = time * 13;
  365. targetMaterial.emissive.setHSL(time * 10 % 1, 1, .25);
  366. targetMaterial.color.setHSL(time * 10 % 1, 1, .25);
  367. </pre>
  368. <p>Pour le char, il y a un <a href="/docs/#api/en/core/Object3D"><code class="notranslate" translate="no">Object3D</code></a> appelé <code class="notranslate" translate="no">tank</code> qui est utilisé pour déplacer tout ce qui se
  369. trouve en dessous. Le code utilise une <a href="/docs/#api/en/extras/curves/SplineCurve"><code class="notranslate" translate="no">SplineCurve</code></a> à laquelle il peut demander les positions
  370. le long de cette courbe. 0.0 est le début de la courbe. 1.0 est la fin de la courbe. Il
  371. demande la position actuelle où il place le char. Il demande ensuite une
  372. position légèrement plus loin le long de la courbe et l'utilise pour orienter le char dans cette
  373. direction en utilisant <a href="/docs/#api/en/core/Object3D.lookAt"><code class="notranslate" translate="no">Object3D.lookAt</code></a>.</p>
  374. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const tankPosition = new THREE.Vector2();
  375. const tankTarget = new THREE.Vector2();
  376. ...
  377. // déplacer le char
  378. const tankTime = time * .05;
  379. curve.getPointAt(tankTime % 1, tankPosition);
  380. curve.getPointAt((tankTime + 0.01) % 1, tankTarget);
  381. tank.position.set(tankPosition.x, 0, tankPosition.y);
  382. tank.lookAt(tankTarget.x, 0, tankTarget.y);
  383. </pre>
  384. <p>La tourelle sur le dessus du char est déplacée automatiquement en étant un enfant
  385. du char. Pour la pointer vers la cible, nous demandons simplement la position mondiale de la cible
  386. et ensuite utilisons à nouveau <a href="/docs/#api/en/core/Object3D.lookAt"><code class="notranslate" translate="no">Object3D.lookAt</code></a>.</p>
  387. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const targetPosition = new THREE.Vector3();
  388. ...
  389. // orienter la tourelle vers la cible
  390. targetMesh.getWorldPosition(targetPosition);
  391. turretPivot.lookAt(targetPosition);
  392. </pre>
  393. <p>Il y a une <code class="notranslate" translate="no">turretCamera</code> qui est un enfant du <code class="notranslate" translate="no">turretMesh</code>, donc
  394. elle montera et descendra et tournera avec la tourelle. Nous la faisons
  395. viser la cible.</p>
  396. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">// faire pointer la turretCamera vers la cible
  397. turretCamera.lookAt(targetPosition);
  398. </pre>
  399. <p>Il y a aussi un <code class="notranslate" translate="no">targetCameraPivot</code> qui est un enfant du <code class="notranslate" translate="no">targetBob</code>, donc il flotte
  400. autour de la cible. Nous le faisons viser le char. Son but est de permettre à la
  401. <code class="notranslate" translate="no">targetCamera</code> d'être décalée par rapport à la cible elle-même. Si nous avions fait de la caméra
  402. un enfant du <code class="notranslate" translate="no">targetBob</code> et l'avions simplement fait pointer, elle serait à l'intérieur de la
  403. cible.</p>
  404. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">// faire pointer le targetCameraPivot vers le char
  405. tank.getWorldPosition(targetPosition);
  406. targetCameraPivot.lookAt(targetPosition);
  407. </pre>
  408. <p>Enfin, nous faisons tourner toutes les roues</p>
  409. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">wheelMeshes.forEach((obj) =&gt; {
  410. obj.rotation.x = time * 3;
  411. });
  412. </pre>
  413. <p>Pour les caméras, nous avons configuré un tableau de toutes les 4 caméras au moment de l'initialisation avec des descriptions.</p>
  414. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const cameras = [
  415. { cam: camera, desc: 'caméra détachée', },
  416. { cam: turretCamera, desc: 'sur tourelle regardant la cible', },
  417. { cam: targetCamera, desc: 'près de la cible regardant le char', },
  418. { cam: tankCamera, desc: 'au-dessus de l'arrière du char', },
  419. ];
  420. const infoElem = document.querySelector('#info');
  421. </pre>
  422. <p>et passons en revue nos caméras au moment du rendu.</p>
  423. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const camera = cameras[time * .25 % cameras.length | 0];
  424. infoElem.textContent = camera.desc;
  425. </pre>
  426. <p></p><div translate="no" class="threejs_example_container notranslate">
  427. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/scenegraph-tank.html"></iframe></div>
  428. <a class="threejs_center" href="/manual/examples/scenegraph-tank.html" target="_blank">cliquez ici pour ouvrir dans une fenêtre séparée</a>
  429. </div>
  430. <p></p>
  431. <p>J'espère que cela vous donne une idée du fonctionnement des graphes de scène et de la manière dont vous pourriez les utiliser.
  432. Créer des nœuds <a href="/docs/#api/en/core/Object3D"><code class="notranslate" translate="no">Object3D</code></a> et les rendre parents d'autres objets est une étape importante pour bien utiliser
  433. un moteur 3D comme three.js. Souvent, il peut sembler qu'il soit nécessaire de faire des calculs mathématiques complexes
  434. pour faire bouger et pivoter quelque chose comme vous le souhaitez. Par exemple, sans graphe de scène,
  435. calculer le mouvement de la lune ou où placer les roues de la voiture par rapport à sa
  436. carrosserie serait très compliqué, mais en utilisant un graphe de scène, cela devient beaucoup plus facile.</p>
  437. <p><a href="materials.html">Ensuite, nous aborderons les matériaux</a>.</p>
  438. </div>
  439. </div>
  440. </div>
  441. <script src="../resources/prettify.js"></script>
  442. <script src="../resources/lesson.js"></script>
  443. </body></html>
粤ICP备19079148号