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.
		
		
		
		
			
				
					569 lines
				
				32 KiB
			
		
		
			
		
	
	
					569 lines
				
				32 KiB
			| 
								 
											3 years ago
										 
									 | 
							
								<!DOCTYPE html><html lang="en"><head>
							 | 
						||
| 
								 | 
							
								    <meta charset="utf-8">
							 | 
						||
| 
								 | 
							
								    <title>Textures</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 – Textures">
							 | 
						||
| 
								 | 
							
								    <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>Textures</h1>
							 | 
						||
| 
								 | 
							
								      </div>
							 | 
						||
| 
								 | 
							
								      <div class="lesson">
							 | 
						||
| 
								 | 
							
								        <div class="lesson-main">
							 | 
						||
| 
								 | 
							
								          <p>This article is one in a series of articles about three.js.
							 | 
						||
| 
								 | 
							
								The first article was <a href="fundamentals.html">about three.js fundamentals</a>.
							 | 
						||
| 
								 | 
							
								The <a href="setup.html">previous article</a> was about setting up for this article.
							 | 
						||
| 
								 | 
							
								If you haven't read that yet you might want to start there.</p>
							 | 
						||
| 
								 | 
							
								<p>Textures are a kind of large topic in Three.js and
							 | 
						||
| 
								 | 
							
								I'm not 100% sure at what level to explain them but I will try.
							 | 
						||
| 
								 | 
							
								There are many topics and many of them interrelate so it's hard to explain
							 | 
						||
| 
								 | 
							
								them all at once. Here's quick table of contents for this article.</p>
							 | 
						||
| 
								 | 
							
								<ul>
							 | 
						||
| 
								 | 
							
								<li><a href="#hello">Hello Texture</a></li>
							 | 
						||
| 
								 | 
							
								<li><a href="#six">6 textures, a different one on each face of a cube</a></li>
							 | 
						||
| 
								 | 
							
								<li><a href="#loading">Loading textures</a></li>
							 | 
						||
| 
								 | 
							
								<ul>
							 | 
						||
| 
								 | 
							
								  <li><a href="#easy">The easy way</a></li>
							 | 
						||
| 
								 | 
							
								  <li><a href="#wait1">Waiting for a texture to load</a></li>
							 | 
						||
| 
								 | 
							
								  <li><a href="#waitmany">Waiting for multiple textures to load</a></li>
							 | 
						||
| 
								 | 
							
								  <li><a href="#cors">Loading textures from other origins</a></li>
							 | 
						||
| 
								 | 
							
								</ul>
							 | 
						||
| 
								 | 
							
								<li><a href="#memory">Memory usage</a></li>
							 | 
						||
| 
								 | 
							
								<li><a href="#format">JPG vs PNG</a></li>
							 | 
						||
| 
								 | 
							
								<li><a href="#filtering-and-mips">Filtering and mips</a></li>
							 | 
						||
| 
								 | 
							
								<li><a href="#uvmanipulation">Repeating, offseting, rotating, wrapping</a></li>
							 | 
						||
| 
								 | 
							
								</ul>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<h2 id="-a-name-hello-a-hello-texture"><a name="hello"></a> Hello Texture</h2>
							 | 
						||
| 
								 | 
							
								<p>Textures are <em>generally</em> images that are most often created
							 | 
						||
| 
								 | 
							
								in some 3rd party program like Photoshop or GIMP. For example let's
							 | 
						||
| 
								 | 
							
								put this image on cube.</p>
							 | 
						||
| 
								 | 
							
								<div class="threejs_center">
							 | 
						||
| 
								 | 
							
								  <img src="../examples/resources/images/wall.jpg" style="width: 600px;" class="border">
							 | 
						||
| 
								 | 
							
								</div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<p>We'll modify one of our first samples. All we need to do is create a <a href="/docs/#api/en/loaders/TextureLoader"><code class="notranslate" translate="no">TextureLoader</code></a>. Call its
							 | 
						||
| 
								 | 
							
								<a href="/docs/#api/en/loaders/TextureLoader#load"><code class="notranslate" translate="no">load</code></a> method with the URL of an
							 | 
						||
| 
								 | 
							
								image and set the material's <code class="notranslate" translate="no">map</code> property to the result instead of setting its <code class="notranslate" translate="no">color</code>.</p>
							 | 
						||
| 
								 | 
							
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const loader = new THREE.TextureLoader();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const material = new THREE.MeshBasicMaterial({
							 | 
						||
| 
								 | 
							
								-  color: 0xFF8844,
							 | 
						||
| 
								 | 
							
								+  map: loader.load('resources/images/wall.jpg'),
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								</pre>
							 | 
						||
| 
								 | 
							
								<p>Note that we're using <a href="/docs/#api/en/materials/MeshBasicMaterial"><code class="notranslate" translate="no">MeshBasicMaterial</code></a> so no need for any lights.</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/textured-cube.html"></iframe></div>
							 | 
						||
| 
								 | 
							
								  <a class="threejs_center" href="/manual/examples/textured-cube.html" target="_blank">click here to open in a separate window</a>
							 | 
						||
| 
								 | 
							
								</div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<p></p>
							 | 
						||
| 
								 | 
							
								<h2 id="-a-name-six-a-6-textures-a-different-one-on-each-face-of-a-cube"><a name="six"></a> 6 Textures, a different one on each face of a cube</h2>
							 | 
						||
| 
								 | 
							
								<p>How about 6 textures, one on each face of a cube?</p>
							 | 
						||
| 
								 | 
							
								<div class="threejs_center">
							 | 
						||
| 
								 | 
							
								  <div>
							 | 
						||
| 
								 | 
							
								    <img src="../examples/resources/images/flower-1.jpg" style="width: 100px;" class="border">
							 | 
						||
| 
								 | 
							
								    <img src="../examples/resources/images/flower-2.jpg" style="width: 100px;" class="border">
							 | 
						||
| 
								 | 
							
								    <img src="../examples/resources/images/flower-3.jpg" style="width: 100px;" class="border">
							 | 
						||
| 
								 | 
							
								  </div>
							 | 
						||
| 
								 | 
							
								  <div>
							 | 
						||
| 
								 | 
							
								    <img src="../examples/resources/images/flower-4.jpg" style="width: 100px;" class="border">
							 | 
						||
| 
								 | 
							
								    <img src="../examples/resources/images/flower-5.jpg" style="width: 100px;" class="border">
							 | 
						||
| 
								 | 
							
								    <img src="../examples/resources/images/flower-6.jpg" style="width: 100px;" class="border">
							 | 
						||
| 
								 | 
							
								  </div>
							 | 
						||
| 
								 | 
							
								</div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<p>We just make 6 materials and pass them as an array when we create the <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a></p>
							 | 
						||
| 
								 | 
							
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const loader = new THREE.TextureLoader();
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								-const material = new THREE.MeshBasicMaterial({
							 | 
						||
| 
								 | 
							
								-  map: loader.load('resources/images/wall.jpg'),
							 | 
						||
| 
								 | 
							
								-});
							 | 
						||
| 
								 | 
							
								+const materials = [
							 | 
						||
| 
								 | 
							
								+  new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-1.jpg')}),
							 | 
						||
| 
								 | 
							
								+  new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-2.jpg')}),
							 | 
						||
| 
								 | 
							
								+  new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-3.jpg')}),
							 | 
						||
| 
								 | 
							
								+  new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-4.jpg')}),
							 | 
						||
| 
								 | 
							
								+  new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-5.jpg')}),
							 | 
						||
| 
								 | 
							
								+  new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-6.jpg')}),
							 | 
						||
| 
								 | 
							
								+];
							 | 
						||
| 
								 | 
							
								-const cube = new THREE.Mesh(geometry, material);
							 | 
						||
| 
								 | 
							
								+const cube = new THREE.Mesh(geometry, materials);
							 | 
						||
| 
								 | 
							
								</pre>
							 | 
						||
| 
								 | 
							
								<p>It works!</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/textured-cube-6-textures.html"></iframe></div>
							 | 
						||
| 
								 | 
							
								  <a class="threejs_center" href="/manual/examples/textured-cube-6-textures.html" target="_blank">click here to open in a separate window</a>
							 | 
						||
| 
								 | 
							
								</div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<p></p>
							 | 
						||
| 
								 | 
							
								<p>It should be noted though that not all geometry types supports multiple
							 | 
						||
| 
								 | 
							
								materials. <a href="/docs/#api/en/geometries/BoxGeometry"><code class="notranslate" translate="no">BoxGeometry</code></a> can use 6 materials one for each face.
							 | 
						||
| 
								 | 
							
								<a href="/docs/#api/en/geometries/ConeGeometry"><code class="notranslate" translate="no">ConeGeometry</code></a> can use 2 materials, one for the bottom and one for the cone.
							 | 
						||
| 
								 | 
							
								<a href="/docs/#api/en/geometries/CylinderGeometry"><code class="notranslate" translate="no">CylinderGeometry</code></a> can use 3 materials, bottom, top, and side.
							 | 
						||
| 
								 | 
							
								For other cases you will need to build or load custom geometry and/or modify texture coordinates.</p>
							 | 
						||
| 
								 | 
							
								<p>It's far more common in other 3D engines and far more performant to use a
							 | 
						||
| 
								 | 
							
								<a href="https://en.wikipedia.org/wiki/Texture_atlas">Texture Atlas</a>
							 | 
						||
| 
								 | 
							
								if you want to allow multiple images on a single geometry. A Texture atlas
							 | 
						||
| 
								 | 
							
								is where you put multiple images in a single texture and then use texture coordinates
							 | 
						||
| 
								 | 
							
								on the vertices of your geometry to select which parts of a texture are used on
							 | 
						||
| 
								 | 
							
								each triangle in your geometry.</p>
							 | 
						||
| 
								 | 
							
								<p>What are texture coordinates? They are data added to each vertex of a piece of geometry
							 | 
						||
| 
								 | 
							
								that specify what part of the texture corresponds to that specific vertex.
							 | 
						||
| 
								 | 
							
								We'll go over them when we start <a href="custom-buffergeometry.html">building custom geometry</a>.</p>
							 | 
						||
| 
								 | 
							
								<h2 id="-a-name-loading-a-loading-textures"><a name="loading"></a> Loading Textures</h2>
							 | 
						||
| 
								 | 
							
								<h3 id="-a-name-easy-a-the-easy-way"><a name="easy"></a> The Easy Way</h3>
							 | 
						||
| 
								 | 
							
								<p>Most of the code on this site uses the easiest method of loading textures.
							 | 
						||
| 
								 | 
							
								We create a <a href="/docs/#api/en/loaders/TextureLoader"><code class="notranslate" translate="no">TextureLoader</code></a> and then call its <a href="/docs/#api/en/loaders/TextureLoader#load"><code class="notranslate" translate="no">load</code></a> method.
							 | 
						||
| 
								 | 
							
								This returns a <a href="/docs/#api/en/textures/Texture"><code class="notranslate" translate="no">Texture</code></a> object.</p>
							 | 
						||
| 
								 | 
							
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const texture = loader.load('resources/images/flower-1.jpg');
							 | 
						||
| 
								 | 
							
								</pre>
							 | 
						||
| 
								 | 
							
								<p>It's important to note that using this method our texture will be transparent until
							 | 
						||
| 
								 | 
							
								the image is loaded asynchronously by three.js at which point it will update the texture
							 | 
						||
| 
								 | 
							
								with the downloaded image.</p>
							 | 
						||
| 
								 | 
							
								<p>This has the big advantage that we don't have to wait for the texture to load and our
							 | 
						||
| 
								 | 
							
								page will start rendering immediately. That's probably okay for a great many use cases
							 | 
						||
| 
								 | 
							
								but if we want we can ask three.js to tell us when the texture has finished downloading.</p>
							 | 
						||
| 
								 | 
							
								<h3 id="-a-name-wait1-a-waiting-for-a-texture-to-load"><a name="wait1"></a> Waiting for a texture to load</h3>
							 | 
						||
| 
								 | 
							
								<p>To wait for a texture to load the <code class="notranslate" translate="no">load</code> method of the texture loader takes a callback
							 | 
						||
| 
								 | 
							
								that will be called when the texture has finished loading. Going back to our top example
							 | 
						||
| 
								 | 
							
								we can wait for the texture to load before creating our <a href="/docs/#api/en/objects/Mesh"><code class="notranslate" translate="no">Mesh</code></a> and adding it to scene
							 | 
						||
| 
								 | 
							
								like this</p>
							 | 
						||
| 
								 | 
							
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const loader = new THREE.TextureLoader();
							 | 
						||
| 
								 | 
							
								loader.load('resources/images/wall.jpg', (texture) => {
							 | 
						||
| 
								 | 
							
								  const material = new THREE.MeshBasicMaterial({
							 | 
						||
| 
								 | 
							
								    map: texture,
							 | 
						||
| 
								 | 
							
								  });
							 | 
						||
| 
								 | 
							
								  const cube = new THREE.Mesh(geometry, material);
							 | 
						||
| 
								 | 
							
								  scene.add(cube);
							 | 
						||
| 
								 | 
							
								  cubes.push(cube);  // add to our list of cubes to rotate
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								</pre>
							 | 
						||
| 
								 | 
							
								<p>Unless you clear your browser's cache and have a slow connection you're unlikely
							 | 
						||
| 
								 | 
							
								to see the any difference but rest assured it is waiting for the texture to load.</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/textured-cube-wait-for-texture.html"></iframe></div>
							 | 
						||
| 
								 | 
							
								  <a class="threejs_center" href="/manual/examples/textured-cube-wait-for-texture.html" target="_blank">click here to open in a separate window</a>
							 | 
						||
| 
								 | 
							
								</div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<p></p>
							 | 
						||
| 
								 | 
							
								<h3 id="-a-name-waitmany-a-waiting-for-multiple-textures-to-load"><a name="waitmany"></a> Waiting for multiple textures to load</h3>
							 | 
						||
| 
								 | 
							
								<p>To wait until all textures have loaded you can use a <a href="/docs/#api/en/loaders/managers/LoadingManager"><code class="notranslate" translate="no">LoadingManager</code></a>. Create one
							 | 
						||
| 
								 | 
							
								and pass it to the <a href="/docs/#api/en/loaders/TextureLoader"><code class="notranslate" translate="no">TextureLoader</code></a> then set its  <a href="/docs/#api/en/loaders/managers/LoadingManager#onLoad"><code class="notranslate" translate="no">onLoad</code></a>
							 | 
						||
| 
								 | 
							
								property to a callback.</p>
							 | 
						||
| 
								 | 
							
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const loadManager = new THREE.LoadingManager();
							 | 
						||
| 
								 | 
							
								*const loader = new THREE.TextureLoader(loadManager);
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const materials = [
							 | 
						||
| 
								 | 
							
								  new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-1.jpg')}),
							 | 
						||
| 
								 | 
							
								  new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-2.jpg')}),
							 | 
						||
| 
								 | 
							
								  new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-3.jpg')}),
							 | 
						||
| 
								 | 
							
								  new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-4.jpg')}),
							 | 
						||
| 
								 | 
							
								  new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-5.jpg')}),
							 | 
						||
| 
								 | 
							
								  new THREE.MeshBasicMaterial({map: loader.load('resources/images/flower-6.jpg')}),
							 | 
						||
| 
								 | 
							
								];
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								+loadManager.onLoad = () => {
							 | 
						||
| 
								 | 
							
								+  const cube = new THREE.Mesh(geometry, materials);
							 | 
						||
| 
								 | 
							
								+  scene.add(cube);
							 | 
						||
| 
								 | 
							
								+  cubes.push(cube);  // add to our list of cubes to rotate
							 | 
						||
| 
								 | 
							
								+};
							 | 
						||
| 
								 | 
							
								</pre>
							 | 
						||
| 
								 | 
							
								<p>The <a href="/docs/#api/en/loaders/managers/LoadingManager"><code class="notranslate" translate="no">LoadingManager</code></a> also has an <a href="/docs/#api/en/loaders/managers/LoadingManager#onProgress"><code class="notranslate" translate="no">onProgress</code></a> property
							 | 
						||
| 
								 | 
							
								we can set to another callback to show a progress indicator.</p>
							 | 
						||
| 
								 | 
							
								<p>First we'll add a progress bar in HTML</p>
							 | 
						||
| 
								 | 
							
								<pre class="prettyprint showlinemods notranslate lang-html" translate="no"><body>
							 | 
						||
| 
								 | 
							
								  <canvas id="c"></canvas>
							 | 
						||
| 
								 | 
							
								+  <div id="loading">
							 | 
						||
| 
								 | 
							
								+    <div class="progress"><div class="progressbar"></div></div>
							 | 
						||
| 
								 | 
							
								+  </div>
							 | 
						||
| 
								 | 
							
								</body>
							 | 
						||
| 
								 | 
							
								</pre>
							 | 
						||
| 
								 | 
							
								<p>and the CSS for it</p>
							 | 
						||
| 
								 | 
							
								<pre class="prettyprint showlinemods notranslate lang-css" translate="no">#loading {
							 | 
						||
| 
								 | 
							
								    position: fixed;
							 | 
						||
| 
								 | 
							
								    top: 0;
							 | 
						||
| 
								 | 
							
								    left: 0;
							 | 
						||
| 
								 | 
							
								    width: 100%;
							 | 
						||
| 
								 | 
							
								    height: 100%;
							 | 
						||
| 
								 | 
							
								    display: flex;
							 | 
						||
| 
								 | 
							
								    justify-content: center;
							 | 
						||
| 
								 | 
							
								    align-items: center;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								#loading .progress {
							 | 
						||
| 
								 | 
							
								    margin: 1.5em;
							 | 
						||
| 
								 | 
							
								    border: 1px solid white;
							 | 
						||
| 
								 | 
							
								    width: 50vw;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								#loading .progressbar {
							 | 
						||
| 
								 | 
							
								    margin: 2px;
							 | 
						||
| 
								 | 
							
								    background: white;
							 | 
						||
| 
								 | 
							
								    height: 1em;
							 | 
						||
| 
								 | 
							
								    transform-origin: top left;
							 | 
						||
| 
								 | 
							
								    transform: scaleX(0);
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								</pre>
							 | 
						||
| 
								 | 
							
								<p>Then in the code we'll update the scale of the <code class="notranslate" translate="no">progressbar</code> in our <code class="notranslate" translate="no">onProgress</code> callback. It gets
							 | 
						||
| 
								 | 
							
								called with the URL of the last item loaded, the number of items loaded so far, and the total
							 | 
						||
| 
								 | 
							
								number of items loaded.</p>
							 | 
						||
| 
								 | 
							
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const loadingElem = document.querySelector('#loading');
							 | 
						||
| 
								 | 
							
								+const progressBarElem = loadingElem.querySelector('.progressbar');
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								loadManager.onLoad = () => {
							 | 
						||
| 
								 | 
							
								+  loadingElem.style.display = 'none';
							 | 
						||
| 
								 | 
							
								  const cube = new THREE.Mesh(geometry, materials);
							 | 
						||
| 
								 | 
							
								  scene.add(cube);
							 | 
						||
| 
								 | 
							
								  cubes.push(cube);  // add to our list of cubes to rotate
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								+loadManager.onProgress = (urlOfLastItemLoaded, itemsLoaded, itemsTotal) => {
							 | 
						||
| 
								 | 
							
								+  const progress = itemsLoaded / itemsTotal;
							 | 
						||
| 
								 | 
							
								+  progressBarElem.style.transform = `scaleX(${progress})`;
							 | 
						||
| 
								 | 
							
								+};
							 | 
						||
| 
								 | 
							
								</pre>
							 | 
						||
| 
								 | 
							
								<p>Unless you clear your cache and have a slow connection you might not see
							 | 
						||
| 
								 | 
							
								the loading bar.</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/textured-cube-wait-for-all-textures.html"></iframe></div>
							 | 
						||
| 
								 | 
							
								  <a class="threejs_center" href="/manual/examples/textured-cube-wait-for-all-textures.html" target="_blank">click here to open in a separate window</a>
							 | 
						||
| 
								 | 
							
								</div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<p></p>
							 | 
						||
| 
								 | 
							
								<h2 id="-a-name-cors-a-loading-textures-from-other-origins"><a name="cors"></a> Loading textures from other origins</h2>
							 | 
						||
| 
								 | 
							
								<p>To use images from other servers those servers need to send the correct headers.
							 | 
						||
| 
								 | 
							
								If they don't you cannot use the images in three.js and will get an error.
							 | 
						||
| 
								 | 
							
								If you run the server providing the images make sure it
							 | 
						||
| 
								 | 
							
								<a href="https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS">sends the correct headers</a>.
							 | 
						||
| 
								 | 
							
								If you don't control the server hosting the images and it does not send the
							 | 
						||
| 
								 | 
							
								permission headers then you can't use the images from that server.</p>
							 | 
						||
| 
								 | 
							
								<p>For example <a href="https://imgur.com">imgur</a>, <a href="https://flickr.com">flickr</a>, and
							 | 
						||
| 
								 | 
							
								<a href="https://github.com">github</a> all send headers allowing you to use images
							 | 
						||
| 
								 | 
							
								hosted on their servers in three.js. Most other websites do not.</p>
							 | 
						||
| 
								 | 
							
								<h2 id="-a-name-memory-a-memory-usage"><a name="memory"></a> Memory Usage</h2>
							 | 
						||
| 
								 | 
							
								<p>Textures are often the part of a three.js app that use the most memory. It's important to understand
							 | 
						||
| 
								 | 
							
								that <em>in general</em>, textures take <code class="notranslate" translate="no">width * height * 4 * 1.33</code> bytes of memory.</p>
							 | 
						||
| 
								 | 
							
								<p>Notice that says nothing about compression. I can make a .jpg image and set its compression super
							 | 
						||
| 
								 | 
							
								high. For example let's say I was making a scene of a house. Inside the house there is a table
							 | 
						||
| 
								 | 
							
								and I decide to put this wood texture on the top surface of the table</p>
							 | 
						||
| 
								 | 
							
								<div class="threejs_center"><img class="border" src="../resources/images/compressed-but-large-wood-texture.jpg" align="center" style="width: 300px"></div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<p>That image is only 157k so it will download relatively quickly but <a href="resources/images/compressed-but-large-wood-texture.jpg">it is actually
							 | 
						||
| 
								 | 
							
								3024 x 3761 pixels in size</a>.
							 | 
						||
| 
								 | 
							
								Following the equation above that's</p>
							 | 
						||
| 
								 | 
							
								<pre class="prettyprint showlinemods notranslate notranslate" translate="no">3024 * 3761 * 4 * 1.33 = 60505764.5
							 | 
						||
| 
								 | 
							
								</pre><p>That image will take <strong>60 MEG OF MEMORY!</strong> in three.js.
							 | 
						||
| 
								 | 
							
								A few textures like that and you'll be out of memory.</p>
							 | 
						||
| 
								 | 
							
								<p>I bring this up because it's important to know that using textures has a hidden cost.
							 | 
						||
| 
								 | 
							
								In order for three.js to use the texture it has to hand it off to the GPU and the
							 | 
						||
| 
								 | 
							
								GPU <em>in general</em> requires the texture data to be uncompressed.</p>
							 | 
						||
| 
								 | 
							
								<p>The moral of the story is make your textures small in dimensions not just small
							 | 
						||
| 
								 | 
							
								in file size. Small in file size = fast to download. Small in dimensions = takes
							 | 
						||
| 
								 | 
							
								less memory. How small should you make them?
							 | 
						||
| 
								 | 
							
								As small as you can and still look as good as you need them to look.</p>
							 | 
						||
| 
								 | 
							
								<h2 id="-a-name-format-a-jpg-vs-png"><a name="format"></a> JPG vs PNG</h2>
							 | 
						||
| 
								 | 
							
								<p>This is pretty much the same as regular HTML in that JPGs have lossy compression,
							 | 
						||
| 
								 | 
							
								PNGs have lossless compression so PNGs are generally slower to download.
							 | 
						||
| 
								 | 
							
								But, PNGs support transparency. PNGs are also probably the appropriate format
							 | 
						||
| 
								 | 
							
								for non-image data like normal maps, and other kinds of non-image maps which we'll go over later.</p>
							 | 
						||
| 
								 | 
							
								<p>It's important to remember that a JPG doesn't use
							 | 
						||
| 
								 | 
							
								less memory than a PNG in WebGL. See above.</p>
							 | 
						||
| 
								 | 
							
								<h2 id="-a-name-filtering-and-mips-a-filtering-and-mips"><a name="filtering-and-mips"></a> Filtering and Mips</h2>
							 | 
						||
| 
								 | 
							
								<p>Let's apply this 16x16 texture</p>
							 | 
						||
| 
								 | 
							
								<div class="threejs_center"><img src="../resources/images/mip-low-res-enlarged.png" class="nobg" align="center"></div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<p>To a cube</p>
							 | 
						||
| 
								 | 
							
								<div class="spread"><div data-diagram="filterCube"></div></div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<p>Let's draw that cube really small</p>
							 | 
						||
| 
								 | 
							
								<div class="spread"><div data-diagram="filterCubeSmall"></div></div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<p>Hmmm, I guess that's hard to see. Let's magnify that tiny cube</p>
							 | 
						||
| 
								 | 
							
								<div class="spread"><div data-diagram="filterCubeSmallLowRes"></div></div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<p>How does the GPU know which colors to make each pixel it's drawing for the tiny cube?
							 | 
						||
| 
								 | 
							
								What if the cube was so small that it's just 1 or 2 pixels?</p>
							 | 
						||
| 
								 | 
							
								<p>This is what filtering is about.</p>
							 | 
						||
| 
								 | 
							
								<p>If it was Photoshop, Photoshop would average nearly all the pixels together to figure out what color
							 | 
						||
| 
								 | 
							
								to make those 1 or 2 pixels. That would be a very slow operation. GPUs solve this issue
							 | 
						||
| 
								 | 
							
								using mipmaps.</p>
							 | 
						||
| 
								 | 
							
								<p>Mips are copies of the texture, each one half as wide and half as tall as the previous
							 | 
						||
| 
								 | 
							
								mip where the pixels have been blended to make the next smaller mip. Mips are created
							 | 
						||
| 
								 | 
							
								until we get all the way to a 1x1 pixel mip. For the image above all of the mips would
							 | 
						||
| 
								 | 
							
								end up being something like this</p>
							 | 
						||
| 
								 | 
							
								<div class="threejs_center"><img src="../resources/images/mipmap-low-res-enlarged.png" class="nobg" align="center"></div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<p>Now, when the cube is drawn so small that it's only 1 or 2 pixels large the GPU can choose
							 | 
						||
| 
								 | 
							
								to use just the smallest or next to smallest mip level to decide what color to make the
							 | 
						||
| 
								 | 
							
								tiny cube.</p>
							 | 
						||
| 
								 | 
							
								<p>In three.js you can choose what happens both when the texture is drawn
							 | 
						||
| 
								 | 
							
								larger than its original size and what happens when it's drawn smaller than its
							 | 
						||
| 
								 | 
							
								original size.</p>
							 | 
						||
| 
								 | 
							
								<p>For setting the filter when the texture is drawn larger than its original size
							 | 
						||
| 
								 | 
							
								you set <a href="/docs/#api/en/textures/Texture#magFilter"><code class="notranslate" translate="no">texture.magFilter</code></a> property to either <code class="notranslate" translate="no">THREE.NearestFilter</code> or
							 | 
						||
| 
								 | 
							
								 <code class="notranslate" translate="no">THREE.LinearFilter</code>.  <code class="notranslate" translate="no">NearestFilter</code> means
							 | 
						||
| 
								 | 
							
								just pick the closet single pixel from the original texture. With a low
							 | 
						||
| 
								 | 
							
								resolution texture this gives you a very pixelated look like Minecraft.</p>
							 | 
						||
| 
								 | 
							
								<p><code class="notranslate" translate="no">LinearFilter</code> means choose the 4 pixels from the texture that are closest
							 | 
						||
| 
								 | 
							
								to the where we should be choosing a color from and blend them in the
							 | 
						||
| 
								 | 
							
								appropriate proportions relative to how far away the actual point is from
							 | 
						||
| 
								 | 
							
								each of the 4 pixels.</p>
							 | 
						||
| 
								 | 
							
								<div class="spread">
							 | 
						||
| 
								 | 
							
								  <div>
							 | 
						||
| 
								 | 
							
								    <div data-diagram="filterCubeMagNearest" style="height: 250px;"></div>
							 | 
						||
| 
								 | 
							
								    <div class="code">Nearest</div>
							 | 
						||
| 
								 | 
							
								  </div>
							 | 
						||
| 
								 | 
							
								  <div>
							 | 
						||
| 
								 | 
							
								    <div data-diagram="filterCubeMagLinear" style="height: 250px;"></div>
							 | 
						||
| 
								 | 
							
								    <div class="code">Linear</div>
							 | 
						||
| 
								 | 
							
								  </div>
							 | 
						||
| 
								 | 
							
								</div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<p>For setting the filter when the texture is drawn smaller than its original size
							 | 
						||
| 
								 | 
							
								you set the <a href="/docs/#api/en/textures/Texture#minFilter"><code class="notranslate" translate="no">texture.minFilter</code></a> property to one of 6 values.</p>
							 | 
						||
| 
								 | 
							
								<ul>
							 | 
						||
| 
								 | 
							
								<li><p><code class="notranslate" translate="no">THREE.NearestFilter</code></p>
							 | 
						||
| 
								 | 
							
								<p> same as above, choose the closest pixel in the texture</p>
							 | 
						||
| 
								 | 
							
								</li>
							 | 
						||
| 
								 | 
							
								<li><p><code class="notranslate" translate="no">THREE.LinearFilter</code></p>
							 | 
						||
| 
								 | 
							
								<p> same as above, choose 4 pixels from the texture and blend them</p>
							 | 
						||
| 
								 | 
							
								</li>
							 | 
						||
| 
								 | 
							
								<li><p><code class="notranslate" translate="no">THREE.NearestMipmapNearestFilter</code></p>
							 | 
						||
| 
								 | 
							
								<p> choose the appropriate mip then choose one pixel</p>
							 | 
						||
| 
								 | 
							
								</li>
							 | 
						||
| 
								 | 
							
								<li><p><code class="notranslate" translate="no">THREE.NearestMipmapLinearFilter</code></p>
							 | 
						||
| 
								 | 
							
								<p> choose 2 mips, choose one pixel from each, blend the 2 pixels</p>
							 | 
						||
| 
								 | 
							
								</li>
							 | 
						||
| 
								 | 
							
								<li><p><code class="notranslate" translate="no">THREE.LinearMipmapNearestFilter</code></p>
							 | 
						||
| 
								 | 
							
								<p> chose the appropriate mip then choose 4 pixels and blend them</p>
							 | 
						||
| 
								 | 
							
								</li>
							 | 
						||
| 
								 | 
							
								<li><p><code class="notranslate" translate="no">THREE.LinearMipmapLinearFilter</code></p>
							 | 
						||
| 
								 | 
							
								<p>choose 2 mips, choose 4 pixels from each and blend all 8 into 1 pixel</p>
							 | 
						||
| 
								 | 
							
								</li>
							 | 
						||
| 
								 | 
							
								</ul>
							 | 
						||
| 
								 | 
							
								<p>Here's an example showing all 6 settings</p>
							 | 
						||
| 
								 | 
							
								<div class="spread">
							 | 
						||
| 
								 | 
							
								  <div data-diagram="filterModes" style="
							 | 
						||
| 
								 | 
							
								    height: 450px;
							 | 
						||
| 
								 | 
							
								    position: relative;
							 | 
						||
| 
								 | 
							
								  ">
							 | 
						||
| 
								 | 
							
								    <div style="
							 | 
						||
| 
								 | 
							
								      width: 100%;
							 | 
						||
| 
								 | 
							
								      height: 100%;
							 | 
						||
| 
								 | 
							
								      display: flex;
							 | 
						||
| 
								 | 
							
								      align-items: center;
							 | 
						||
| 
								 | 
							
								      justify-content: flex-start;
							 | 
						||
| 
								 | 
							
								    ">
							 | 
						||
| 
								 | 
							
								      <div style="
							 | 
						||
| 
								 | 
							
								        background: rgba(255,0,0,.8);
							 | 
						||
| 
								 | 
							
								        color: white;
							 | 
						||
| 
								 | 
							
								        padding: .5em;
							 | 
						||
| 
								 | 
							
								        margin: 1em;
							 | 
						||
| 
								 | 
							
								        font-size: small;
							 | 
						||
| 
								 | 
							
								        border-radius: .5em;
							 | 
						||
| 
								 | 
							
								        line-height: 1.2;
							 | 
						||
| 
								 | 
							
								        user-select: none;">click to<br>change<br>texture</div>
							 | 
						||
| 
								 | 
							
								    </div>
							 | 
						||
| 
								 | 
							
								    <div class="filter-caption" style="left: 0.5em; top: 0.5em;">nearest</div>
							 | 
						||
| 
								 | 
							
								    <div class="filter-caption" style="width: 100%; text-align: center; top: 0.5em;">linear</div>
							 | 
						||
| 
								 | 
							
								    <div class="filter-caption" style="right: 0.5em; text-align: right; top: 0.5em;">nearest<br>mipmap<br>nearest</div>
							 | 
						||
| 
								 | 
							
								    <div class="filter-caption" style="left: 0.5em; text-align: left; bottom: 0.5em;">nearest<br>mipmap<br>linear</div>
							 | 
						||
| 
								 | 
							
								    <div class="filter-caption" style="width: 100%; text-align: center; bottom: 0.5em;">linear<br>mipmap<br>nearest</div>
							 | 
						||
| 
								 | 
							
								    <div class="filter-caption" style="right: 0.5em; text-align: right; bottom: 0.5em;">linear<br>mipmap<br>linear</div>
							 | 
						||
| 
								 | 
							
								  </div>
							 | 
						||
| 
								 | 
							
								</div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<p>One thing to notice is the top left and top middle using <code class="notranslate" translate="no">NearestFilter</code> and <code class="notranslate" translate="no">LinearFilter</code>
							 | 
						||
| 
								 | 
							
								don't use the mips. Because of that they flicker in the distance because the GPU is
							 | 
						||
| 
								 | 
							
								picking pixels from the original texture. On the left just one pixel is chosen and
							 | 
						||
| 
								 | 
							
								in the middle 4 are chosen and blended but it's not enough come up with a good
							 | 
						||
| 
								 | 
							
								representative color. The other 4 strips do better with the bottom right,
							 | 
						||
| 
								 | 
							
								<code class="notranslate" translate="no">LinearMipmapLinearFilter</code> being best.</p>
							 | 
						||
| 
								 | 
							
								<p>If you click the picture above it will toggle between the texture we've been using above
							 | 
						||
| 
								 | 
							
								and a texture where every mip level is a different color.</p>
							 | 
						||
| 
								 | 
							
								<div class="threejs_center">
							 | 
						||
| 
								 | 
							
								  <div data-texture-diagram="differentColoredMips"></div>
							 | 
						||
| 
								 | 
							
								</div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<p>This makes it more clear
							 | 
						||
| 
								 | 
							
								what is happening. You can see in the top left and top middle the first mip is used all the way
							 | 
						||
| 
								 | 
							
								into the distance. The top right and bottom middle you can clearly see where a different mip
							 | 
						||
| 
								 | 
							
								is used.</p>
							 | 
						||
| 
								 | 
							
								<p>Switching back to the original texture you can see the bottom right is the smoothest,
							 | 
						||
| 
								 | 
							
								highest quality. You might ask why not always use that mode. The most obvious reason
							 | 
						||
| 
								 | 
							
								is sometimes you want things to be pixelated for a retro look or some other reason.
							 | 
						||
| 
								 | 
							
								The next most common reason is that reading 8 pixels and blending them is slower
							 | 
						||
| 
								 | 
							
								than reading 1 pixel and blending. While it's unlikely that a single texture is going
							 | 
						||
| 
								 | 
							
								to be the difference between fast and slow as we progress further into these articles
							 | 
						||
| 
								 | 
							
								we'll eventually have materials that use 4 or 5 textures all at once. 4 textures * 8
							 | 
						||
| 
								 | 
							
								pixels per texture is looking up 32 pixels for ever pixel rendered.
							 | 
						||
| 
								 | 
							
								This can be especially important to consider on mobile devices.</p>
							 | 
						||
| 
								 | 
							
								<h2 id="-a-name-uvmanipulation-a-repeating-offseting-rotating-wrapping-a-texture"><a name="uvmanipulation"></a> Repeating, offseting, rotating, wrapping a texture</h2>
							 | 
						||
| 
								 | 
							
								<p>Textures have settings for repeating, offseting, and rotating a texture.</p>
							 | 
						||
| 
								 | 
							
								<p>By default textures in three.js do not repeat. To set whether or not a
							 | 
						||
| 
								 | 
							
								texture repeats there are 2 properties, <a href="/docs/#api/en/textures/Texture#wrapS"><code class="notranslate" translate="no">wrapS</code></a> for horizontal wrapping
							 | 
						||
| 
								 | 
							
								and <a href="/docs/#api/en/textures/Texture#wrapT"><code class="notranslate" translate="no">wrapT</code></a> for vertical wrapping.</p>
							 | 
						||
| 
								 | 
							
								<p>They can be set to one of:</p>
							 | 
						||
| 
								 | 
							
								<ul>
							 | 
						||
| 
								 | 
							
								<li><p><code class="notranslate" translate="no">THREE.ClampToEdgeWrapping</code></p>
							 | 
						||
| 
								 | 
							
								<p> the last pixel on each edge is repeated forever</p>
							 | 
						||
| 
								 | 
							
								</li>
							 | 
						||
| 
								 | 
							
								<li><p><code class="notranslate" translate="no">THREE.RepeatWrapping</code></p>
							 | 
						||
| 
								 | 
							
								<p> the texture is repeated</p>
							 | 
						||
| 
								 | 
							
								</li>
							 | 
						||
| 
								 | 
							
								<li><p><code class="notranslate" translate="no">THREE.MirroredRepeatWrapping</code></p>
							 | 
						||
| 
								 | 
							
								<p> the texture is mirrored and repeated</p>
							 | 
						||
| 
								 | 
							
								</li>
							 | 
						||
| 
								 | 
							
								</ul>
							 | 
						||
| 
								 | 
							
								<p>For example to turn on wrapping in both directions:</p>
							 | 
						||
| 
								 | 
							
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">someTexture.wrapS = THREE.RepeatWrapping;
							 | 
						||
| 
								 | 
							
								someTexture.wrapT = THREE.RepeatWrapping;
							 | 
						||
| 
								 | 
							
								</pre>
							 | 
						||
| 
								 | 
							
								<p>Repeating is set with the [repeat] repeat property.</p>
							 | 
						||
| 
								 | 
							
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const timesToRepeatHorizontally = 4;
							 | 
						||
| 
								 | 
							
								const timesToRepeatVertically = 2;
							 | 
						||
| 
								 | 
							
								someTexture.repeat.set(timesToRepeatHorizontally, timesToRepeatVertically);
							 | 
						||
| 
								 | 
							
								</pre>
							 | 
						||
| 
								 | 
							
								<p>Offseting the texture can be done by setting the <code class="notranslate" translate="no">offset</code> property. Textures
							 | 
						||
| 
								 | 
							
								are offset with units where 1 unit = 1 texture size. On other words 0 = no offset
							 | 
						||
| 
								 | 
							
								and 1 = offset one full texture amount.</p>
							 | 
						||
| 
								 | 
							
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const xOffset = .5;   // offset by half the texture
							 | 
						||
| 
								 | 
							
								const yOffset = .25;  // offset by 1/4 the texture
							 | 
						||
| 
								 | 
							
								someTexture.offset.set(xOffset, yOffset);
							 | 
						||
| 
								 | 
							
								</pre>
							 | 
						||
| 
								 | 
							
								<p>Rotating the texture can be set by setting the <code class="notranslate" translate="no">rotation</code> property in radians
							 | 
						||
| 
								 | 
							
								as well as the <code class="notranslate" translate="no">center</code> property for choosing the center of rotation.
							 | 
						||
| 
								 | 
							
								It defaults to 0,0 which rotates from the bottom left corner. Like offset
							 | 
						||
| 
								 | 
							
								these units are in texture size so setting them to <code class="notranslate" translate="no">.5, .5</code> would rotate
							 | 
						||
| 
								 | 
							
								around the center of the texture.</p>
							 | 
						||
| 
								 | 
							
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">someTexture.center.set(.5, .5);
							 | 
						||
| 
								 | 
							
								someTexture.rotation = THREE.MathUtils.degToRad(45);
							 | 
						||
| 
								 | 
							
								</pre>
							 | 
						||
| 
								 | 
							
								<p>Let's modify the top sample above to play with these values</p>
							 | 
						||
| 
								 | 
							
								<p>First we'll keep a reference to the texture so we can manipulate it</p>
							 | 
						||
| 
								 | 
							
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">+const texture = loader.load('resources/images/wall.jpg');
							 | 
						||
| 
								 | 
							
								const material = new THREE.MeshBasicMaterial({
							 | 
						||
| 
								 | 
							
								-  map: loader.load('resources/images/wall.jpg');
							 | 
						||
| 
								 | 
							
								+  map: texture,
							 | 
						||
| 
								 | 
							
								});
							 | 
						||
| 
								 | 
							
								</pre>
							 | 
						||
| 
								 | 
							
								<p>Then we'll use <a href="https://github.com/georgealways/lil-gui">lil-gui</a> again to provide a simple interface.</p>
							 | 
						||
| 
								 | 
							
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">import {GUI} from 'three/addons/libs/lil-gui.module.min.js';
							 | 
						||
| 
								 | 
							
								</pre>
							 | 
						||
| 
								 | 
							
								<p>As we did in previous lil-gui examples we'll use a simple class to
							 | 
						||
| 
								 | 
							
								give lil-gui an object that it can manipulate in degrees
							 | 
						||
| 
								 | 
							
								but that will set a property in radians.</p>
							 | 
						||
| 
								 | 
							
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">class DegRadHelper {
							 | 
						||
| 
								 | 
							
								  constructor(obj, prop) {
							 | 
						||
| 
								 | 
							
								    this.obj = obj;
							 | 
						||
| 
								 | 
							
								    this.prop = prop;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  get value() {
							 | 
						||
| 
								 | 
							
								    return THREE.MathUtils.radToDeg(this.obj[this.prop]);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  set value(v) {
							 | 
						||
| 
								 | 
							
								    this.obj[this.prop] = THREE.MathUtils.degToRad(v);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								</pre>
							 | 
						||
| 
								 | 
							
								<p>We also need a class that will convert from a string like <code class="notranslate" translate="no">"123"</code> into
							 | 
						||
| 
								 | 
							
								a number like <code class="notranslate" translate="no">123</code> since three.js requires numbers for enum settings
							 | 
						||
| 
								 | 
							
								like <code class="notranslate" translate="no">wrapS</code> and <code class="notranslate" translate="no">wrapT</code> but lil-gui only uses strings for enums.</p>
							 | 
						||
| 
								 | 
							
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">class StringToNumberHelper {
							 | 
						||
| 
								 | 
							
								  constructor(obj, prop) {
							 | 
						||
| 
								 | 
							
								    this.obj = obj;
							 | 
						||
| 
								 | 
							
								    this.prop = prop;
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  get value() {
							 | 
						||
| 
								 | 
							
								    return this.obj[this.prop];
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								  set value(v) {
							 | 
						||
| 
								 | 
							
								    this.obj[this.prop] = parseFloat(v);
							 | 
						||
| 
								 | 
							
								  }
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								</pre>
							 | 
						||
| 
								 | 
							
								<p>Using those classes we can setup a simple GUI for the settings above</p>
							 | 
						||
| 
								 | 
							
								<pre class="prettyprint showlinemods notranslate lang-js" translate="no">const wrapModes = {
							 | 
						||
| 
								 | 
							
								  'ClampToEdgeWrapping': THREE.ClampToEdgeWrapping,
							 | 
						||
| 
								 | 
							
								  'RepeatWrapping': THREE.RepeatWrapping,
							 | 
						||
| 
								 | 
							
								  'MirroredRepeatWrapping': THREE.MirroredRepeatWrapping,
							 | 
						||
| 
								 | 
							
								};
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								function updateTexture() {
							 | 
						||
| 
								 | 
							
								  texture.needsUpdate = true;
							 | 
						||
| 
								 | 
							
								}
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								const gui = new GUI();
							 | 
						||
| 
								 | 
							
								gui.add(new StringToNumberHelper(texture, 'wrapS'), 'value', wrapModes)
							 | 
						||
| 
								 | 
							
								  .name('texture.wrapS')
							 | 
						||
| 
								 | 
							
								  .onChange(updateTexture);
							 | 
						||
| 
								 | 
							
								gui.add(new StringToNumberHelper(texture, 'wrapT'), 'value', wrapModes)
							 | 
						||
| 
								 | 
							
								  .name('texture.wrapT')
							 | 
						||
| 
								 | 
							
								  .onChange(updateTexture);
							 | 
						||
| 
								 | 
							
								gui.add(texture.repeat, 'x', 0, 5, .01).name('texture.repeat.x');
							 | 
						||
| 
								 | 
							
								gui.add(texture.repeat, 'y', 0, 5, .01).name('texture.repeat.y');
							 | 
						||
| 
								 | 
							
								gui.add(texture.offset, 'x', -2, 2, .01).name('texture.offset.x');
							 | 
						||
| 
								 | 
							
								gui.add(texture.offset, 'y', -2, 2, .01).name('texture.offset.y');
							 | 
						||
| 
								 | 
							
								gui.add(texture.center, 'x', -.5, 1.5, .01).name('texture.center.x');
							 | 
						||
| 
								 | 
							
								gui.add(texture.center, 'y', -.5, 1.5, .01).name('texture.center.y');
							 | 
						||
| 
								 | 
							
								gui.add(new DegRadHelper(texture, 'rotation'), 'value', -360, 360)
							 | 
						||
| 
								 | 
							
								  .name('texture.rotation');
							 | 
						||
| 
								 | 
							
								</pre>
							 | 
						||
| 
								 | 
							
								<p>The last thing to note about the example is that if you change <code class="notranslate" translate="no">wrapS</code> or
							 | 
						||
| 
								 | 
							
								<code class="notranslate" translate="no">wrapT</code> on the texture you must also set <a href="/docs/#api/en/textures/Texture#needsUpdate"><code class="notranslate" translate="no">texture.needsUpdate</code></a>
							 | 
						||
| 
								 | 
							
								so three.js knows to apply those settings. The other settings are automatically applied.</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/textured-cube-adjust.html"></iframe></div>
							 | 
						||
| 
								 | 
							
								  <a class="threejs_center" href="/manual/examples/textured-cube-adjust.html" target="_blank">click here to open in a separate window</a>
							 | 
						||
| 
								 | 
							
								</div>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								<p></p>
							 | 
						||
| 
								 | 
							
								<p>This is only one step into the topic of textures. At some point we'll go over
							 | 
						||
| 
								 | 
							
								texture coordinates as well as 9 other types of textures that can be applied
							 | 
						||
| 
								 | 
							
								to materials.</p>
							 | 
						||
| 
								 | 
							
								<p>For now let's move on to <a href="lights.html">lights</a>.</p>
							 | 
						||
| 
								 | 
							
								<!--
							 | 
						||
| 
								 | 
							
								alpha
							 | 
						||
| 
								 | 
							
								ao
							 | 
						||
| 
								 | 
							
								env
							 | 
						||
| 
								 | 
							
								light
							 | 
						||
| 
								 | 
							
								specular
							 | 
						||
| 
								 | 
							
								bumpmap ?
							 | 
						||
| 
								 | 
							
								normalmap ?
							 | 
						||
| 
								 | 
							
								metalness
							 | 
						||
| 
								 | 
							
								roughness
							 | 
						||
| 
								 | 
							
								-->
							 | 
						||
| 
								 | 
							
								<p><link rel="stylesheet" href="../resources/threejs-textures.css"></p>
							 | 
						||
| 
								 | 
							
								<script type="module" src="../resources/threejs-textures.js"></script>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        </div>
							 | 
						||
| 
								 | 
							
								      </div>
							 | 
						||
| 
								 | 
							
								    </div>
							 | 
						||
| 
								 | 
							
								  
							 | 
						||
| 
								 | 
							
								  <script src="/manual/resources/prettify.js"></script>
							 | 
						||
| 
								 | 
							
								  <script src="/manual/resources/lesson.js"></script>
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								</body></html>
							 |