PROWAREtech

articles » current » javascript » three-js » survival-guide

ThreeJS: A Survival Guide

A tutorial on the basics of THREE.js and a guide to more advanced features including examples, information about mesh materials both reflective and not, lighting, groups, textures and how to load them, displacement and alpha maps, and how to modify a scene during the window scroll event.

This guide requires a basic understanding of JavaScript.

The THREE.js library used in the following examples is version 147 and may be downloaded here: THREEJS.zip. It is incompatible with Internet Explorer 11 (IE11).

This is a guide to the basics for getting started. For the THREE.js full documentation see the THREE.js site.

What is THREE.js

THREE.js is a WebGL plug-in based on JavaScript. It works straight from the browser and is used to power games, advertisements or any other GPU-powered apps. JavaScript is an interpreted language and as a result, THREE.js cannot perform as well as a language like C/C++ which is compiled and linked to a hardware platform.

The Basics of THREE.js

WebGL and THREE.js require at least one of the special <CANVAS> HTML tags to be in the HTML document. The <CANVAS> tag is used to draw graphics, on the fly, via JavaScript scripting.

THREE.js is based around a single scene which is a container with objects like a camera, planes, cubes, spheres, and much more... Every THREE.js application requires a renderer and an function that animates the scene, but lights are optional depending on whether or not the other objects in the scene reflect light (some objects do not reflect light and therefore do not need it to be seen). Every object has a mesh, which is simply a material associated with it.

Three dimensional means having or appearing to have length, breadth, and depth, so all objects on the scene have x, y and z positions as well as x, y and z rotations.

Here are all the steps, one by one, to creating a very basic THREE.js scene using JavaScript:

  1. Create the HTML document with at least one <CANVAS> tag (or create one dynamically).
  2. Add the THREE.js JavaScript library to the HTML document before any code that requires it.
  3. Add a script to the HTML document.
  4. Create the scene container object which has a default background color of black.
  5. Set the scene background color (orange in the case of the following example).
  6. Create one or more objects with a surface material (mesh).
  7. Rotate/position the object(s) as needed for the scene (this can be done during the animation of the scene, or as the window is scrolled, which is covered near the end of this guide).
  8. Create a perspective camera with its field of view, aspect ratio, near and far frustum (how near and far the camera can see).
  9. Set the camera position in space and add it to the scene.
  10. Create the scene renderer passing it the canvas to use.
  11. Set the renderer's device pixel ratio which is available from the browser.
  12. Set the renderer's size which is based on the size of the canvas.
  13. Finally, create the animation function:
    1. Rotate and/or move any objects if so desired in the animation function.
    2. Call renderer.render() with the scene and camera as parameters.
    3. Call the THREE.js requestAnimationFrame() function passing it the animation function as a parameter.
    4. Call the animation function once to get it started.

Here is a full example of the above steps:


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>THREE.js - Basic Example</title>
</head>
<body style="background-color:#FFFFFF;">
	<canvas style="display: block; width: 300px; height: 300px;"></canvas>
	<script src="/js/three.min.js"></script>
	<script type="text/javascript">

		// NOTE: get the canvas element - this can be created with document.createElement("canvas") and added with document.body.appendChild(createdCanvasObject);
		var canvas = document.getElementsByTagName("canvas")[0];

		var scene = new THREE.Scene();
		scene.background = new THREE.Color(0xFF8000); // NOTE: color 0xFF8000 is the same as the CSS color #FF8000 which is simply orange in this case

		var cubeSize = 2;
		var cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
		var materials = {}; // NOTE: use an object to store mesh objects
		materials.white = new THREE.MeshBasicMaterial({ color: 0xFFFFFF });
		materials.silver = new THREE.MeshBasicMaterial({ color: 0xCCCCCC });
		materials.lightgray = new THREE.MeshBasicMaterial({ color: 0x999999 });
		materials.gray = new THREE.MeshBasicMaterial({ color: 0x666666 });
		materials.darkgray = new THREE.MeshBasicMaterial({ color: 0x333333 });
		materials.black = new THREE.MeshBasicMaterial({ color: 0x000000 });
		var cubeSides = [];
		cubeSides.push(materials.white); // NOTE: right side of cube
		cubeSides.push(materials.silver); // NOTE: left side of cube
		cubeSides.push(materials.lightgray); // NOTE: top of cube 
		cubeSides.push(materials.gray); // NOTE: bottom of cube
		cubeSides.push(materials.darkgray); // NOTE: front of the cube
		cubeSides.push(materials.black); // NOTE: back of cube
		var cube = new THREE.Mesh(cubeGeometry, cubeSides);
		scene.add(cube);

		var fieldOfView = 75; // NOTE: this is in degrees and is the vertical field of view
		var aspectRatio = canvas.offsetWidth / canvas.offsetHeight;
		var near = 1;
		var far = 10000;
		// NOTE: "near" and "far" define the frustum which is the region in the 3D space that is going to be projected to the screen
		var camera = new THREE.PerspectiveCamera(fieldOfView, aspectRatio, near, far);
		camera.position.z = 5; // NOTE: position the camera back from the scene some so as to "see" the objects
		scene.add(camera);

		var renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
		renderer.setPixelRatio(window.devicePixelRatio);
		renderer.setSize(canvas.offsetWidth, canvas.offsetHeight);

		// NOTE: required animation function
		function animate() {

			// NOTE: move the cube around
			cube.rotation.x += 0.001;
			cube.rotation.y += 0.002;
			cube.rotation.z += 0.003;

			renderer.render(scene, camera); // NOTE: render the scene
			requestAnimationFrame(animate); // NOTE: call the animate function when the next frame is ready, typically 60 per second
		}
		animate(); // NOTE: call animation function once to get it started

	</script>
</body>
</html>

Reflective Materials and Lights

Besides the THREE.MeshBasicMaterial which is non-reflective, there are several materials available with different reflective qualities. THREE.MeshStandardMaterial is used for any surface. THREE.MeshLambertMaterial is used to simulate surfaces without shine, like a natural, unvarnished wood surface. THREE.MeshPhongMaterial is used to simulate shiny surfaces, like polished stone or wood with varnish. These last three surfaces require a light be added to the scene. THREE.MeshBasicMaterial requires no light.

Lights are required when using materials with reflective qualities. There are several lights all with different qualities. THREE.AmbientLight shines from every direction. THREE.DirectionalLight is light like that of the sun, directional, and its rays are all parallel. It can cast shadows. THREE.PointLight is like a lightbulb, which is also directional and can cast shadows, but for shadows the THREE.DirectionalLight seems best. Lights can emit any color, not just white.

Here is an example using these lights and reflective materials (notice that there can be subtle differences of each light on the spheres):


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>THREE.js - Lights and Materials Example</title>
</head>
<body style="background-color:#FFFFFF; font-size:10px;">
	<table style="width:300px;"><tr><th>BasicMaterial</th><th>LambertMaterial</th><th>PhongMaterial</th></tr></table>
	<canvas style="display: inline-block; width: 300px; height: 300px;"></canvas>
	<table style="display:inline-block;"><tr style="height: 100px;"><td>spheres</td></tr><tr style="height: 100px;"><td>cubes</td></tr><tr style="height: 100px;"><td>planes</td></tr></table>
	<div>
		<label><input type="radio" name="light" onclick="setLight(['ambient']);" />AmbientLight</label><br />
		<label><input type="radio" name="light" onclick="setLight(['directional']);" />DirectionalLight</label><br />
		<label><input type="radio" name="light" onclick="setLight(['point']);" />PointLight</label><br />
		<label><input type="radio" name="light" onclick="setLight(['hemisphere']);" />HemisphereLight</label><br />
		<label><input type="radio" name="light" onclick="setLight(['spot']);" />SpotLight</label><br />
		<label><input type="radio" name="light" onclick="setLight(['ambient','directional']);" checked />AmbientLight+DirectionalLight</label><br />
		<label><input type="radio" name="light" onclick="setLight(['ambient','point']);" />AmbientLight+PointLight</label><br />
		<label><input type="radio" name="light" onclick="setLight(['directional','hemisphere']);" />DirectionalLight+HemisphereLight</label><br />
		<label><input type="radio" name="light" onclick="setLight(['ambient','hemisphere']);" />AmbientLight+HemisphereLight</label><br />
		<label><input type="radio" name="light" onclick="setLight(['ambient','spot']);" />AmbientLight+SpotLight</label><br />
		<label><input type="radio" name="light" onclick="setLight([]);" />None</label><br />
	</div>
	<script src="/js/three.min.js"></script>
	<script type="text/javascript">

		var canvas = document.getElementsByTagName("canvas")[0]; // NOTE: get the canvas element - this can be created with document.createElement("canvas") and added with document.body.appendChild(createdCanvasObject);

		var scene = new THREE.Scene();
		scene.background = new THREE.Color(0xFF8000); // NOTE: color 0xFF8000 is the same as the CSS color #FF8000 which is simply orange in this case

		function createCube(size, material) {
			var geometry = new THREE.BoxGeometry(size, size, size);
			return new THREE.Mesh(geometry, material);
		}
		function createSphere(size, material) {
			var geometry = new THREE.SphereGeometry(size);
			return new THREE.Mesh(geometry, material);
		}
		function createPlane(size, material) {
			var geometry = new THREE.PlaneGeometry(size, size);
			return new THREE.Mesh(geometry, material);
		}
		var materials = {};
		materials.basic = new THREE.MeshBasicMaterial({ color: 0x6699CC });
		materials.lambert = new THREE.MeshLambertMaterial({ color: 0x6699CC });
		materials.phong = new THREE.MeshPhongMaterial({ color: 0x6699CC, shininess: 20 });

		var objects = {};
		objects.basicCube = createCube(1, materials.basic);
		objects.basicCube.position.x = -2;
		scene.add(objects.basicCube);
		objects.lambertCube = createCube(1, materials.lambert);
		scene.add(objects.lambertCube);
		objects.phongCube = createCube(1, materials.phong);
		objects.phongCube.position.x = 2;
		scene.add(objects.phongCube);

		objects.basicSphere = createSphere(.67, materials.basic);
		objects.basicSphere.position.x = -2;
		objects.basicSphere.position.y = 2;
		scene.add(objects.basicSphere);
		objects.lambertSphere = createSphere(.67, materials.lambert);
		objects.lambertSphere.position.y = 2;
		scene.add(objects.lambertSphere);
		objects.phongSphere = createSphere(.67, materials.phong);
		objects.phongSphere.position.x = 2;
		objects.phongSphere.position.y = 2;
		scene.add(objects.phongSphere);

		objects.basicPlane = createPlane(1, materials.basic);
		objects.basicPlane.position.x = -2;
		objects.basicPlane.position.y = -2;
		scene.add(objects.basicPlane);
		objects.lambertPlane = createPlane(1, materials.lambert);
		objects.lambertPlane.position.y = -2;
		scene.add(objects.lambertPlane);
		objects.phongPlane = createPlane(1, materials.phong);
		objects.phongPlane.position.x = 2;
		objects.phongPlane.position.y = -2;
		scene.add(objects.phongPlane);

		for(var object in objects) {
			objects[object].castShadow = objects[object].receiveShadow = true;
		}

		var back = createPlane(1000, new THREE.MeshLambertMaterial({ color: 0xCCCCCC }));
		back.receiveShadow = true;
		back.position.z = -3;
		back.rotation.x = Math.PI * -0.142857143;
		scene.add(back);

		var lights = {};

		lights.ambient = new THREE.AmbientLight(0xffffff, .5);

		lights.hemisphere = new THREE.HemisphereLight(0xffffff, 0x080820, 1);

		lights.directional = new THREE.DirectionalLight(0xffffff, 1);
		lights.directional.position.set(10, 25, 15);

		lights.point = new THREE.PointLight(0xffffff, 1);
		lights.point.position.set(10, 25, 15);

		lights.spot = new THREE.SpotLight(0xffffff);
		lights.spot.position.set(10, 25, 15);

		function setLight(lightNames) {
			for(var light in lights) {
				scene.remove(lights[light]);
			}
			for(var i = 0; i < lightNames.length; i++) {
				scene.add(lights[lightNames[i]]);
			}
		}
		setLight(['ambient','directional']);

		var fieldOfView = 10; // NOTE: this is in degrees and is the vertical field of view
		var aspectRatio = canvas.offsetWidth / canvas.offsetHeight;
		var near = 1;
		var far = 10000;
		var camera = new THREE.PerspectiveCamera(fieldOfView, aspectRatio, near, far);
		camera.position.z = 40; // NOTE: position the camera back from the scene some so as to "see" the objects
		scene.add(camera);

		var setShadow = function (light) {
			light.castShadow = true;
			light.shadow.mapSize.width = 1024;
			light.shadow.mapSize.height = 1024;
			light.shadow.camera.near = near;
			light.shadow.camera.far = far;
		};
		setShadow(lights.directional);
		setShadow(lights.point);
		setShadow(lights.spot);

		var renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
		renderer.shadowMap.enabled = true;
		renderer.setPixelRatio(window.devicePixelRatio);
		renderer.setSize(canvas.offsetWidth, canvas.offsetHeight);

		// NOTE: animation function which rotates the cube
		function animate() {
			for(var object in objects) {
				objects[object].rotation.x += 0.006;
				objects[object].rotation.y += 0.009;
				objects[object].rotation.z += 0.012;
			}
			renderer.render(scene, camera); // NOTE: render the scene
			requestAnimationFrame(animate); // NOTE: call the animate function when the next frame is ready, typically 60 frames-per-second
		}
		animate(); // NOTE: call animation function once to get it started

	</script>
</body>
</html>

Object Groups

Groups are designed to make it simple to create a single object out of several basic objects by grouping them together into one. They may still be controlled individually but they can be rotated and positioned as a whole by setting the group's rotation and position properties. Groups make it possible to create a city, for example, with all the individual objects contained within a city group including people, cars, houses, etc. which are also groups themselves.

In this example, a group is used to add all the objects together so that they may be rotated in space as one unit:


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>THREE.js - Grouping Example</title>
</head>
<body style="background-color:#FFFFFF;">
	<canvas style="display: block; width: 300px; height: 300px;"></canvas>
	<script src="/js/three.min.js"></script>
	<script type="text/javascript">

		var canvas = document.getElementsByTagName("canvas")[0]; // NOTE: get the canvas element - this can be created with document.createElement("canvas") and added with document.body.appendChild(createdCanvasObject);

		var scene = new THREE.Scene();
		scene.background = new THREE.Color(0xFF8000); // NOTE: color 0xFF8000 is the same as the CSS color #FF8000 which is simply orange in this case

		var group = new THREE.Group(); // NOTE: create a group to add objects to
		
		function createCube(size, material) {
			var geometry = new THREE.BoxGeometry(size, size, size);
			return new THREE.Mesh(geometry, material);
		}
		function createSphere(size, material) {
			var geometry = new THREE.SphereGeometry(size);
			return new THREE.Mesh(geometry, material);
		}
		function createTorus(size, material) {
			var geometry = new THREE.TorusGeometry(size, size / 2, 16, 100);
			return new THREE.Mesh(geometry, material);
		}
		var materials = {};
		materials.lambert = new THREE.MeshLambertMaterial({ color: 0x6699CC });
		materials.phong = new THREE.MeshPhongMaterial({ color: 0x6699CC });

		var objects = {};
		objects.lambertCube = createCube(1, materials.lambert);
		objects.lambertCube.position.x = -1;
		group.add(objects.lambertCube);
		objects.phongCube = createCube(1, materials.phong);
		objects.phongCube.position.x = 1;
		group.add(objects.phongCube);

		objects.lambertSphere = createSphere(.67, materials.lambert);
		objects.lambertSphere.position.x = -1;
		objects.lambertSphere.position.y = 2;
		group.add(objects.lambertSphere);
		objects.phongSphere = createSphere(.67, materials.phong);
		objects.phongSphere.position.x = 1;
		objects.phongSphere.position.y = 2;
		group.add(objects.phongSphere);

		objects.lambertPlane = createTorus(.5, materials.lambert);
		objects.lambertPlane.position.x = -1;
		objects.lambertPlane.position.y = -2;
		group.add(objects.lambertPlane);
		objects.phongPlane = createTorus(.5, materials.phong);
		objects.phongPlane.position.x = 1;
		objects.phongPlane.position.y = -2;
		group.add(objects.phongPlane);

		scene.add(group);

		var lights = {};
		lights.ambient = new THREE.AmbientLight(0xffffff, .5);

		lights.directional = new THREE.DirectionalLight(0xffffff, 1);
		lights.directional.position.set(10, 25, 15);

		function setLight(lightNames) {
			for(var light in lights) {
				scene.remove(lights[light]);
			}
			for(var i = 0; i < lightNames.length; i++) {
				scene.add(lights[lightNames[i]]);
			}
		}
		setLight(['ambient','directional']);

		var fieldOfView = 10; // NOTE: this is in degrees and is the vertical field of view
		var aspectRatio = canvas.offsetWidth / canvas.offsetHeight;
		var near = 1;
		var far = 10000;
		var camera = new THREE.PerspectiveCamera(fieldOfView, aspectRatio, near, far);
		camera.position.z = 40; // NOTE: position the camera back from the scene some so as to "see" the objects
		scene.add(camera);

		var renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
		renderer.setPixelRatio(window.devicePixelRatio);
		renderer.setSize(canvas.offsetWidth, canvas.offsetHeight);

		// NOTE: animation function which rotates the cube
		function animate() {

			// NOTE: rotate each object
			for(var object in objects) {
				objects[object].rotation.x += 0.006;
				objects[object].rotation.y += 0.009;
				objects[object].rotation.z += 0.012;
			}

			// NOTE: rotate the whole group of objects
			group.rotation.x += 0.01;
			group.rotation.y += 0.02;

			renderer.render(scene, camera); // NOTE: render the scene
			requestAnimationFrame(animate); // NOTE: call the animate function when the next frame is ready, typically 60 frames-per-second
		}
		animate(); // NOTE: call animation function once to get it started

	</script>
</body>
</html>

Using Textures and the TextureLoader

The THREE.TextureLoader is used for loading textures which are then set to objects.

Settings the Scene Background

In this example, the scene background (scene.background) is set using the texture loader.


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>THREE.js - Background Example</title>
</head>
<body style="background-color:#FFFFFF;">
	<canvas style="display: block; width: 300px; height: 300px;"></canvas>
	<script src="/js/three.min.js"></script>
	<script type="text/javascript">

		// NOTE: this is an image in base64 format; a url to an image can be used such as:
		// var stars = "/images/stars.jpg";
		var stars = "data:image/jpeg;base64,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";

		// NOTE: get the canvas element - this can be created with document.createElement("canvas") and added with document.body.appendChild(createdCanvasObject);
		var canvas = document.getElementsByTagName("canvas")[0];

		// NOTE: create the texture loader
		var loader = new THREE.TextureLoader();

		var scene = new THREE.Scene();
		// NOTE: set the background to a JPEG image of stars
		// could also be something like scene.background = loader.load("/images/stars.jpg");
		scene.background = loader.load(stars);

		var cubeSize = 2;
		var cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
		var materials = {}; // NOTE: use an object to store mesh objects
		materials.blue = new THREE.MeshPhongMaterial({ color: 0x6699CC });
		var cube = new THREE.Mesh(cubeGeometry, materials.blue);
		scene.add(cube);

		var lights = {};
		lights.ambient = new THREE.AmbientLight(0xffffff, .5);
		scene.add(lights.ambient);
		lights.directional = new THREE.DirectionalLight(0xffffff, 1);
		lights.directional.position.set(10, 25, 15);
		scene.add(lights.directional);

		var fieldOfView = 75; // NOTE: this is in degrees and is the vertical field of view
		var aspectRatio = canvas.offsetWidth / canvas.offsetHeight;
		var near = 1;
		var far = 10000;
		// NOTE: "near" and "far" define the frustum which is the region in the 3D space that is going to be projected to the screen
		var camera = new THREE.PerspectiveCamera(fieldOfView, aspectRatio, near, far);
		camera.position.z = 5; // NOTE: position the camera back from the scene some so as to "see" the objects
		scene.add(camera);

		var renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
		renderer.setPixelRatio(window.devicePixelRatio);
		renderer.setSize(canvas.offsetWidth, canvas.offsetHeight);

		// NOTE: required animation function
		function animate() {

			// NOTE: move the cube around
			cube.rotation.x += 0.001;
			cube.rotation.y += 0.002;
			cube.rotation.z += 0.003;

			renderer.render(scene, camera); // NOTE: render the scene
			requestAnimationFrame(animate); // NOTE: call the animate function when the next frame is ready, typically 60 per second
		}
		animate(); // NOTE: call animation function once to get it started

	</script>
</body>
</html>
Adding Textures to Objects

Textures can also be applied to object surfaces by "mapping" them to the mesh material.

In this example, a texture is mapped to the sides of the cube:


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>THREE.js - Add Texture to Objects Example</title>
</head>
<body style="background-color:#FFFFFF;">
	<canvas style="display: block; width: 300px; height: 300px;"></canvas>
	<script src="/js/three.min.js"></script>
	<script type="text/javascript">

		// NOTE: these images are in base64 format; a url to an image can be used such as:
		// var stars = "/images/stars.jpg";
		var stars = "data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAeAAD/7gAhQWRvYmUAZMAAAAABAwAQAwIDBgAAAhMAAAM0AAAFv//bAIQAEAsLCwwLEAwMEBcPDQ8XGxQQEBQbHxcXFxcXHx4XGhoaGhceHiMlJyUjHi8vMzMvL0BAQEBAQEBAQEBAQEBAQAERDw8RExEVEhIVFBEUERQaFBYWFBomGhocGhomMCMeHh4eIzArLicnJy4rNTUwMDU1QEA/QEBAQEBAQEBAQEBA/8IAEQgAZABkAwEiAAIRAQMRAf/EAJQAAQEBAQEBAQAAAAAAAAAAAAABAgMEBQYBAQEBAAAAAAAAAAAAAAAAAAABAhAAAgICAgIBBAIDAAAAAAAAAQIAESEDEgQQMRMgUEEUIgUyIyURAAEDAgUCBQQCAwAAAAAAAAEAEQIhMUFRYRIDEHGBkbEiE6HB0TJCFFJiBBIAAwEAAAAAAAAAAAAAAAAAAFAxQf/aAAwDAQACEQMRAAAA/ExC3A1vn2l5XNsMh15w2qXMLEsKFixDWSnql8qrEUXIstM17Tw1BZpYhLnWRYN5pZ6PNU7cevMZADVnoPMQvXnSSCtYLOmFBFhdTJLKE7clA1N5TLqMZFUJoT6vywzBb6RPcNZ//9oACAECAAEFAPqv7SPc/9oACAEDAAEFAPqr7SfU/9oACAEBAAEFAM0bhsRWpS2V07X1lsalV3NwmXNHZ3ddvka+bBSZnwCaPb3/AK6qXZ9To8o0QKnDV8gIBjAgj3AARdE3BBUUkTiKo+AYaMErl4FEgkE6iNfjrt0x18crIlkzINChc9kDLKblGG6UFjbUYilyysjeCpBKsrdX+p7vZ6xQgkEHMQMzw2fFkmyIrcCGIYsWOjvdnTpbUw1GqOTPyTnBlkSrliuLKAICRNe3bpZmLMBcx4GDxZwBPcIm3S+prxBcyScG5Yl5bvbQuZVS8PQArxYZfUdUVJwPL2ORK63+NibGZmexmDjyBy2vYqg1PyKmbqe4bHhdmKuBbA9cWXWP5Pw/2n/EzEbjZgq/6D9T9h+FmCLU6vw/J/zP3f/aAAgBAgIGPwBhlP/aAAgBAwIGPwBhsP/aAAgBAQEGPwAnBfXwVe47KQYEnHJsk1iKKXNGBPHBt0sA69SgJEQif5F2Hki1Rngg1Q1ehnwzPHIhnjditznfd8XRgCdpLkdk/wBOjumxu+K/q7j8O7fsw3WdCMQ8pFgMypccxtlAkSBwa6on8FFpPSos2iZbfk9n+bH0TsJDKv2Tm6Y4UQZaol2bA41QIdxitxrm+fTROOycGuVXTdK11TgdCRSjnoxtpdOMaKPI4aRIABrTMJj5aov9FyjmiTzFvhIoAdVo6/CcpyH0RLCtlQeCceS1Re4N3os02j2QCAFSS20XTP4Yo+iERWUqAO1fFGEg0hQjo+aG0uSAaZ5IxIIkCxGIK5v+ng4zLh4ADySyTIh3wpUKqpIRlcElrVunerus2oVVUTIiUXNYtJ6JwWILjuiT7pSLmRNSSp8HHySjx8n7xBoe6HM0hxzkYiRFDtr90wxq7Ik0PUlr+S1yVOxZaIghycXwQowNjn26HWihMgSEfdGE6xL4spSIA3VZs8kat1cC2ClMCgrIiwdZMMVVh04xzWmBMbSJHbL7ouK0YvZNYIOTogPABMQzXHR2HZPdc3Fwj4eDnYy4okt7bXqitU1yfMIRBJlj+E5rp0AAYj9j0iRPdKT7ot+pelem2j2Z8cley24O7J2BoQ0tcaIua+bpxTJk+PRjggCWD1N2COOShKUTGPJWEsCBSiYh3qmavSlNOlFW5VE3x8ZMQGkf9a4FiTiq3wTuKea7KHISJCTtF3I2nEYLczObCwW3VUs4uq+C9V7ba3X5Xutoub+z8O34eTZ8ztubBsVJrv7Wey1oy16R+b9dF/L492j3X//Z";
		var starDust = "data:image/jpeg;base64,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";

		var canvas = document.getElementsByTagName("canvas")[0];

		// NOTE: create the texture loader
		var loader = new THREE.TextureLoader();

		var scene = new THREE.Scene();
		scene.background = new THREE.Color(0xFFFFFF); // NOTE: make background white

		var cubeSize = 2;
		var cubeGeometry = new THREE.BoxGeometry(cubeSize, cubeSize, cubeSize);
		var materials = {}; // NOTE: use an object to store mesh objects
		materials.stars = new THREE.MeshPhongMaterial({ map: loader.load(stars) }); // NOTE: load the stars image and map it
		materials.starDust = new THREE.MeshPhongMaterial({ map: loader.load(starDust) }); // NOTE: load the star dust image and map it
		var sides = [];
		sides.push(materials.stars);
		sides.push(materials.stars);
		sides.push(materials.stars);
		sides.push(materials.stars);
		sides.push(materials.starDust); // NOTE: front of cube
		sides.push(materials.starDust); // NOTE: back of cube
		var cube = new THREE.Mesh(cubeGeometry, sides);
		scene.add(cube);

		var lights = {};
		lights.ambient = new THREE.AmbientLight(0xffffff, .5);
		scene.add(lights.ambient);
		lights.directional = new THREE.DirectionalLight(0xffffff, 1);
		lights.directional.position.set(10, 25, 15);
		scene.add(lights.directional);

		var fieldOfView = 75;
		var aspectRatio = canvas.offsetWidth / canvas.offsetHeight;
		var near = 1;
		var far = 10000;
		var camera = new THREE.PerspectiveCamera(fieldOfView, aspectRatio, near, far);
		camera.position.z = 5;
		scene.add(camera);

		var renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
		renderer.setPixelRatio(window.devicePixelRatio);
		renderer.setSize(canvas.offsetWidth, canvas.offsetHeight);

		function animate() {

			// NOTE: move the cube around
			cube.rotation.x += 0.001;
			cube.rotation.y += 0.002;
			cube.rotation.z += 0.003;

			renderer.render(scene, camera);
			requestAnimationFrame(animate);
		}
		animate();

	</script>
</body>
</html>

Displacement Maps

A texture can have a displacement map. A displacement map is a grayscale image that can be used to alter geometry. The lighter areas have greater displacement. The darker areas less so. Each pixel's value in the displacement map image is used to change the position of the vertices of the mesh.

These are the displacement maps use in the following example:


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>THREE.js - Two Planes with Displacement Map Example</title>
</head>
<body style="background-color:#FFFFFF;">
	<canvas style="display: block; width: 300px; height: 300px;"></canvas>
	<script src="/js/three.min.js"></script>
	<script type="text/javascript">

		// NOTE: these images are in base64 format, a url to an image can be used such as:
		// var stars = "/images/stars.jpg";
		var stars = "data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAeAAD/7gAhQWRvYmUAZMAAAAABAwAQAwIDBgAAAhMAAAM0AAAFv//bAIQAEAsLCwwLEAwMEBcPDQ8XGxQQEBQbHxcXFxcXHx4XGhoaGhceHiMlJyUjHi8vMzMvL0BAQEBAQEBAQEBAQEBAQAERDw8RExEVEhIVFBEUERQaFBYWFBomGhocGhomMCMeHh4eIzArLicnJy4rNTUwMDU1QEA/QEBAQEBAQEBAQEBA/8IAEQgAZABkAwEiAAIRAQMRAf/EAJQAAQEBAQEBAQAAAAAAAAAAAAABAgMEBQYBAQEBAAAAAAAAAAAAAAAAAAABAhAAAgICAgIBBAIDAAAAAAAAAQIAESEDEgQQMRMgUEEUIgUyIyURAAEDAgUCBQQCAwAAAAAAAAEAEQIhMUFRYRIDEHGBkbEiE6HB0TJCFFJiBBIAAwEAAAAAAAAAAAAAAAAAAFAxQf/aAAwDAQACEQMRAAAA/ExC3A1vn2l5XNsMh15w2qXMLEsKFixDWSnql8qrEUXIstM17Tw1BZpYhLnWRYN5pZ6PNU7cevMZADVnoPMQvXnSSCtYLOmFBFhdTJLKE7clA1N5TLqMZFUJoT6vywzBb6RPcNZ//9oACAECAAEFAPqv7SPc/9oACAEDAAEFAPqr7SfU/9oACAEBAAEFAM0bhsRWpS2V07X1lsalV3NwmXNHZ3ddvka+bBSZnwCaPb3/AK6qXZ9To8o0QKnDV8gIBjAgj3AARdE3BBUUkTiKo+AYaMErl4FEgkE6iNfjrt0x18crIlkzINChc9kDLKblGG6UFjbUYilyysjeCpBKsrdX+p7vZ6xQgkEHMQMzw2fFkmyIrcCGIYsWOjvdnTpbUw1GqOTPyTnBlkSrliuLKAICRNe3bpZmLMBcx4GDxZwBPcIm3S+prxBcyScG5Yl5bvbQuZVS8PQArxYZfUdUVJwPL2ORK63+NibGZmexmDjyBy2vYqg1PyKmbqe4bHhdmKuBbA9cWXWP5Pw/2n/EzEbjZgq/6D9T9h+FmCLU6vw/J/zP3f/aAAgBAgIGPwBhlP/aAAgBAwIGPwBhsP/aAAgBAQEGPwAnBfXwVe47KQYEnHJsk1iKKXNGBPHBt0sA69SgJEQif5F2Hki1Rngg1Q1ehnwzPHIhnjditznfd8XRgCdpLkdk/wBOjumxu+K/q7j8O7fsw3WdCMQ8pFgMypccxtlAkSBwa6on8FFpPSos2iZbfk9n+bH0TsJDKv2Tm6Y4UQZaol2bA41QIdxitxrm+fTROOycGuVXTdK11TgdCRSjnoxtpdOMaKPI4aRIABrTMJj5aov9FyjmiTzFvhIoAdVo6/CcpyH0RLCtlQeCceS1Re4N3os02j2QCAFSS20XTP4Yo+iERWUqAO1fFGEg0hQjo+aG0uSAaZ5IxIIkCxGIK5v+ng4zLh4ADySyTIh3wpUKqpIRlcElrVunerus2oVVUTIiUXNYtJ6JwWILjuiT7pSLmRNSSp8HHySjx8n7xBoe6HM0hxzkYiRFDtr90wxq7Ik0PUlr+S1yVOxZaIghycXwQowNjn26HWihMgSEfdGE6xL4spSIA3VZs8kat1cC2ClMCgrIiwdZMMVVh04xzWmBMbSJHbL7ouK0YvZNYIOTogPABMQzXHR2HZPdc3Fwj4eDnYy4okt7bXqitU1yfMIRBJlj+E5rp0AAYj9j0iRPdKT7ot+pelem2j2Z8cley24O7J2BoQ0tcaIua+bpxTJk+PRjggCWD1N2COOShKUTGPJWEsCBSiYh3qmavSlNOlFW5VE3x8ZMQGkf9a4FiTiq3wTuKea7KHISJCTtF3I2nEYLczObCwW3VUs4uq+C9V7ba3X5Xutoub+z8O34eTZ8ztubBsVJrv7Wey1oy16R+b9dF/L492j3X//Z";
		var starDust = "data:image/jpeg;base64,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";
		// NOTE: these displacement maps are just the original image converted to grayscale, the lighter areas will displace more than the darker areas
		var starsDisplacementMap = "data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAeAAD/7gAhQWRvYmUAZMAAAAABAwAQAwIDBgAAAfkAAALvAAAE5f/bAIQAEAsLCwwLEAwMEBcPDQ8XGxQQEBQbHxcXFxcXHx4XGhoaGhceHiMlJyUjHi8vMzMvL0BAQEBAQEBAQEBAQEBAQAERDw8RExEVEhIVFBEUERQaFBYWFBomGhocGhomMCMeHh4eIzArLicnJy4rNTUwMDU1QEA/QEBAQEBAQEBAQEBA/8IAEQgAZABkAwEiAAIRAQMRAf/EAJEAAQEBAQEBAQAAAAAAAAAAAAABAgMEBQYBAQAAAAAAAAAAAAAAAAAAAAAQAAICAgICAQQDAAAAAAAAAAECABEhAxASMQRBUBMUBSIjJREAAQMCBgAEBAQHAAAAAAAAAQARAhAhMUFRYRIDcYEiEyChsTKR0UIUweHxUmIjBBIBAAAAAAAAAAAAAAAAAAAAUP/aAAwDAQACEQMRAAAA/DxC3Iu+fU53NLIHTEK0MxRAVAsDWRXc86hKFgFM16zx1CpoiCywA1mh24Drz3gQCDVnc4SwdMUiCrkN4KAQ1IADrzCUs1CNjOQUFD6XzgzAvYPYD//aAAgBAgABBQD6j//aAAgBAwABBQD6j//aAAgBAQABBQDNG5mKf4k5XVsZC0RQzGE8at+3S3c32aieQcfkbvsBSzNrZHlQgVOmvuCAYQQR5gGPENwQQWJWK4uHMEq+BRIJEKEJxpb1Rpxd1xkH4E+ayQblHgCzZqKpYsrK3FEEqwb1v1nu+z6xU2QQYgLNDfFkyzAesBIJYsdPuexq1NrYaz4OTwTnm8URBLIiPs1MxJIHI89WYCeYRNmp9bXiZmTDgzEvLe5sC5lVLw1AY4wVjKgWdT28izSN0a7HHkZgq4yOFBqfIqfPB4V8VcAsDx1Kp5br/YfHB62YKv8ASfi/fbrZggqev9rv/n/mf//aAAgBAgIGPwBH/9oACAEDAgY/AEf/2gAIAQEBBj8AdfPyoQzk56JlLsjEmEG5SyD0AkREH9Rdh+CtffJBtKc+qZhJmcY3XJzyxfdGL+l3I8Pg+br9vyPtcuXHLlg6EYh5EsFKEg0okiQOTYqydBi9r7Jlx5+j+5j9E7Pst0xypujdv4oHPVOb+NbJwb6Z/BaltKMcNsU4Qm4YkgAG9tRXsHbEntLe0QWAL50/Kjm6NsVYKy3V6MgEALklmGKb5Z0AFycPHzRjIMRYijoMXJvb6JiCJCxGYK7v+np6jLp6AD2yyD0b+dLECWIJLb4p3v8AAyIlFzcMXsnFiLhEm8pFyTip9PX2Sj19n3xBsW1Q7WIhImIkRYt/VW8USbVelvNqG19UNDhvQ72UJMCI+qMZXiX2RLY3ZHKrt5IyAsMdLrwrAduEgJBiCeMkXF8jomWKATENqKOw8Fqu3r6v9XT3sZdcSW9OGN6tmgAXOf5JzQAC4xNIkSeRflFvtOV6cc8Fjgmyd07A2Zii5v8AVWtVtEHLB7nFlqoylEgTvE5EC1kzO6ZqW+FuECQAxP8AjfwL5rdPZeChNxISf0u5DHMZJ2ZzgMAuO6tg4V/Knpw+dPVhsu39x7PH2ezh7ztyazcc9FJsXs2i3yW9I+79uy/V7fLZ8V//2Q==";
		var starDustDisplacementMap = "data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAeAAD/7gAhQWRvYmUAZMAAAAABAwAQAwIDBgAAAkYAAARXAAAJw//bAIQAEAsLCwwLEAwMEBcPDQ8XGxQQEBQbHxcXFxcXHx4XGhoaGhceHiMlJyUjHi8vMzMvL0BAQEBAQEBAQEBAQEBAQAERDw8RExEVEhIVFBEUERQaFBYWFBomGhocGhomMCMeHh4eIzArLicnJy4rNTUwMDU1QEA/QEBAQEBAQEBAQEBA/8IAEQgAZABkAwEiAAIRAQMRAf/EAJMAAAIDAQEAAAAAAAAAAAAAAAQFAAMGAgEBAQAAAAAAAAAAAAAAAAAAAAAQAAMBAAICAgIBBQAAAAAAAAIDBAETBQASERQhFVAiQiMzBhEAAgEEAQIEBAQFBQEAAAAAAQIRACESAzFBE1FhgSJxkTIEobHRQvDhUiMUEGKCotJEEgEAAAAAAAAAAAAAAAAAAABQ/9oADAMBAAIRAxEAAADNe+MwQ05kZ1g16B+yeTMRn6UENgASSCLRKRQ83O6gzjEBebIXLlj45UGM+RSzuMIZa24YKKozxzKujvR5l2H3ilgxC3g1s9hjYFaeLjBSj0jsoe59mH2AElTQTsaRVBOegcDOvgoSWNBTvx1mg0Ug0zjVVUauCwy1o1oTeGWFFrRjVADdjKjzkVgEil05gF3IWESF4shZXINZIVeyCaSH/9oACAECAAEFAP5H/9oACAEDAAEFAP5H/9oACAEBAAEFABIt81Y+Kxe7k2sTJ1ZkQjRypylT7qFyASVVvdMYkHXUIV+uKjf0GfYRvvk3XOMYejfm02dZN5N2HWOEqMmAQW1LpFF4HSQjoIXj9P4S2hwH94ufrkaWpZOoKu5JzVIWWVCaKeu75kHnX9519Lj7VAOhu56K6Yp0I7NVadbPofZl5RXs/l7TI5EFtcidFHZ1KJnthkomLZOh2JkzY+vnL7RdYnGOCcp3+0/slbqlZ1wli1Agq36jrCM2MNmlo7pMmEUSm0uferHCChYubTNVv095QpyKNJt8Tehaq6nOL33xvqAJM8L7ZrCHVBZ2N6uYyx7pWUnZ9n/DOQl5aWF5kzm6wzUWCTNwy+UbvvMAtyLi+52Rt4o0YSetnKY/uJ591maYvIKNP22Y/ZomjFTgai+Vl1tpRG3SY4KanKRGmbLLHmzlq4pmhoTOmdrOv33Z0Fjgs6q9GRddUxf6WVsgxxDiFzZlSeE2uJfgUIBXLnyvfzOEoAi8TGTvThXd3L7R063jXS6OF7i3YeqKgKv+beldczUN5SWXuX65XqPmvI/J2MDznAmZmiarBAKGfckiQX2BYAtDtK597jsH1Ut38elH0s+M8T6/Liz3gXjdByp/OUtdNetGfaQGxunZjqsVlbWu0wYvz7Jce/Hgef2j8+q/b1/q8Z7cYe/HJw8Vn+pX1uGv44/xz//aAAgBAgIGPwBH/9oACAEDAgY/AEf/2gAIAQEBBj8AlTBFpoG5FYlZ86OtQyr0sTPlWKkWuWNqGl17r/tby8a12CgSG/aR+tA6lOZvtxMEj1oujSpJyVjeJnmlQoDsMhUX3QvSs9msPscEDVF1jkmLUM3xZYJMSLjyrudwczN8fnVxJ4BodvrzHT1rufcMuOVvHyrApnhyVBav7AWYuWUL+tFk1ZGfaF5v50rfczr2HoLtHXiiciNQUAZDN44+dHeNrOwOSL+0Am5MUQqMxU5I5BhvKk7mwBjJbp+VZ6YYEkOR48CKnM9yeZMT8OKDACBeKDECRwJAE+NKuvZgqmIXkz4kUQskP1F/lTKpaFMA8fOgrAOIlsrmfjT7NoZCBySCCfAeFF0lyZlci3BNAIsIBHsVob063pn16hmnAYgQJ4/lQWW1PJABIK8cmkB3MuxTDKpsb8xFZ9te79P0dZ+qOOKALYqbW4mu3nNwJFvwFYa0BPmTE1mTOIJLAxiY4FOFYyTBI6eU0JJAMAk3t8KYaiGsbtYR480W3AkbFy1FbnI8e3wtTfeFXcA4kJHtBkSQa/yNwy1al/t6iTyesda3bWWRsb+0nSPEig+9AFmQeZFZ4DOJyv4TxPMVmpLMvEmgxMsRl5+tazBPORUmfwp3TYvvkhDE80S5LZGW8zSiBCiFgAdf3UrHiRPh8qQMgfdsbNQIKhD0ofZqvbLkubEH8aZgFYEfTM5HyHWgmPZgmw+k3pdTZZ5AauimOSfjU4e3szzaYiZoBI7jDmLgVmxxm5kmTNOxPvWwLXF6Hc5F46X4NX/CkIBDOMrxESR7YoAdeJrVqBJJWDBBjK9orXu+9c7C69Tl7VNpqNAxCidY6rPmK14NGxPcXtBtecorssvuUkAMCBczNr+dYQc4xi+PH63rPawwBtPU0cBCkGJs1Lp1nN9phQLDLwvTayIKsQ3USKhQSfDk0SbkyDInmlHAPB8aY9NADSPAwLDrRZ9hwW+P7oHS1Ig1R2xZgOZ5LE+FO7sS0wsQTa/BNH7neTjce8GWJ+mPOKnuHtcdInmcYiaGNxNh50rmyMeeeehrBJyX24jn41iTLck+HxpAjFT4ixvY0+Yi3sYEA5f7p6VgbkGZFd1fcViFImPn4UPuYLLsloUYi5kin1fVraYVv6vPziu6/wByG3IQy6F5PrSbNRyDQTrJ4MdPQV3O0MpnDy+NElvgCajYQsQCOv8AAoOWzkzr2nz86B+zwZifcx/IdKJ+4Ull9sjj50WQgIb38qL7thR0YH2jJb+FFR7wpFgTN/zim0ZlELlvd0vQOnbmpBET19KKMfcbFhWhSQduwXeJKA9K/wAb/wCbHLvQJn/zUTEC09fKsthBaOTMyelqbXlmuJOIsLeANKIyyP0lrRXa1IGcm0Xyvb1rUutGRyxV5ECelukV2eyrJAyI8+JHxooFhmOR8hUvs7WUQ/I85+dAatwebmefworuUgg2BpNnOPieRUd08dyJEYx+dSRJqOR0oNMAcg0NjLmoMEeR5oNoYAbDIgwPUU+vZvnG4xmTXd17ZYQrL8etN/kAOXIVDx1/MU/28FcCSoEGKa7MAQVAmTfjg0H2qFBFlAuBxc+NKuMHw61GJiZnrHh4/wClz6eNFQIUcAUqMQM7CSFHqTRRVzM+12vXc+lgeBQBUnU9tqeU+NHbp2NAJwDfUJ4veafbtaXYAMBwYouGCowLaxEk9L0GAWGHhcTWRubXr678T1j4UYoVf65/6xSzH8ChjGdu3PPpNNl9U3+PpVojH3fy86H9M+sVsmcotMxj5R1o/wBdu3P04xSd7H8fXijhh2sbYxP6/Oukz/xr/9k=";

		var canvas = document.getElementsByTagName("canvas")[0];

		// NOTE: create the texture loader
		var loader = new THREE.TextureLoader();

		var scene = new THREE.Scene();
		scene.background = new THREE.Color(0xFFFFFF); // NOTE: make background white

		var planeSize = 4;

		var materials = {}; // NOTE: use an object to store mesh objects
		materials.stars = new THREE.MeshPhongMaterial({
			map: loader.load(stars),                               // NOTE: load the stars image
			displacementMap: loader.load(starsDisplacementMap),    // NOTE: load the displacementMap
			displacementScale: 1,                                  // NOTE: this changes the amount of the displacement, starts at 0
			side: THREE.DoubleSide                                 // NOTE: make both sides visible
		});
		materials.starDust = new THREE.MeshPhongMaterial({
			map: loader.load(starDust),                            // NOTE: load the star dust image
			displacementMap: loader.load(starDustDisplacementMap), // NOTE: load the displacementMap
			displacementScale: 1,                                  // NOTE: this changes the amount of the displacement, starts at 0
			side: THREE.DoubleSide                                 // NOTE: make both sides visible
		});
		materials.plane = new THREE.MeshPhongMaterial({ color: 0x6699CC });

		var planeBufferGeometry = new THREE.PlaneBufferGeometry(planeSize, planeSize, 100, 100); // NOTE: create a plane buffer, 100 vertices

		var planeBuffer1 = new THREE.Mesh(planeBufferGeometry, materials.stars);
		planeBuffer1.rotation.x = -Math.PI / 2.5;
		scene.add(planeBuffer1);

		var planeBuffer2 = new THREE.Mesh(planeBufferGeometry, materials.starDust);
		planeBuffer2.rotation.x = -Math.PI / 2.5;
		planeBuffer2.position.y = -1;
		scene.add(planeBuffer2);

		var lights = {};
		lights.directional = new THREE.DirectionalLight(0xffffff, 1);
		lights.directional.position.set(10, 25, 15);
		scene.add(lights.directional);

		var fieldOfView = 75;
		var aspectRatio = canvas.offsetWidth / canvas.offsetHeight;
		var near = 1;
		var far = 10000;
		var camera = new THREE.PerspectiveCamera(fieldOfView, aspectRatio, near, far);
		camera.position.z = 5;
		camera.position.y = -1;
		scene.add(camera);

		var renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
		renderer.setPixelRatio(window.devicePixelRatio);
		renderer.setSize(canvas.offsetWidth, canvas.offsetHeight);

		function animate() {

			// NOTE: move the objects around
			planeBuffer1.rotation.z += 0.003;
			planeBuffer2.rotation.z = planeBuffer1.rotation.z;

			renderer.render(scene, camera);
			requestAnimationFrame(animate);
		}
		animate();

	</script>
</body>
</html>

Alpha Maps

A texture can have an alpha map, which is a grayscale texture that controls the opacity across the surface. Black is fully transparent while white is fully opaque.

This is the alpha map used in the following example:


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>THREE.js - Plane with Alpha Map and Displacement Map Example</title>
</head>
<body style="background-color:#FFFFFF;">
	<canvas style="display: block; width: 300px; height: 300px;"></canvas>
	<script src="/js/three.min.js"></script>
	<script type="text/javascript">

		// NOTE: these are images in base64 format, a url to an image can be used such as:
		// var stars = "/images/stars.jpg";
		var stars = "data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAeAAD/7gAhQWRvYmUAZMAAAAABAwAQAwIDBgAAAhMAAAM0AAAFv//bAIQAEAsLCwwLEAwMEBcPDQ8XGxQQEBQbHxcXFxcXHx4XGhoaGhceHiMlJyUjHi8vMzMvL0BAQEBAQEBAQEBAQEBAQAERDw8RExEVEhIVFBEUERQaFBYWFBomGhocGhomMCMeHh4eIzArLicnJy4rNTUwMDU1QEA/QEBAQEBAQEBAQEBA/8IAEQgAZABkAwEiAAIRAQMRAf/EAJQAAQEBAQEBAQAAAAAAAAAAAAABAgMEBQYBAQEBAAAAAAAAAAAAAAAAAAABAhAAAgICAgIBBAIDAAAAAAAAAQIAESEDEgQQMRMgUEEUIgUyIyURAAEDAgUCBQQCAwAAAAAAAAEAEQIhMUFRYRIDEHGBkbEiE6HB0TJCFFJiBBIAAwEAAAAAAAAAAAAAAAAAAFAxQf/aAAwDAQACEQMRAAAA/ExC3A1vn2l5XNsMh15w2qXMLEsKFixDWSnql8qrEUXIstM17Tw1BZpYhLnWRYN5pZ6PNU7cevMZADVnoPMQvXnSSCtYLOmFBFhdTJLKE7clA1N5TLqMZFUJoT6vywzBb6RPcNZ//9oACAECAAEFAPqv7SPc/9oACAEDAAEFAPqr7SfU/9oACAEBAAEFAM0bhsRWpS2V07X1lsalV3NwmXNHZ3ddvka+bBSZnwCaPb3/AK6qXZ9To8o0QKnDV8gIBjAgj3AARdE3BBUUkTiKo+AYaMErl4FEgkE6iNfjrt0x18crIlkzINChc9kDLKblGG6UFjbUYilyysjeCpBKsrdX+p7vZ6xQgkEHMQMzw2fFkmyIrcCGIYsWOjvdnTpbUw1GqOTPyTnBlkSrliuLKAICRNe3bpZmLMBcx4GDxZwBPcIm3S+prxBcyScG5Yl5bvbQuZVS8PQArxYZfUdUVJwPL2ORK63+NibGZmexmDjyBy2vYqg1PyKmbqe4bHhdmKuBbA9cWXWP5Pw/2n/EzEbjZgq/6D9T9h+FmCLU6vw/J/zP3f/aAAgBAgIGPwBhlP/aAAgBAwIGPwBhsP/aAAgBAQEGPwAnBfXwVe47KQYEnHJsk1iKKXNGBPHBt0sA69SgJEQif5F2Hki1Rngg1Q1ehnwzPHIhnjditznfd8XRgCdpLkdk/wBOjumxu+K/q7j8O7fsw3WdCMQ8pFgMypccxtlAkSBwa6on8FFpPSos2iZbfk9n+bH0TsJDKv2Tm6Y4UQZaol2bA41QIdxitxrm+fTROOycGuVXTdK11TgdCRSjnoxtpdOMaKPI4aRIABrTMJj5aov9FyjmiTzFvhIoAdVo6/CcpyH0RLCtlQeCceS1Re4N3os02j2QCAFSS20XTP4Yo+iERWUqAO1fFGEg0hQjo+aG0uSAaZ5IxIIkCxGIK5v+ng4zLh4ADySyTIh3wpUKqpIRlcElrVunerus2oVVUTIiUXNYtJ6JwWILjuiT7pSLmRNSSp8HHySjx8n7xBoe6HM0hxzkYiRFDtr90wxq7Ik0PUlr+S1yVOxZaIghycXwQowNjn26HWihMgSEfdGE6xL4spSIA3VZs8kat1cC2ClMCgrIiwdZMMVVh04xzWmBMbSJHbL7ouK0YvZNYIOTogPABMQzXHR2HZPdc3Fwj4eDnYy4okt7bXqitU1yfMIRBJlj+E5rp0AAYj9j0iRPdKT7ot+pelem2j2Z8cley24O7J2BoQ0tcaIua+bpxTJk+PRjggCWD1N2COOShKUTGPJWEsCBSiYh3qmavSlNOlFW5VE3x8ZMQGkf9a4FiTiq3wTuKea7KHISJCTtF3I2nEYLczObCwW3VUs4uq+C9V7ba3X5Xutoub+z8O34eTZ8ztubBsVJrv7Wey1oy16R+b9dF/L492j3X//Z";
		var starsDisplacementMap = "data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAeAAD/7gAhQWRvYmUAZMAAAAABAwAQAwIDBgAAAfkAAALvAAAE5f/bAIQAEAsLCwwLEAwMEBcPDQ8XGxQQEBQbHxcXFxcXHx4XGhoaGhceHiMlJyUjHi8vMzMvL0BAQEBAQEBAQEBAQEBAQAERDw8RExEVEhIVFBEUERQaFBYWFBomGhocGhomMCMeHh4eIzArLicnJy4rNTUwMDU1QEA/QEBAQEBAQEBAQEBA/8IAEQgAZABkAwEiAAIRAQMRAf/EAJEAAQEBAQEBAQAAAAAAAAAAAAABAgMEBQYBAQAAAAAAAAAAAAAAAAAAAAAQAAICAgICAQQDAAAAAAAAAAECABEhAxASMQRBUBMUBSIjJREAAQMCBgAEBAQHAAAAAAAAAQARAhAhMUFRYRIDcYEiEyChsTKR0UIUweHxUmIjBBIBAAAAAAAAAAAAAAAAAAAAUP/aAAwDAQACEQMRAAAA/DxC3Iu+fU53NLIHTEK0MxRAVAsDWRXc86hKFgFM16zx1CpoiCywA1mh24Drz3gQCDVnc4SwdMUiCrkN4KAQ1IADrzCUs1CNjOQUFD6XzgzAvYPYD//aAAgBAgABBQD6j//aAAgBAwABBQD6j//aAAgBAQABBQDNG5mKf4k5XVsZC0RQzGE8at+3S3c32aieQcfkbvsBSzNrZHlQgVOmvuCAYQQR5gGPENwQQWJWK4uHMEq+BRIJEKEJxpb1Rpxd1xkH4E+ayQblHgCzZqKpYsrK3FEEqwb1v1nu+z6xU2QQYgLNDfFkyzAesBIJYsdPuexq1NrYaz4OTwTnm8URBLIiPs1MxJIHI89WYCeYRNmp9bXiZmTDgzEvLe5sC5lVLw1AY4wVjKgWdT28izSN0a7HHkZgq4yOFBqfIqfPB4V8VcAsDx1Kp5br/YfHB62YKv8ASfi/fbrZggqev9rv/n/mf//aAAgBAgIGPwBH/9oACAEDAgY/AEf/2gAIAQEBBj8AdfPyoQzk56JlLsjEmEG5SyD0AkREH9Rdh+CtffJBtKc+qZhJmcY3XJzyxfdGL+l3I8Pg+br9vyPtcuXHLlg6EYh5EsFKEg0okiQOTYqydBi9r7Jlx5+j+5j9E7Pst0xypujdv4oHPVOb+NbJwb6Z/BaltKMcNsU4Qm4YkgAG9tRXsHbEntLe0QWAL50/Kjm6NsVYKy3V6MgEALklmGKb5Z0AFycPHzRjIMRYijoMXJvb6JiCJCxGYK7v+np6jLp6AD2yyD0b+dLECWIJLb4p3v8AAyIlFzcMXsnFiLhEm8pFyTip9PX2Sj19n3xBsW1Q7WIhImIkRYt/VW8USbVelvNqG19UNDhvQ72UJMCI+qMZXiX2RLY3ZHKrt5IyAsMdLrwrAduEgJBiCeMkXF8jomWKATENqKOw8Fqu3r6v9XT3sZdcSW9OGN6tmgAXOf5JzQAC4xNIkSeRflFvtOV6cc8Fjgmyd07A2Zii5v8AVWtVtEHLB7nFlqoylEgTvE5EC1kzO6ZqW+FuECQAxP8AjfwL5rdPZeChNxISf0u5DHMZJ2ZzgMAuO6tg4V/Knpw+dPVhsu39x7PH2ezh7ztyazcc9FJsXs2i3yW9I+79uy/V7fLZ8V//2Q==";
		var alphaMap = "data:image/jpeg;base64,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";

		var canvas = document.getElementsByTagName("canvas")[0];

		// NOTE: create the texture loader
		var loader = new THREE.TextureLoader();

		var scene = new THREE.Scene();
		scene.background = new THREE.Color(0x6699CC); // NOTE: make the background blue

		var planeSize = 4;

		var materials = {}; // NOTE: use an object to store mesh objects
		materials.stars = new THREE.MeshPhongMaterial({
			map: loader.load(stars),                            // NOTE: load the stars image
			displacementMap: loader.load(starsDisplacementMap), // NOTE: load the displacementMap (not required for alpha maps)
			displacementScale: 1,                               // NOTE: this changes the amount of the displacement, starts at 0 (not required for alpha maps)
			alphaMap: loader.load(alphaMap),                    // NOTE: load the alphaMap
			transparent: true,                                  // NOTE: must specify this
			side: THREE.DoubleSide                              // NOTE: make both sides visible
		});

		var planeBufferGeometry = new THREE.PlaneBufferGeometry(planeSize, planeSize, 100, 100); // NOTE: create a plane buffer, 100 vertices

		var planeBuffer = new THREE.Mesh(planeBufferGeometry, materials.stars);
		planeBuffer.rotation.x = -Math.PI / 2.5;
		scene.add(planeBuffer);

		var lights = {};
		lights.directional = new THREE.DirectionalLight(0xffffff, 1);
		lights.directional.position.set(10, 25, 15);
		scene.add(lights.directional);

		var fieldOfView = 75;
		var aspectRatio = canvas.offsetWidth / canvas.offsetHeight;
		var near = 1;
		var far = 10000;
		var camera = new THREE.PerspectiveCamera(fieldOfView, aspectRatio, near, far);
		camera.position.z = 5;
		scene.add(camera);

		var renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
		renderer.setPixelRatio(window.devicePixelRatio);
		renderer.setSize(canvas.offsetWidth, canvas.offsetHeight);

		function animate() {

			// NOTE: move the object around
			planeBuffer.rotation.z += 0.003;

			renderer.render(scene, camera);
			requestAnimationFrame(animate);
		}
		animate();

	</script>
</body>
</html>

Moving Objects as the User Scrolls

To move an object around as the user scrolls, the parent element of the canvas must have a CSS height value higher than the browser window, such as 400vh which is 4 times the window height, and the canvas must have a position of sticky or fixed with a value set for its CSS top property, usually set to 0.

A basic example for moving an object during the window scroll event is adding a constant to the rotation of the mesh object as in this example:


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>THREE.js - Basic Scroll Example</title>
</head>
<body style="margin: 0; padding: 0;background-color:#FFFFFF; min-height: 400vh;">
	<canvas style="display: block; position: fixed; top: 0; left: calc(50% - 150px); width: 300px; height: 300px;"></canvas>
	<script src="/js/three.min.js"></script>
	<script type="text/javascript">

		var canvas = document.getElementsByTagName("canvas")[0]; // NOTE: get the canvas element - this can be created with document.createElement("canvas") and added with document.body.appendChild(createdCanvasObject);

		var scene = new THREE.Scene();
		scene.background = new THREE.Color(0xFFFFFF); // NOTE: make background white like the HTML page

		function createCube(size, material) {
			var geometry = new THREE.BoxGeometry(size, size, size);
			return new THREE.Mesh(geometry, material);
		}
		var materials = {}; // NOTE: use an object to store mesh objects (object materials)
		materials.lambert = new THREE.MeshLambertMaterial({ color: 0x6699CC });

		var objects = {};
		objects.lambertCube = createCube(3, materials.lambert);
		scene.add(objects.lambertCube);

		var lights = {};
		lights.ambient = new THREE.AmbientLight(0xffffff, .5);
		scene.add(lights.ambient);
		lights.directional = new THREE.DirectionalLight(0xffffff, 1);
		lights.directional.position.set(10, 25, 15);
		scene.add(lights.directional);

		var fieldOfView = 10;
		var aspectRatio = canvas.offsetWidth / canvas.offsetHeight;
		var near = 1;
		var far = 10000;
		var camera = new THREE.PerspectiveCamera(fieldOfView, aspectRatio, near, far);
		camera.position.z = 40;
		scene.add(camera);

		var renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
		renderer.setPixelRatio(window.devicePixelRatio);
		renderer.setSize(canvas.offsetWidth, canvas.offsetHeight);

		// NOTE: animation function which only updates the canvas and does not modify any objects
		function animate() {
			renderer.render(scene, camera);
			requestAnimationFrame(animate);
		}
		animate();

	window.addEventListener("scroll", function () {
		
		// NOTE: rotate the objects in the scene a fixed amount and forward direction only
		for(var object in objects) {
			objects[object].rotation.x += 0.009;
			objects[object].rotation.y += 0.018;
			objects[object].rotation.z += 0.036;
		}

	});

	</script>
</body>
</html>
Using Scroll Position to Set Objects

A better example uses the position of scroll to set the rotation as in this example:


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>THREE.js - Rotate Element on Scroll Example</title>
</head>
<body style="margin: 0; padding: 0;background-color:#FFFFFF; min-height: 400vh;">
	<canvas style="display: block; position: fixed; top: 0; left: calc(50% - 150px); width: 300px; height: 300px;"></canvas>
	<script src="/js/three.min.js"></script>
	<script type="text/javascript">

		var canvas = document.getElementsByTagName("canvas")[0]; // NOTE: get the canvas element - this can be created with document.createElement("canvas") and added with document.body.appendChild(createdCanvasObject);

		var scene = new THREE.Scene();
		scene.background = new THREE.Color(0xFFFFFF); // NOTE: make background white like the HTML page

		function createCube(size, material) {
			var geometry = new THREE.BoxGeometry(size, size, size);
			return new THREE.Mesh(geometry, material);
		}
		var materials = {}; // NOTE: use an object to store mesh objects (object materials)
		materials.lambert = new THREE.MeshLambertMaterial({ color: 0x6699CC });

		var objects = {};
		objects.lambertCube = createCube(3, materials.lambert);
		scene.add(objects.lambertCube);

		var lights = {};
		lights.ambient = new THREE.AmbientLight(0xffffff, .5);
		scene.add(lights.ambient);
		lights.directional = new THREE.DirectionalLight(0xffffff, 1);
		lights.directional.position.set(10, 25, 15);
		scene.add(lights.directional);

		var fieldOfView = 10;
		var aspectRatio = canvas.offsetWidth / canvas.offsetHeight;
		var near = 1;
		var far = 10000;
		var camera = new THREE.PerspectiveCamera(fieldOfView, aspectRatio, near, far);
		camera.position.z = 40;
		scene.add(camera);

		var renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
		renderer.setPixelRatio(window.devicePixelRatio);
		renderer.setSize(canvas.offsetWidth, canvas.offsetHeight);

		// NOTE: animation function which only updates the canvas and does not modify any objects
		function animate() {
			renderer.render(scene, camera);
			requestAnimationFrame(animate);
		}
		animate();

	window.addEventListener("scroll", function () {

		// NOTE: get the position of the scroll value (0 < position < 1)
		var position = window.scrollY / (canvas.parentElement.offsetHeight - window.innerHeight);

		// NOTE: rotate the objects in the scene
		for(var object in objects) {
			objects[object].rotation.x = position * 2;
			objects[object].rotation.y = position * 4;
			objects[object].rotation.z = position * 8;
		}

	});

	</script>
</body>
</html>
Using Scroll Position to Set Camera Position

In this example the camera is moved forward as the user scrolls:


<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<meta name="viewport" content="width=device-width, initial-scale=1.0">
	<title>THREE.js - Zoom on Scroll Example</title>
</head>
<body style="margin: 0; padding: 0;background-color:#FFFFFF; min-height: 400vh;">
	<canvas style="display: block; position: fixed; top: 0; left: calc(50% - 150px); width: 300px; height: 300px;"></canvas>
	<script src="/js/three.min.js"></script>
	<script type="text/javascript">

		var canvas = document.getElementsByTagName("canvas")[0]; // NOTE: get the canvas element - this can be created with document.createElement("canvas") and added with document.body.appendChild(createdCanvasObject);

		var scene = new THREE.Scene();
		scene.background = new THREE.Color(0xFFFFFF); // NOTE: make background white like the HTML page

		function createCube(size, material) {
			var geometry = new THREE.BoxGeometry(size, size, size);
			return new THREE.Mesh(geometry, material);
		}
		var materials = {}; // NOTE: use an object to store mesh objects (object materials)
		materials.lambert = new THREE.MeshLambertMaterial({ color: 0x6699CC });

		var objects = {};
		var cubeSize = 3;
		objects.lambertCube = createCube(cubeSize, materials.lambert);
		scene.add(objects.lambertCube);

		var lights = {};
		lights.ambient = new THREE.AmbientLight(0xffffff, .5);
		scene.add(lights.ambient);
		lights.directional = new THREE.DirectionalLight(0xffffff, 1);
		lights.directional.position.set(10, 25, 15);
		scene.add(lights.directional);

		var fieldOfView = 10;
		var aspectRatio = canvas.offsetWidth / canvas.offsetHeight;
		var near = 1;
		var far = 10000;
		var camera = new THREE.PerspectiveCamera(fieldOfView, aspectRatio, near, far);
		var cameraPositionZ = 50;
		camera.position.z = cameraPositionZ;
		scene.add(camera);

		var renderer = new THREE.WebGLRenderer({ canvas: canvas, antialias: true });
		renderer.setPixelRatio(window.devicePixelRatio);
		renderer.setSize(canvas.offsetWidth, canvas.offsetHeight);

		// NOTE: animation function which only updates the canvas and does not modify any objects
		function animate() {
			renderer.render(scene, camera);
			requestAnimationFrame(animate);
		}
		animate();

	window.addEventListener("scroll", function () {

		// NOTE: get the position of the scroll value (0 < position < 1)
		var position = window.scrollY / (canvas.parentElement.offsetHeight - window.innerHeight);

		// NOTE: rotate the objects in the scene
		for(var object in objects) {
			objects[object].rotation.x = position * (Math.PI / 2);
			objects[object].rotation.y = position * Math.PI;
			objects[object].rotation.z = position * (Math.PI * 1.5);
		}

		// NOTE: this will zoom the camera into the scene
		// cubeSize is added to make the camera not go beyond the cube as it zooms
		camera.position.z = cameraPositionZ - position * cameraPositionZ + cubeSize;
	});

	</script>
</body>
</html>

Other Things to Consider

This site uses cookies. Cookies are simple text files stored on the user's computer. They are used for adding features and security to this site. Read the privacy policy.
CLOSE