WebGL With Three.js – Lesson 4

Tutorials

Today we continue our lessons for those who study webgl, and today we will show you how to add 3D text on the scene, how to extrude two-dimensional shapes, we also will consider how to load ready 3D models into the scene using the OBJLoader. It seems to be a difficult process, but it is not – the code for loading 3D models is fairly simple.

Live Demo

HTML

Two new libraries were added into the html: font1.js and OBJLoader.js

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 4 | 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/fonts/font1.js"></script>
15         <script src="js/OBJLoader.js"></script>
16         <script src="js/stats.min.js"></script>
17         <script src="js/script.js"></script>
18     </body>
19 </html>

Javascript

First, we create a simple (empty) scene (scene, camera, renderer, controls, light and ground):

01 // load texture
02 var texture = THREE.ImageUtils.loadTexture('texture.png');
03 texture.repeat.set(0.03, 0.03);
04 texture.wrapS = texture.wrapT = THREE.RepeatWrapping;
05 texture.anisotropy = 16;
06 texture.needsUpdate = true;
07 var lesson4 = {
08     scene: null,
09     camera: null,
10     renderer: null,
11     container: null,
12     controls: null,
13     clock: null,
14     stats: null,
15     init: function() { // Initialization
16         // create main scene
17         this.scene = new THREE.Scene();
18         var SCREEN_WIDTH = window.innerWidth,
19             SCREEN_HEIGHT = window.innerHeight;
20         // prepare camera
21         var VIEW_ANGLE = 45, ASPECT = SCREEN_WIDTH / SCREEN_HEIGHT, NEAR = 1, FAR = 10000;
22         this.camera = new THREE.PerspectiveCamera( VIEW_ANGLE, ASPECT, NEAR, FAR);
23         this.scene.add(this.camera);
24         this.camera.position.set(0, 400, 800);
25         this.camera.lookAt(new THREE.Vector3(0,0,0));
26         // prepare renderer
27         this.renderer = new THREE.WebGLRenderer({antialias:true, alpha: false});
28         this.renderer.setSize(SCREEN_WIDTH, SCREEN_HEIGHT);
29         this.renderer.setClearColor(0xffffff);
30         this.renderer.shadowMapEnabled = true;
31         this.renderer.shadowMapSoft = true;
32         // prepare container
33         this.container = document.createElement('div');
34         document.body.appendChild(this.container);
35         this.container.appendChild(this.renderer.domElement);
36         // events
37         THREEx.WindowResize(this.renderer, this.camera);
38         // prepare controls (OrbitControls)
39         this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
40         this.controls.target = new THREE.Vector3(0, 0, 0);
41         // prepare clock
42         this.clock = new THREE.Clock();
43         // prepare stats
44         this.stats = new Stats();
45         this.stats.domElement.style.position = 'absolute';
46         this.stats.domElement.style.bottom = '0px';
47         this.stats.domElement.style.zIndex = 10;
48         this.container.appendChild( this.stats.domElement );
49         // add directional light
50         var dLight = new THREE.DirectionalLight(0xffffff);
51         dLight.position.set(0, 1000, 0);
52         dLight.castShadow = true;
53         // dLight.shadowCameraVisible = true;
54         this.scene.add(dLight);
55         // add simple ground
56         var groundGeometry = new THREE.PlaneGeometry(1000, 1000, 1, 1);
57         ground = new THREE.Mesh(groundGeometry, new THREE.MeshLambertMaterial({
58             color: 0x4489FE, side: THREE.DoubleSide
59         }));
60         ground.position.y = -20;
61         ground.rotation.x = - Math.PI / 2;
62         ground.receiveShadow = true;
63         this.scene.add(ground);
64     },
65 };
66 // Animate the scene
67 function animate() {
68     requestAnimationFrame(animate);
69     render();
70     update();
71 }
72 // Update controls and stats
73 function update() {
74     lesson4.controls.update(lesson4.clock.getDelta());
75     lesson4.stats.update();
76 }
77 // Render the scene
78 function render() {
79     if (lesson4.renderer) {
80         lesson4.renderer.render(lesson4.scene, lesson4.camera);
81     }
82 }
83 // Initialize lesson on page load
84 function initializeLesson() {
85     lesson4.init();
86     animate();
87 }
88 if (window.addEventListener)
89     window.addEventListener('load', initializeLesson, false);
90 else if (window.attachEvent)
91     window.attachEvent('onload', initializeLesson);
92 else window.onload = initializeLesson;

3D text

The best way to display text in 3D enviromnemt is to use a ready 3D font (for Three.js). In general, there are many websites where you can download fonts, however we need special javascript fonts (typefaced fonts). This website may help you to convert custom fonts into javascript fonts (upload your font, hit the ‘convert’, and then follow the steps until it let you download the result). However, at the time of writing this tutorial, this service was not available, so I had to use ready-made fonts to create our demonstration. To draw a three-dimensional text I prepared the following function:

01 draw3dText: function(x, y, z, text) {
02     // prepare text geometry
03     var textGeometry = new THREE.TextGeometry(text, {
04         size: 60, // Font size
05         height: 20, // Font height (depth)
06         font: 'droid serif'// Font family
07         weight: 'bold'// Font weight
08         style: 'normal'// Font style
09         curveSegments: 1, // Amount of curve segments
10         bevelThickness: 5, // Bevel thickness
11         bevelSize: 5, // Bevel size
12         bevelEnabled: true// Enable/Disable the bevel
13         material: 0, // Main material
14         extrudeMaterial: 1 // Side (extrude) material
15     });
16     // prepare two materials
17     var materialFront = new THREE.MeshPhongMaterial({ map: texture, color: 0xffff00, emissive: 0x888888 });
18     var materialSide = new THREE.MeshPhongMaterial({ map: texture, color: 0xff00ff, emissive: 0x444444 });
19     // create mesh object
20     var textMaterial = new THREE.MeshFaceMaterial([ materialFront, materialSide ]);
21     var textMesh = new THREE.Mesh(textGeometry, textMaterial);
22     textMesh.castShadow = true;
23     // place the mesh in the certain position, rotate it and add to the scene
24     textMesh.position.set(x, y, z);
25     textMesh.rotation.x = -0.3;
26     this.scene.add(textMesh);
27 }

Two different materials are used to different sides of the text (for the front and side).

ExtrudeGeometry

This class allows us to create three-dimensional extruded geometry from two-dimensional path shape. I drew the boat for our today’s demonstration:

01 drawCustomObject: function(x, y, z) {
02     // prepare points for custom shape (ship)
03     var objectPoints = [
04         new THREE.Vector2 (275, 265),
05         new THREE.Vector2 (205, 240),
06         new THREE.Vector2 (125, 220),
07         new THREE.Vector2 (274, 115),
08         new THREE.Vector2 (275, 85),
09         new THREE.Vector2 (330, 85),
10         new THREE.Vector2 (310, 100),
11         new THREE.Vector2 (330, 115),
12         new THREE.Vector2 (275, 115),
13         new THREE.Vector2 (274, 266),
14         new THREE.Vector2 (305, 266),
15         new THREE.Vector2 (305, 240),
16         new THREE.Vector2 (360, 240),
17         new THREE.Vector2 (360, 285),
18         new THREE.Vector2 (340, 335),
19         new THREE.Vector2 (215, 335),
20         new THREE.Vector2 (175, 320),
21         new THREE.Vector2 (150, 290),
22         new THREE.Vector2 (75, 230),
23         new THREE.Vector2 (200, 264),
24         new THREE.Vector2 (274, 264),
25     ];
26     // prepare shape
27     var objectShape = new THREE.Shape(objectPoints);
28     var extrusionSettings = {
29         amount: 20,
30         curveSegments: 1, // Amount of curve segments
31         bevelThickness: 5, // Bevel thickness
32         bevelSize: 5, // Bevel size
33         bevelEnabled: true// Enable/Disable the bevel
34         material: 0, // Main material
35         extrudeMaterial: 1 // Side (extrude) material
36     };
37     // prepare ship geometry
38     var objectGeometry = new THREE.ExtrudeGeometry( objectShape, extrusionSettings );
39     // prepare two materials
40     var materialFront = new THREE.MeshPhongMaterial({ map: texture, color: 0xffff00, emissive: 0x888888 });
41     var materialSide = new THREE.MeshPhongMaterial({ map: texture, color: 0xff00ff, emissive: 0x444444 });
42     // create mesh object of the ship
43     var objectMaterial = new THREE.MeshFaceMaterial([ materialFront, materialSide ]);
44     var objectMesh = new THREE.Mesh( objectGeometry, objectMaterial );
45     objectMesh.castShadow = true;
46     // place the object in the certain position, rotate it and add to the scene
47     objectMesh.position.set(x, y, z);
48     objectMesh.rotation.x = Math.PI;
49     this.scene.add(objectMesh);
50 }

OBJLoader

I left the most interesting for the end – loading ready OBJ models. The fact that there are a huge number of ready three-dimensional objects (at various websites) that you can add into your scene, and three.js gives us this opportunity through the use of the OBJLoader class:

01 loadObjFile: function(x, y, z) {
02     // prepare new OBJLoader and load the 'legoBrick.obj' model
03     var loader = new THREE.OBJLoader();
04     loader.load('legoBrick.obj'function(object) {
05         // apply custom material for all children
06         var legoMat = new THREE.MeshLambertMaterial({ color: 0x008800 });
07         object.traverse( function (child) {
08             if (child instanceof THREE.Mesh) {
09                 child.material = legoMat;
10                 child.material.needsUpdate = true;
11             }
12         });
13         // place the object in the certain position, rotate, scale and add to the scene
14         object.position.x = x;
15         object.position.y = y;
16         object.position.z = z;
17         object.rotation.y = Math.PI/2;
18         object.scale.set(40, 40, 40);
19         lesson4.scene.add(object);
20     });
21 }

To import the model we just specify the address to this model, as well as the callback function. In this function we applied the custom material for it’s children.


Live Demo

[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