WebGL With Three.js – Lesson 3
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:
<!DOCTYPE html> <html lang="en" > <head> <meta charset="utf-8" /> <meta name="author" content="Script Tutorials" /> <title>WebGL With Three.js - Lesson 3 | Script Tutorials</title> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no"> <link href="css/main.css" rel="stylesheet" type="text/css" /> </head> <body> <script src="js/three.min.js"></script> <script src="js/THREEx.WindowResize.js"></script> <script src="js/OrbitControls.js"></script> <script src="js/stats.min.js"></script> <script src="js/script.js"></script> </body> </html>
Javascript
For a start, let’s create some simple scene that includes the following elements: camera, direct light, the ground and two spheres.:
var dLight, bboxHelper, dlightHelper; // load texture var texture = THREE.ImageUtils.loadTexture('texture.png'); texture.repeat.set(10, 10); texture.wrapS = texture.wrapT = THREE.RepeatWrapping; texture.anisotropy = 16; texture.needsUpdate = true; var textureBump = THREE.ImageUtils.loadTexture('bump.png'); textureBump.repeat.set(10, 10); textureBump.wrapS = textureBump.wrapT = THREE.RepeatWrapping; textureBump.anisotropy = 16; textureBump.needsUpdate = true; var lesson3 = { scene: null, camera: null, renderer: null, container: null, controls: null, clock: null, stats: null, init: function() { // Initialization // create main scene this.scene = new THREE.Scene(); var SCREEN_WIDTH = window.innerWidth, SCREEN_HEIGHT = window.innerHeight; // prepare camera var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 1, FAR = 10000; this.camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR); this.scene.add(this.camera); this.camera.position.set(-1600, 600, 1200); this.camera.lookAt(new THREE.Vector3(0,0,0)); // prepare renderer this.renderer = new THREE.WebGLRenderer({antialias:true, alpha: false}); this.renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT); this.renderer.setClearColor(0xffffff); this.renderer.shadowMapEnabled = true; this.renderer.shadowMapSoft = true; // prepare container this.container = document.createElement('div'); document.body.appendChild(this.container); this.container.appendChild(this.renderer.domElement); // events THREEx.WindowResize(this.renderer, this.camera); // prepare controls (OrbitControls) this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement); this.controls.target = new THREE.Vector3(0, 0, 0); // prepare clock this.clock = new THREE.Clock(); // prepare stats this.stats = new Stats(); this.stats.domElement.style.position = 'absolute'; this.stats.domElement.style.bottom = '0px'; this.stats.domElement.style.zIndex = 10; this.container.appendChild( this.stats.domElement ); // add directional light dLight = new THREE.DirectionalLight(0xffffff); dLight.position.set(0, 400, 0); dLight.castShadow = true; // dLight.shadowCameraVisible = true; dLight.shadowMapWidth = dLight.shadowMapHeight = 1000; this.scene.add(dLight); // add simple ground var groundGeometry = new THREE.PlaneGeometry(1200, 1200, 1, 1); ground = new THREE.Mesh(groundGeometry, new THREE.MeshLambertMaterial({ color: 0x9669FE })); ground.position.y = -20; ground.rotation.x = - Math.PI / 2; ground.receiveShadow = true; this.scene.add(ground); // create a new group (Object3D) var group = new THREE.Object3D(); // add two spheres var sphere = this.drawSphere(-100, 150, new THREE.MeshPhongMaterial({ map: texture, bumpMap: textureBump, color: 0x00ff00, specular: 0xff2200, emissive: 0x004000 })); var sphere2 = this.drawSphere( 100, 150, new THREE.MeshPhongMaterial({ map: texture, bumpMap: textureBump, color: 0x00ff00, specular: 0xff2200, shininess: 3 })); // and add them into the group group.add(sphere); group.add(sphere2); this.scene.add(group); }, drawSphere: function(x, z, material) { var sphere = new THREE.Mesh(new THREE.SphereGeometry(70, 70, 20), material); sphere.rotation.x = sphere.rotation.z = Math.PI * Math.random(); sphere.position.x = x; sphere.position.y = 100; sphere.position.z = z; sphere.castShadow = sphere.receiveShadow = true; return sphere; } }; // Animate the scene function animate() { requestAnimationFrame(animate); render(); update(); } // Update controls and stats function update() { bboxHelper.update(); dlightHelper.update(); lesson3.controls.update(lesson3.clock.getDelta()); lesson3.stats.update(); // smoothly move the dLight var timer = Date.now() * 0.000025; dLight.position.x = Math.sin(timer * 5) * 300; dLight.position.z = Math.cos(timer * 5) * 300; } // Render the scene function render() { if (lesson3.renderer) { lesson3.renderer.render(lesson3.scene, lesson3.camera); } } // Initialize lesson on page load function initializeLesson() { lesson3.init(); animate(); } if (window.addEventListener) window.addEventListener('load', initializeLesson, false); else if (window.attachEvent) window.attachEvent('onload', initializeLesson); 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. ArrowHelper var directionV3 = new THREE.Vector3(1, 0, 1); var originV3 = new THREE.Vector3(0, 200, 0); var arrowHelper = new THREE.ArrowHelper(directionV3, originV3, 100, 0xff0000, 20, 10); // 100 is length, 20 and 10 are head length and width 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. AxisHelper var axisHelper = new THREE.AxisHelper(800); // 500 is size 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:
// 3. BoundingBoxHelper bboxHelper = new THREE.BoundingBoxHelper(group, 0x999999); 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:
// 4. CameraHelper var cameraParObj = new THREE.Object3D(); cameraParObj.position.y = 200; cameraParObj.position.z = 700; this.scene.add(cameraParObj); perspectiveCamera = new THREE.PerspectiveCamera(90, window.innerWidth / window.innerHeight, 0.01, 1500); cameraParObj.add(perspectiveCamera); var cameraHelper = new THREE.CameraHelper(perspectiveCamera); 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:
// 5. DirectionalLightHelper dlightHelper = new THREE.DirectionalLightHelper(dLight, 50); // 50 is helper size 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:
var gridHelper = new THREE.GridHelper(500, 40); // 500 is grid size, 20 is grid step gridHelper.position = new THREE.Vector3(0, 0, 0); gridHelper.rotation = new THREE.Euler(0, 0, 0); this.scene.add(gridHelper); var gridHelper2 = gridHelper.clone(); gridHelper2.rotation = new THREE.Euler(Math.PI / 2, 0, 0); this.scene.add(gridHelper2); var gridHelper3 = gridHelper.clone(); gridHelper3.rotation = new THREE.Euler(Math.PI / 2, 0, Math.PI / 2); 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:
// add hemisphere light var hemiLight = new THREE.HemisphereLight(0x0000ff, 0x00ff00, 0.4); hemiLight.color.setHSL(0.6, 1, 0.6); hemiLight.groundColor.setHSL(0.095, 1, 0.75); hemiLight.position.set(-200, 400, -200); this.scene.add(hemiLight); var hlightHelper = new THREE.HemisphereLightHelper(hemiLight, 50, 300); // 50 is sphere size, 300 is arrow length this.scene.add(hlightHelper);
PointLightHelper
Similar to the previous, the PointLightHelper is for PointLight object. To add this helper, use the following code:
// add point light var pointLight = new THREE.PointLight(0xffff00, 1.0); pointLight.position.set(300,300,300); this.scene.add(pointLight); var pointLightHelper = new THREE.PointLightHelper(pointLight, 50); // 50 is sphere size 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:
// add spot light var spotLight = new THREE.SpotLight(0xffffff); spotLight.position.set(-300,400,300); spotLight.castShadow = true; spotLight.shadowCameraFov = 60; this.scene.add(spotLight); var spotLightHelper = new THREE.SpotLightHelper(spotLight, 50); // 50 is sphere size 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.