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.
HTML
This section has not changed, nothing has been added:
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" /> |
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> |
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; |
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; |
023 | this.scene = new THREE.Scene(); |
024 | var SCREEN_WIDTH = window.innerWidth, |
025 | SCREEN_HEIGHT = window.innerHeight; |
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)); |
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; |
039 | this.container = document.createElement('div'); |
040 | document.body.appendChild(this.container); |
041 | this.container.appendChild(this.renderer.domElement); |
043 | THREEx.WindowResize(this.renderer, this.camera); |
045 | this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement); |
046 | this.controls.target = new THREE.Vector3(0, 0, 0); |
048 | this.clock = new THREE.Clock(); |
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 ); |
056 | dLight = new THREE.DirectionalLight(0xffffff); |
057 | dLight.position.set(0, 400, 0); |
058 | dLight.castShadow = true; |
060 | dLight.shadowMapWidth = dLight.shadowMapHeight = 1000; |
061 | this.scene.add(dLight); |
063 | var groundGeometry = new THREE.PlaneGeometry(1200, 1200, 1, 1); |
064 | ground = new THREE.Mesh(groundGeometry, new THREE.MeshLambertMaterial({ |
067 | ground.position.y = -20; |
068 | ground.rotation.x = - Math.PI / 2; |
069 | ground.receiveShadow = true; |
070 | this.scene.add(ground); |
072 | var group = new THREE.Object3D(); |
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 })); |
079 | this.scene.add(group); |
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; |
093 | requestAnimationFrame(animate); |
100 | dlightHelper.update(); |
101 | lesson3.controls.update(lesson3.clock.getDelta()); |
102 | lesson3.stats.update(); |
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; |
110 | if (lesson3.renderer) { |
111 | lesson3.renderer.render(lesson3.scene, lesson3.camera); |
115 | function initializeLesson() { |
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:
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); |
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:
2 | var axisHelper = new THREE.AxisHelper(800); |
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:
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:
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:
2 | dlightHelper = new THREE.DirectionalLightHelper(dLight, 50); |
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); |
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:
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); |
8 | this.scene.add(hlightHelper); |
PointLightHelper
Similar to the previous, the PointLightHelper is for PointLight object. To add this helper, use the following code:
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); |
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:
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); |
8 | this.scene.add(spotLightHelper); |
[sociallocker]
[/sociallocker]
Conclusion
Stay tuned for new lessons and you are sure to find something new and interesting for yourself.