fundamentals.html 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. <!DOCTYPE html><html lang="en"><head>
  2. <meta charset="utf-8">
  3. <title>Fundamentals</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 – Fundamentals">
  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="/manual/resources/lesson.css">
  12. <link rel="stylesheet" href="/manual/resources/lang.css">
  13. <!-- Import maps polyfill -->
  14. <!-- Remove this when import maps will be widely supported -->
  15. <script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"></script>
  16. <script type="importmap">
  17. {
  18. "imports": {
  19. "three": "../../build/three.module.js"
  20. }
  21. }
  22. </script>
  23. </head>
  24. <body>
  25. <div class="container">
  26. <div class="lesson-title">
  27. <h1>Fundamentals</h1>
  28. </div>
  29. <div class="lesson">
  30. <div class="lesson-main">
  31. <p>This is the first article in a series of articles about three.js.
  32. <a href="https://threejs.org">Three.js</a> is a 3D library that tries to make
  33. it as easy as possible to get 3D content on a webpage.</p>
  34. <p>Three.js is often confused with WebGL since more often than
  35. not, but not always, three.js uses WebGL to draw 3D.
  36. <a href="https://webglfundamentals.org">WebGL is a very low-level system that only draws points, lines, and triangles</a>.
  37. To do anything useful with WebGL generally requires quite a bit of
  38. code and that is where three.js comes in. It handles stuff
  39. like scenes, lights, shadows, materials, textures, 3d math, all things that you'd
  40. have to write yourself if you were to use WebGL directly.</p>
  41. <p>These tutorials assume you already know JavaScript and, for the
  42. most part they will use ES6 style. <a href="prerequisites.html">See here for a
  43. terse list of things you're expected to already know</a>.
  44. Most browsers that support three.js are auto-updated so most users should
  45. be able to run this code. If you'd like to make this code run
  46. on really old browsers look into a transpiler like <a href="https://babeljs.io">Babel</a>.
  47. Of course users running really old browsers probably have machines
  48. that can't run three.js.</p>
  49. <p>When learning most programming languages the first thing people
  50. do is make the computer print <code class="notranslate" translate="no">"Hello World!"</code>. For 3D one
  51. of the most common first things to do is to make a 3D cube.
  52. So let's start with "Hello Cube!"</p>
  53. <p>Before we get started let's try to give you an idea of the structure
  54. of a three.js app. A three.js app requires you to create a bunch of
  55. objects and connect them together. Here's a diagram that represents
  56. a small three.js app</p>
  57. <div class="threejs_center"><img src="../resources/images/threejs-structure.svg" style="width: 768px;"></div>
  58. <p>Things to notice about the diagram above.</p>
  59. <ul>
  60. <li><p>There is a <a href="/docs/#api/en/constants/Renderer"><code class="notranslate" translate="no">Renderer</code></a>. This is arguably the main object of three.js. You pass a
  61. <a href="/docs/#api/en/scenes/Scene"><code class="notranslate" translate="no">Scene</code></a> and a <a href="/docs/#api/en/cameras/Camera"><code class="notranslate" translate="no">Camera</code></a> to a <a href="/docs/#api/en/constants/Renderer"><code class="notranslate" translate="no">Renderer</code></a> and it renders (draws) the portion of
  62. the 3D scene that is inside the <em>frustum</em> of the camera as a 2D image to a
  63. canvas.</p>
  64. </li>
  65. <li><p>There is a <a href="scenegraph.html">scenegraph</a> which is a tree like
  66. structure, consisting of various objects like a <a href="/docs/#api/en/scenes/Scene"><code class="notranslate" translate="no">Scene</code></a> object, multiple
  67. <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a> objects, <a href="/docs/#api/en/lights/Light"><code class="notranslate" translate="no">Light</code></a> objects, <a href="/docs/#api/en/objects/Group"><code class="notranslate" translate="no">Group</code></a>, <a href="/docs/#api/en/core/Object3D"><code class="notranslate" translate="no">Object3D</code></a>, and <a href="/docs/#api/en/cameras/Camera"><code class="notranslate" translate="no">Camera</code></a> objects. A
  68. <a href="/docs/#api/en/scenes/Scene"><code class="notranslate" translate="no">Scene</code></a> object defines the root of the scenegraph and contains properties like
  69. the background color and fog. These objects define a hierarchical parent/child
  70. tree like structure and represent where objects appear and how they are
  71. oriented. Children are positioned and oriented relative to their parent. For
  72. example the wheels on a car might be children of the car so that moving and
  73. orienting the car's object automatically moves the wheels. You can read more
  74. about this in <a href="scenegraph.html">the article on scenegraphs</a>.</p>
  75. <p>Note in the diagram <a href="/docs/#api/en/cameras/Camera"><code class="notranslate" translate="no">Camera</code></a> is half in half out of the scenegraph. This is to
  76. represent that in three.js, unlike the other objects, a <a href="/docs/#api/en/cameras/Camera"><code class="notranslate" translate="no">Camera</code></a> does not have
  77. to be in the scenegraph to function. Just like other objects, a <a href="/docs/#api/en/cameras/Camera"><code class="notranslate" translate="no">Camera</code></a>, as a
  78. child of some other object, will move and orient relative to its parent object.
  79. There is an example of putting multiple <a href="/docs/#api/en/cameras/Camera"><code class="notranslate" translate="no">Camera</code></a> objects in a scenegraph at
  80. the end of <a href="scenegraph.html">the article on scenegraphs</a>.</p>
  81. </li>
  82. <li><p><a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a> objects represent drawing a specific <code class="notranslate" translate="no">Geometry</code> with a specific
  83. <a href="/docs/#api/en/materials/Material"><code class="notranslate" translate="no">Material</code></a>. Both <a href="/docs/#api/en/materials/Material"><code class="notranslate" translate="no">Material</code></a> objects and <code class="notranslate" translate="no">Geometry</code> objects can be used by
  84. multiple <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a> objects. For example to draw two blue cubes in different
  85. locations we could need two <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a> objects to represent the position and
  86. orientation of each cube. We would only need one <code class="notranslate" translate="no">Geometry</code> to hold the vertex
  87. data for a cube and we would only need one <a href="/docs/#api/en/materials/Material"><code class="notranslate" translate="no">Material</code></a> to specify the color
  88. blue. Both <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a> objects could reference the same <code class="notranslate" translate="no">Geometry</code> object and the
  89. same <a href="/docs/#api/en/materials/Material"><code class="notranslate" translate="no">Material</code></a> object.</p>
  90. </li>
  91. <li><p><code class="notranslate" translate="no">Geometry</code> objects represent the vertex data of some piece of geometry like
  92. a sphere, cube, plane, dog, cat, human, tree, building, etc...
  93. Three.js provides many kinds of built in
  94. <a href="primitives.html">geometry primitives</a>. You can also
  95. <a href="custom-buffergeometry.html">create custom geometry</a> as well as
  96. <a href="load-obj.html">load geometry from files</a>.</p>
  97. </li>
  98. <li><p><a href="/docs/#api/en/materials/Material"><code class="notranslate" translate="no">Material</code></a> objects represent
  99. <a href="materials.html">the surface properties used to draw geometry</a>
  100. including things like the color to use and how shiny it is. A <a href="/docs/#api/en/materials/Material"><code class="notranslate" translate="no">Material</code></a> can also
  101. reference one or more <a href="/docs/#api/en/textures/Texture"><code class="notranslate" translate="no">Texture</code></a> objects which can be used, for example,
  102. to wrap an image onto the surface of a geometry.</p>
  103. </li>
  104. <li><p><a href="/docs/#api/en/textures/Texture"><code class="notranslate" translate="no">Texture</code></a> objects generally represent images either <a href="textures.html">loaded from image files</a>,
  105. <a href="canvas-textures.html">generated from a canvas</a> or <a href="rendertargets.html">rendered from another scene</a>.</p>
  106. </li>
  107. <li><p><a href="/docs/#api/en/lights/Light"><code class="notranslate" translate="no">Light</code></a> objects represent <a href="lights.html">different kinds of lights</a>.</p>
  108. </li>
  109. </ul>
  110. <p>Given all of that we're going to make the smallest <em>"Hello Cube"</em> setup
  111. that looks like this</p>
  112. <div class="threejs_center"><img src="../resources/images/threejs-1cube-no-light-scene.svg" style="width: 500px;"></div>
  113. <p>First let's load three.js</p>
  114. <pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;script type="module"&gt;
  115. import * as THREE from 'three';
  116. &lt;/script&gt;
  117. </pre>
  118. <p>It's important you put <code class="notranslate" translate="no">type="module"</code> in the script tag. This enables
  119. us to use the <code class="notranslate" translate="no">import</code> keyword to load three.js. As of r147, this is the
  120. only way to load three.js properly. Modules have the advantage that they can easily import other modules
  121. they need. That saves us from having to manually load extra scripts
  122. they are dependent on.</p>
  123. <p>Next we need is a <code class="notranslate" translate="no">&lt;canvas&gt;</code> tag so...</p>
  124. <pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;body&gt;
  125. &lt;canvas id="c"&gt;&lt;/canvas&gt;
  126. &lt;/body&gt;
  127. </pre>
  128. <p>We will ask three.js to draw into that canvas so we need to look it up.</p>
  129. <pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;script type="module"&gt;
  130. import * as THREE from 'three';
  131. +function main() {
  132. + const canvas = document.querySelector('#c');
  133. + const renderer = new THREE.WebGLRenderer({canvas});
  134. + ...
  135. &lt;/script&gt;
  136. </pre>
  137. <p>After we look up the canvas we create a <a href="/docs/#api/en/renderers/WebGLRenderer"><code class="notranslate" translate="no">WebGLRenderer</code></a>. The renderer
  138. is the thing responsible for actually taking all the data you provide
  139. and rendering it to the canvas. In the past there have been other renderers
  140. like <code class="notranslate" translate="no">CSSRenderer</code>, a <code class="notranslate" translate="no">CanvasRenderer</code> and in the future there may be a
  141. <code class="notranslate" translate="no">WebGL2Renderer</code> or <code class="notranslate" translate="no">WebGPURenderer</code>. For now there's the <a href="/docs/#api/en/renderers/WebGLRenderer"><code class="notranslate" translate="no">WebGLRenderer</code></a>
  142. that uses WebGL to render 3D to the canvas.</p>
  143. <p>Note there are some esoteric details here. If you don't pass a canvas
  144. into three.js it will create one for you but then you have to add it
  145. to your document. Where to add it may change depending on your use case
  146. and you'll have to change your code so I find that passing a canvas
  147. to three.js feels a little more flexible. I can put the canvas anywhere
  148. and the code will find it whereas if I had code to insert the canvas
  149. into to the document I'd likely have to change that code if my use case
  150. changed.</p>
  151. <p>Next up we need a camera. We'll create a <a href="/docs/#api/en/cameras/PerspectiveCamera"><code class="notranslate" translate="no">PerspectiveCamera</code></a>.</p>
  152. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const fov = 75;
  153. const aspect = 2; // the canvas default
  154. const near = 0.1;
  155. const far = 5;
  156. const camera = new THREE.PerspectiveCamera(fov, aspect, near, far);
  157. </pre>
  158. <p><code class="notranslate" translate="no">fov</code> is short for <code class="notranslate" translate="no">field of view</code>. In this case 75 degrees in the vertical
  159. dimension. Note that most angles in three.js are in radians but for some
  160. reason the perspective camera takes degrees.</p>
  161. <p><code class="notranslate" translate="no">aspect</code> is the display aspect of the canvas. We'll go over the details
  162. <a href="responsive.html">in another article</a> but by default a canvas is
  163. 300x150 pixels which makes the aspect 300/150 or 2.</p>
  164. <p><code class="notranslate" translate="no">near</code> and <code class="notranslate" translate="no">far</code> represent the space in front of the camera
  165. that will be rendered. Anything before that range or after that range
  166. will be clipped (not drawn).</p>
  167. <p>Those four settings define a <em>"frustum"</em>. A <em>frustum</em> is the name of
  168. a 3d shape that is like a pyramid with the tip sliced off. In other
  169. words think of the word "frustum" as another 3D shape like sphere,
  170. cube, prism, frustum.</p>
  171. <p><img src="../resources/frustum-3d.svg" width="500" class="threejs_center"></p>
  172. <p>The height of the near and far planes are determined by the field of view.
  173. The width of both planes is determined by the field of view and the aspect.</p>
  174. <p>Anything inside the defined frustum will be drawn. Anything outside
  175. will not.</p>
  176. <p>The camera defaults to looking down the -Z axis with +Y up. We'll put our cube
  177. at the origin so we need to move the camera back a little from the origin
  178. in order to see anything.</p>
  179. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">camera.position.z = 2;
  180. </pre>
  181. <p>Here's what we're aiming for.</p>
  182. <p><img src="../resources/scene-down.svg" width="500" class="threejs_center"></p>
  183. <p>In the diagram above we can see our camera is at <code class="notranslate" translate="no">z = 2</code>. It's looking
  184. down the -Z axis. Our frustum starts 0.1 units from the front of the camera
  185. and goes to 5 units in front of the camera. Because in this diagram we are looking down,
  186. the field of view is affected by the aspect. Our canvas is twice as wide
  187. as it is tall so across the canvas the field of view will be much wider than
  188. our specified 75 degrees which is the vertical field of view.</p>
  189. <p>Next we make a <a href="/docs/#api/en/scenes/Scene"><code class="notranslate" translate="no">Scene</code></a>. A <a href="/docs/#api/en/scenes/Scene"><code class="notranslate" translate="no">Scene</code></a> in three.js is the root of a form of scene graph.
  190. Anything you want three.js to draw needs to be added to the scene. We'll
  191. cover more details of <a href="scenegraph.html">how scenes work in a future article</a>.</p>
  192. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const scene = new THREE.Scene();
  193. </pre>
  194. <p>Next up we create a <a href="/docs/#api/en/geometries/BoxGeometry"><code class="notranslate" translate="no">BoxGeometry</code></a> which contains the data for a box.
  195. Almost anything we want to display in Three.js needs geometry which defines
  196. the vertices that make up our 3D object.</p>
  197. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const boxWidth = 1;
  198. const boxHeight = 1;
  199. const boxDepth = 1;
  200. const geometry = new THREE.BoxGeometry(boxWidth, boxHeight, boxDepth);
  201. </pre>
  202. <p>We then create a basic material and set its color. Colors can
  203. be specified using standard CSS style 6 digit hex color values.</p>
  204. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const material = new THREE.MeshBasicMaterial({color: 0x44aa88});
  205. </pre>
  206. <p>We then create a <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a>. A <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a> in three represents the combination
  207. of three things</p>
  208. <ol>
  209. <li>A <code class="notranslate" translate="no">Geometry</code> (the shape of the object)</li>
  210. <li>A <a href="/docs/#api/en/materials/Material"><code class="notranslate" translate="no">Material</code></a> (how to draw the object, shiny or flat, what color, what texture(s) to apply. Etc.)</li>
  211. <li>The position, orientation, and scale of that object in the scene relative to its parent. In the code below that parent is the scene.</li>
  212. </ol>
  213. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const cube = new THREE.Mesh(geometry, material);
  214. </pre>
  215. <p>And finally we add that mesh to the scene</p>
  216. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">scene.add(cube);
  217. </pre>
  218. <p>We can then render the scene by calling the renderer's render function
  219. and passing it the scene and the camera</p>
  220. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">renderer.render(scene, camera);
  221. </pre>
  222. <p>Here's a working example</p>
  223. <p></p><div translate="no" class="threejs_example_container notranslate">
  224. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/fundamentals.html"></iframe></div>
  225. <a class="threejs_center" href="/manual/examples/fundamentals.html" target="_blank">click here to open in a separate window</a>
  226. </div>
  227. <p></p>
  228. <p>It's kind of hard to tell that is a 3D cube since we're viewing
  229. it directly down the -Z axis and the cube itself is axis aligned
  230. so we're only seeing a single face.</p>
  231. <p>Let's animate it spinning and hopefully that will make
  232. it clear it's being drawn in 3D. To animate it we'll render inside a render loop using
  233. <a href="https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame"><code class="notranslate" translate="no">requestAnimationFrame</code></a>.</p>
  234. <p>Here's our loop</p>
  235. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">function render(time) {
  236. time *= 0.001; // convert time to seconds
  237. cube.rotation.x = time;
  238. cube.rotation.y = time;
  239. renderer.render(scene, camera);
  240. requestAnimationFrame(render);
  241. }
  242. requestAnimationFrame(render);
  243. </pre>
  244. <p><code class="notranslate" translate="no">requestAnimationFrame</code> is a request to the browser that you want to animate something.
  245. You pass it a function to be called. In our case that function is <code class="notranslate" translate="no">render</code>. The browser
  246. will call your function and if you update anything related to the display of the
  247. page the browser will re-render the page. In our case we are calling three's
  248. <code class="notranslate" translate="no">renderer.render</code> function which will draw our scene.</p>
  249. <p><code class="notranslate" translate="no">requestAnimationFrame</code> passes the time since the page loaded to
  250. our function. That time is passed in milliseconds. I find it's much
  251. easier to work with seconds so here we're converting that to seconds.</p>
  252. <p>We then set the cube's X and Y rotation to the current time. These rotations
  253. are in <a href="https://en.wikipedia.org/wiki/Radian">radians</a>. There are 2 pi radians
  254. in a circle so our cube should turn around once on each axis in about 6.28
  255. seconds.</p>
  256. <p>We then render the scene and request another animation frame to continue
  257. our loop.</p>
  258. <p>Outside the loop we call <code class="notranslate" translate="no">requestAnimationFrame</code> one time to start the loop.</p>
  259. <p></p><div translate="no" class="threejs_example_container notranslate">
  260. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/fundamentals-with-animation.html"></iframe></div>
  261. <a class="threejs_center" href="/manual/examples/fundamentals-with-animation.html" target="_blank">click here to open in a separate window</a>
  262. </div>
  263. <p></p>
  264. <p>It's a little better but it's still hard to see the 3d. What would help is to
  265. add some lighting so let's add a light. There are many kinds of lights in
  266. three.js which we'll go over in <a href="lights.html">a future article</a>. For now let's create a directional light.</p>
  267. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">{
  268. const color = 0xFFFFFF;
  269. const intensity = 1;
  270. const light = new THREE.DirectionalLight(color, intensity);
  271. light.position.set(-1, 2, 4);
  272. scene.add(light);
  273. }
  274. </pre>
  275. <p>Directional lights have a position and a target. Both default to 0, 0, 0. In our
  276. case we're setting the light's position to -1, 2, 4 so it's slightly on the left,
  277. above, and behind our camera. The target is still 0, 0, 0 so it will shine
  278. toward the origin.</p>
  279. <p>We also need to change the material. The <a href="/docs/#api/en/materials/MeshBasicMaterial"><code class="notranslate" translate="no">MeshBasicMaterial</code></a> is not affected by
  280. lights. Let's change it to a <a href="/docs/#api/en/materials/MeshPhongMaterial"><code class="notranslate" translate="no">MeshPhongMaterial</code></a> which is affected by lights.</p>
  281. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">-const material = new THREE.MeshBasicMaterial({color: 0x44aa88}); // greenish blue
  282. +const material = new THREE.MeshPhongMaterial({color: 0x44aa88}); // greenish blue
  283. </pre>
  284. <p>Here is our new program structure</p>
  285. <div class="threejs_center"><img src="../resources/images/threejs-1cube-with-directionallight.svg" style="width: 500px;"></div>
  286. <p>And here it is working.</p>
  287. <p></p><div translate="no" class="threejs_example_container notranslate">
  288. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/fundamentals-with-light.html"></iframe></div>
  289. <a class="threejs_center" href="/manual/examples/fundamentals-with-light.html" target="_blank">click here to open in a separate window</a>
  290. </div>
  291. <p></p>
  292. <p>It should now be pretty clearly 3D.</p>
  293. <p>Just for the fun of it let's add 2 more cubes.</p>
  294. <p>We'll use the same geometry for each cube but make a different
  295. material so each cube can be a different color.</p>
  296. <p>First we'll make a function that creates a new material
  297. with the specified color. Then it creates a mesh using
  298. the specified geometry and adds it to the scene and
  299. sets its X position.</p>
  300. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">function makeInstance(geometry, color, x) {
  301. const material = new THREE.MeshPhongMaterial({color});
  302. const cube = new THREE.Mesh(geometry, material);
  303. scene.add(cube);
  304. cube.position.x = x;
  305. return cube;
  306. }
  307. </pre>
  308. <p>Then we'll call it 3 times with 3 different colors and X positions
  309. saving the <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a> instances in an array.</p>
  310. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">const cubes = [
  311. makeInstance(geometry, 0x44aa88, 0),
  312. makeInstance(geometry, 0x8844aa, -2),
  313. makeInstance(geometry, 0xaa8844, 2),
  314. ];
  315. </pre>
  316. <p>Finally we'll spin all 3 cubes in our render function. We
  317. compute a slightly different rotation for each one.</p>
  318. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">function render(time) {
  319. time *= 0.001; // convert time to seconds
  320. cubes.forEach((cube, ndx) =&gt; {
  321. const speed = 1 + ndx * .1;
  322. const rot = time * speed;
  323. cube.rotation.x = rot;
  324. cube.rotation.y = rot;
  325. });
  326. ...
  327. </pre>
  328. <p>and here's that.</p>
  329. <p></p><div translate="no" class="threejs_example_container notranslate">
  330. <div><iframe class="threejs_example notranslate" translate="no" style=" " src="/manual/examples/resources/editor.html?url=/manual/examples/fundamentals-3-cubes.html"></iframe></div>
  331. <a class="threejs_center" href="/manual/examples/fundamentals-3-cubes.html" target="_blank">click here to open in a separate window</a>
  332. </div>
  333. <p></p>
  334. <p>If you compare it to the top down diagram above you can see
  335. it matches our expectations. With cubes at X = -2 and X = +2
  336. they are partially outside our frustum. They are also
  337. somewhat exaggeratedly warped since the field of view
  338. across the canvas is so extreme.</p>
  339. <p>Our program now has this structure</p>
  340. <div class="threejs_center"><img src="../resources/images/threejs-3cubes-scene.svg" style="width: 610px;"></div>
  341. <p>As you can see we have 3 <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a> objects each referencing the same <a href="/docs/#api/en/geometries/BoxGeometry"><code class="notranslate" translate="no">BoxGeometry</code></a>.
  342. Each <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a> references a unique <a href="/docs/#api/en/materials/MeshPhongMaterial"><code class="notranslate" translate="no">MeshPhongMaterial</code></a> so that each cube can have
  343. a different color.</p>
  344. <p>I hope this short intro helps to get things started. <a href="responsive.html">Next up we'll cover
  345. making our code responsive so it is adaptable to multiple situations</a>.</p>
  346. <div id="es6" class="threejs_bottombar">
  347. <h3>es6 modules, three.js, and folder structure</h3>
  348. <p>As of version r147 the preferred way to use three.js is via <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/import">es6 modules</a> and import maps.</p>
  349. <p>
  350. es6 modules can be loaded via the <code class="notranslate" translate="no">import</code> keyword in a script
  351. or inline via a <code class="notranslate" translate="no">&lt;script type="module"&gt;</code> tag. Here's an example
  352. </p>
  353. <pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;script type="module"&gt;
  354. import * as THREE from 'three';
  355. ...
  356. &lt;/script&gt;
  357. </pre>
  358. <p>
  359. Notice <code class="notranslate" translate="no">'three'</code> specifier there. If you leave it as it is, it will likely produce an error. An <i>import map</i> should be used to tell the browser where to find three.js
  360. </p>
  361. <pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;script type="importmap"&gt;
  362. {
  363. "imports": {
  364. "three": "./path/to/three.module.js"
  365. }
  366. }
  367. &lt;/script&gt;
  368. </pre>
  369. <p>
  370. Note that path specifier can start only with <code class="notranslate" translate="no">./</code> or <code class="notranslate" translate="no">../</code>.
  371. </p>
  372. <p>
  373. Import maps are still unsupported in Firefox and Safari, so it is recommended to use <a href="https://github.com/guybedford/es-module-shims">an import maps polyfill</a> like so
  374. </p>
  375. <pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"&gt;&lt;/script&gt;</pre>
  376. <p>
  377. To import addons like <a href="https://github.com/mrdoob/three.js/blob/master/examples/jsm/controls/OrbitControls.js"><code class="notranslate" translate="no">OrbitControls.js</code></a> use the following
  378. </p>
  379. <pre class="prettyprint showlinemods notranslate lang-js" translate="no">import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
  380. </pre>
  381. <p>
  382. Don't forget to add addons to the import map like so
  383. </p>
  384. <pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;script type="importmap"&gt;
  385. {
  386. "imports": {
  387. "three": "./path/to/three.module.js",
  388. "three/addons/": "./different/path/to/examples/jsm/"
  389. }
  390. }
  391. &lt;/script&gt;
  392. </pre>
  393. <p>
  394. You can also use a CDN
  395. </p>
  396. <pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;script type="importmap"&gt;
  397. {
  398. "imports": {
  399. "three": "https://unpkg.com/[email protected]/build/three.module.js",
  400. "three/addons/": "https://unpkg.com/[email protected]/examples/jsm/"
  401. }
  402. }
  403. &lt;/script&gt;
  404. </pre>
  405. <p>
  406. To conclude, the recommended way of using three.js is
  407. </p>
  408. <pre class="prettyprint showlinemods notranslate lang-html" translate="no">&lt;script async src="https://unpkg.com/[email protected]/dist/es-module-shims.js"&gt;&lt;/script&gt;
  409. &lt;script type="importmap"&gt;
  410. {
  411. "imports": {
  412. "three": "./path/to/three.module.js",
  413. "three/addons/": "./different/path/to/examples/jsm/"
  414. }
  415. }
  416. &lt;/script&gt;
  417. &lt;script type="module"&gt;
  418. import * as THREE from 'three';
  419. import {OrbitControls} from 'three/addons/controls/OrbitControls.js';
  420. ...
  421. &lt;/script&gt;
  422. </pre>
  423. </div>
  424. <!-- needed in English only to prevent warning from outdated translations -->
  425. <p><a href="geometry.html"></a>
  426. <a href="Geometry"></a></p>
  427. </div>
  428. </div>
  429. </div>
  430. <script src="/manual/resources/prettify.js"></script>
  431. <script src="/manual/resources/lesson.js"></script>
  432. </body></html>