WebGL With Three.js – Lesson 3

Tutorials

Most programmers who are just starting to comprehend the basics of working with 3D (in webgl), usually have difficulties in understanding three-dimensional space. Because we have one extra dimension (volume) compared with what you are used to. Also you may have difficulty in understanding how the different light works, or even how axis are located in space. Today I will help you to deal with these issues. Three.js has all the necessary means to for this – Helpers. In today’s examples, I have prepared you for working demonstration of all existing helpers: ArrowHelper, AxisHelper, BoundingBoxHelper, CameraHelper, DirectionalLightHelper, GridHelper, HemisphereLightHelper, PointLightHelper, SpotLightHelper. All of them will help you understand the insides of WebGL.

Live Demo
Live Demo 2

HTML

This section has not changed, nothing has been added:

01 <!DOCTYPE html>
02 <html lang="en" >
03     <head>
04         <meta charset="utf-8" />
05         <meta name="author" content="Script Tutorials" />
06         <title>WebGL With Three.js - Lesson 3 | Script Tutorials</title>
07         <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
08         <link href="css/main.css" rel="stylesheet" type="text/css" />
09     </head>
10     <body>
11         <script src="js/three.min.js"></script>
12         <script src="js/THREEx.WindowResize.js"></script>
13         <script src="js/OrbitControls.js"></script>
14         <script src="js/stats.min.js"></script>
15         <script src="js/script.js"></script>
16     </body>
17 </html>

Javascript

For a start, let’s create some simple scene that includes the following elements: camera, direct light, the ground and two spheres.:

001 var dLight, bboxHelper, dlightHelper;
002 // load texture
003 var texture = THREE.ImageUtils.loadTexture('texture.png');
004 texture.repeat.set(10, 10);
005 texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
006 texture.anisotropy = 16;
007 texture.needsUpdate = true;
008 var textureBump = THREE.ImageUtils.loadTexture('bump.png');
009 textureBump.repeat.set(10, 10);
010 textureBump.wrapS = textureBump.wrapT = THREE.RepeatWrapping;
011 textureBump.anisotropy = 16;
012 textureBump.needsUpdate = true;
013 var lesson3 = {
014     scene: null,
015     camera: null,
016     renderer: null,
017     container: null,
018     controls: null,
019     clock: null,
020     stats: null,
021     init: function() { // Initialization
022         // create main scene
023         this.scene = new THREE.Scene();
024         var SCREEN_WIDTH = window.innerWidth,
025             SCREEN_HEIGHT = window.innerHeight;
026         // prepare camera
027         var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 1, FAR = 10000;
028         this.camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
029         this.scene.add(this.camera);
030         this.camera.position.set(-1600, 600, 1200);
031         this.camera.lookAt(new THREE.Vector3(0,0,0));
032         // prepare renderer
033         this.renderer = new THREE.WebGLRenderer({antialias:true, alpha: false});
034         this.renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
035         this.renderer.setClearColor(0xffffff);
036         this.renderer.shadowMapEnabled = true;
037         this.renderer.shadowMapSoft = true;
038         // prepare container
039         this.container = document.createElement('div');
040         document.body.appendChild(this.container);
041         this.container.appendChild(this.renderer.domElement);
042         // events
043         THREEx.WindowResize(this.renderer, this.camera);
044         // prepare controls (OrbitControls)
045         this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
046         this.controls.target = new THREE.Vector3(0, 0, 0);
047         // prepare clock
048         this.clock = new THREE.Clock();
049         // prepare stats
050         this.stats = new Stats();
051         this.stats.domElement.style.position = 'absolute';
052         this.stats.domElement.style.bottom = '0px';
053         this.stats.domElement.style.zIndex = 10;
054         this.container.appendChild( this.stats.domElement );
055         // add directional light
056         dLight = new THREE.DirectionalLight(0xffffff);
057         dLight.position.set(0, 400, 0);
058         dLight.castShadow = true;
059         // dLight.shadowCameraVisible = true;
060         dLight.shadowMapWidth = dLight.shadowMapHeight = 1000;
061         this.scene.add(dLight);
062         // add simple ground
063         var groundGeometry = new THREE.PlaneGeometry(1200, 1200, 1, 1);
064         ground = new THREE.Mesh(groundGeometry, new THREE.MeshLambertMaterial({
065             color: 0x9669FE
066         }));
067         ground.position.y = -20;
068         ground.rotation.x = - Math.PI / 2;
069         ground.receiveShadow = true;
070         this.scene.add(ground);
071         // create a new group (Object3D)
072         var group = new THREE.Object3D();
073         // add two spheres
074         var sphere  = this.drawSphere(-100, 150, new THREE.MeshPhongMaterial({ map: texture, bumpMap: textureBump, color: 0x00ff00, specular: 0xff2200, emissive: 0x004000 }));
075         var sphere2 = this.drawSphere( 100, 150, new THREE.MeshPhongMaterial({ map: texture, bumpMap: textureBump, color: 0x00ff00, specular: 0xff2200, shininess: 3 }));
076         // and add them into the group
077         group.add(sphere);
078         group.add(sphere2);
079         this.scene.add(group);
080     },
081     drawSphere: function(x, z, material) {
082         var sphere = new THREE.Mesh(new THREE.SphereGeometry(70, 70, 20), material);
083         sphere.rotation.x = sphere.rotation.z = Math.PI * Math.random();
084         sphere.position.x = x;
085         sphere.position.y = 100;
086         sphere.position.z = z;
087         sphere.castShadow = sphere.receiveShadow = true;
088         return sphere;
089     }
090 };
091 // Animate the scene
092 function animate() {
093     requestAnimationFrame(animate);
094     render();
095     update();
096 }
097 // Update controls and stats
098 function update() {
099     bboxHelper.update();
100     dlightHelper.update();
101     lesson3.controls.update(lesson3.clock.getDelta());
102     lesson3.stats.update();
103     // smoothly move the dLight
104     var timer = Date.now() * 0.000025;
105     dLight.position.x = Math.sin(timer * 5) * 300;
106     dLight.position.z = Math.cos(timer * 5) * 300;
107 }
108 // Render the scene
109 function render() {
110     if (lesson3.renderer) {
111         lesson3.renderer.render(lesson3.scene, lesson3.camera);
112     }
113 }
114 // Initialize lesson on page load
115 function initializeLesson() {
116     lesson3.init();
117     animate();
118 }
119 if (window.addEventListener)
120     window.addEventListener('load', initializeLesson, false);
121 else if (window.attachEvent)
122     window.attachEvent('onload', initializeLesson);
123 else window.onload = initializeLesson;

Please pay attention that two spheres were added into the group (which is ordinary Object3D object). Now, we can start the overview of the helpers.

ArrowHelper

It draws a 3D arrow (starting in origin in the direction dir for a certain length) in space. This helps to understand the direction of a vector in space. To add this helper, use the following code:

1 // 1. ArrowHelper
2 var directionV3 = new THREE.Vector3(1, 0, 1);
3 var originV3 = new THREE.Vector3(0, 200, 0);
4 var arrowHelper = new THREE.ArrowHelper(directionV3, originV3, 100, 0xff0000, 20, 10); // 100 is length, 20 and 10 are head length and width
5 this.scene.add(arrowHelper);

AxisHelper

It draws an axis object to visualize the the 3 axis in a simple way. The X axis is red. The Y axis is green. The Z axis is blue. This helps to understand the direction of all three axis in space. To add this helper, use the following code:

1 // 2. AxisHelper
2 var axisHelper = new THREE.AxisHelper(800); // 500 is size
3 this.scene.add(axisHelper);

BoundingBoxHelper

It draws a line object to the boundingbox of any object (Object3D) to show the world-axis-aligned bounding box for this object. Remember what we combined the two spheres in the single group object? To add this helper, use the following code:

1 // 3. BoundingBoxHelper
2 bboxHelper = new THREE.BoundingBoxHelper(group, 0x999999);
3 this.scene.add(bboxHelper);

CameraHelper

It draws a specific Object3D object (it looks like pyramid) with line geometry, that helps visualizing what a specified camera contains in its frustum. To add this helper, use the following code:

1 // 4. CameraHelper
2 var cameraParObj = new THREE.Object3D();
3 cameraParObj.position.y = 200;
4 cameraParObj.position.z = 700;
5 this.scene.add(cameraParObj);
6 perspectiveCamera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 0.01, 1500);
7 cameraParObj.add(perspectiveCamera);
8 var cameraHelper = new THREE.CameraHelper(perspectiveCamera);
9 this.scene.add(cameraHelper);

DirectionalLightHelper

It draws a line object to show the direction of a directional light. We will gradually move our source of light for you to see clearly this helper. To add this helper, use the following code:

1 // 5. DirectionalLightHelper
2 dlightHelper = new THREE.DirectionalLightHelper(dLight, 50); // 50 is helper size
3 this.scene.add(dlightHelper);

GridHelper

To see the rest of the helpers, we created the second demo. The next is GridHelper, this helper draws a two-dimensional grid of lines. To add this helper, use the following code:

01 var gridHelper = new THREE.GridHelper(500, 40); // 500 is grid size, 20 is grid step
02 gridHelper.position = new THREE.Vector3(0, 0, 0);
03 gridHelper.rotation = new THREE.Euler(0, 0, 0);
04 this.scene.add(gridHelper);
05 var gridHelper2 = gridHelper.clone();
06 gridHelper2.rotation = new THREE.Euler(Math.PI / 2, 0, 0);
07 this.scene.add(gridHelper2);
08 var gridHelper3 = gridHelper.clone();
09 gridHelper3.rotation = new THREE.Euler(Math.PI / 2, 0, Math.PI / 2);
10 this.scene.add(gridHelper3);

Please note, that we created three two-dimensional grid (for all three axis).

HemisphereLightHelper

The rest three helpers are for lights, the HemisphereLightHelper is for HemisphereLight object. We had to turn off our directional light and enable the hemisphere light. To add this helper, use the following code:

1 // add hemisphere light
2 var hemiLight = new THREE.HemisphereLight(0x0000ff, 0x00ff00, 0.4);
3 hemiLight.color.setHSL(0.6, 1, 0.6);
4 hemiLight.groundColor.setHSL(0.095, 1, 0.75);
5 hemiLight.position.set(-200, 400, -200);
6 this.scene.add(hemiLight);
7 var hlightHelper = new THREE.HemisphereLightHelper(hemiLight, 50, 300); // 50 is sphere size, 300 is arrow length
8 this.scene.add(hlightHelper);

PointLightHelper

Similar to the previous, the PointLightHelper is for PointLight object. To add this helper, use the following code:

1 // add point light
2 var pointLight = new THREE.PointLight(0xffff00, 1.0);
3 pointLight.position.set(300,300,300);
4 this.scene.add(pointLight);
5 var pointLightHelper = new THREE.PointLightHelper(pointLight, 50); // 50 is sphere size
6 this.scene.add(pointLightHelper);

SpotLightHelper

Lastly, we added the spot light: the SpotLightHelper is for SpotLight object. To add this helper, use the following code:

1 // add spot light
2 var spotLight = new THREE.SpotLight(0xffffff);
3 spotLight.position.set(-300,400,300);
4 spotLight.castShadow = true;
5 spotLight.shadowCameraFov = 60;
6 this.scene.add(spotLight);
7 var spotLightHelper = new THREE.SpotLightHelper(spotLight, 50); // 50 is sphere size
8 this.scene.add(spotLightHelper);

Live Demo
Live Demo 2

[sociallocker]

download in package

[/sociallocker]


Conclusion

Stay tuned for new lessons and you are sure to find something new and interesting for yourself.

Rate article