Advertisement
 
Tutorial
  1 <!DOCTYPE html> 
  2 <!-- The previous line tells the browser, that the page uses the HTML5 standard. --> 
  3  
  4 <html>
  5     <head>
  6         <title>Three.js tutorial - Lesson 08</title> 
  7         <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1"> 
  8  
  9         <!-- The following meta line optimizes the site for mobile devices. It sets the viewport size 
 10         to the screen size, so it will be displayed maximized, but unscaled. --> 
 11         <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1"> 
 12         <style type="text/css"> 
 13             body { 
 14                 /* Set the background color of the HTML page to black */ 
 15                 background-color: #000000; 
 16  
 17                 /* Hide oversized content. This prevents the scroll bars. */ 
 18                 overflow: hidden; 
 19  
 20                 /* Define the font and the color for the usage, which is an ordinary HTML overlay. */ 
 21                 font-family: Monospace; 
 22                 color: white; 
 23             } 
 24         </style> 
 25         <!-- Include Three.js libraries --> 
 26         <script src="../js/r69/three.js"></script> 
 27         <script src="../js/r69/Detector.js"></script> 
 28         <script src="../js/r69/CanvasRenderer.js"></script> 
 29         <script src="../js/r69/Projector.js"></script> 
 30     </head> 
 31     <body>
 32         <!-- Create a DIV element, which will be shown over the WebGL canvas. The last line 
 33         ("Renderer: ") will be completed either by "WebGL Renderer" or by "Canvas Renderer". --> 
 34         <div id="overlaytext" style="position: absolute; top: 10px; left: 10px"> 
 35             'F': Loop through the three texture filters (only for WebGL renderer)<br/> 
 36             'L': Toggle light (only for WebGL renderer)<br/> 
 37             'B': Toggle blending<br/> 
 38             Cursor left / right: Control y rotation speed<br/> 
 39             Cursor up / down: Control x rotation speed<br/> 
 40             Page up / down: Move along z axis<br/> 
 41             Renderer:  
 42         </div> 
 43  
 44         <!-- This is the DIV element which will contain the WebGL canvas. To be identifiable lateron, 
 45         the id 'WebGLCanvas' is applied to it. --> 
 46         <div id="WebGLCanvas"> 
 47  
 48         <!-- This JavaScript block encloses the Three.js commands --> 
 49         <script> 
 50             // Global scene object 
 51             var scene; 
 52  
 53             // Global camera object 
 54             var camera; 
 55  
 56             // x and y rotation 
 57             var xRotation = 0.0; 
 58             var yRotation = 0.0; 
 59  
 60             // Rotation speed around x and y axis 
 61             var xSpeed = 0.0; 
 62             var ySpeed = 0.0; 
 63  
 64             // Translation along the z axis 
 65             var zTranslation = 0.0; 
 66  
 67             // The x and y speed is controlled by the cursor keys. 
 68             // The translation on the z axis by 'Page up / down'. 
 69             // 'glassTexture' is the texture object. We set it global, to modify it's attributes 
 70             // lateron. 
 71             // 'textureFilter' will have three states (0, 1 or 2), controlling the current texture 
 72             // filtering (nearest, linear or mipmapped). 
 73             // The next two objects hold two different kinds of light: Ambient and directional light. 
 74             // 'enableLights' is the flag, which is switched by the key 'f'. 
 75  
 76             // Texture and flag for current texture filter 
 77             var glassTexture; 
 78             var textureFilter = 0; 
 79  
 80             // Flag for toggling light 
 81             var lightIsOn = true; 
 82  
 83             // Flag for toggling blending 
 84             var blendingIsOn = true; 
 85  
 86             // Global mesh object of the cube 
 87             var boxMesh; 
 88  
 89             // Initialize the scene 
 90             initializeScene(); 
 91  
 92             // Animate the scene 
 93             animateScene(); 
 94  
 95             /** 
 96              * Initialze the scene. 
 97              */ 
 98             function initializeScene(){ 
 99                 // Check whether the browser supports WebGL. If so, instantiate the hardware accelerated 
100                 // WebGL renderer. For antialiasing, we have to enable it. The canvas renderer uses 
101                 // antialiasing by default. 
102                 // The approach of multiplse renderers is quite nice, because your scene can also be 
103                 // viewed in browsers, which don't support WebGL. The limitations of the canvas renderer 
104                 // in contrast to the WebGL renderer will be explained in the tutorials, when there is a 
105                 // difference. 
106                 webGLAvailable = false; 
107                 if(Detector.webgl){ 
108                     renderer = new THREE.WebGLRenderer({antialias:true}); 
109                     webGLAvailable = true; 
110                     document.getElementById("overlaytext").innerHTML += "WebGL Renderer"; 
111  
112                 // If its not supported, instantiate the canvas renderer to support all non WebGL 
113                 // browsers 
114                 } else { 
115                     renderer = new THREE.CanvasRenderer(); 
116                     document.getElementById("overlaytext").innerHTML += "Canvas Renderer"; 
117                 } 
118  
119                 // Set the background color of the renderer to black, with full opacity 
120                 renderer.setClearColor(0x000000, 1); 
121  
122                 // Get the size of the inner window (content area) 
123                 // Reduce the canvas size a little bit to prevent scrolling the whole window 
124                 // content in Firefox while rotating the cube with the keys. 
125                 canvasWidth = window.innerWidth - 10;
126                 canvasHeight = window.innerHeight - 20;
127  
128                 // Set the renderers size to the content areas size 
129                 renderer.setSize(canvasWidth, canvasHeight); 
130  
131                 // Get the DIV element from the HTML document by its ID and append the renderers DOM 
132                 // object to it 
133                 document.getElementById("WebGLCanvas").appendChild(renderer.domElement); 
134  
135                 // Create the scene, in which all objects are stored (e. g. camera, lights, 
136                 // geometries, ...) 
137                 scene = new THREE.Scene(); 
138  
139                 // Now that we have a scene, we want to look into it. Therefore we need a camera. 
140                 // Three.js offers three camera types: 
141                 //  - PerspectiveCamera (perspective projection) 
142                 //  - OrthographicCamera (parallel projection) 
143                 //  - CombinedCamera (allows to switch between perspective / parallel projection 
144                 //    during runtime) 
145                 // In this example we create a perspective camera. Parameters for the perspective 
146                 // camera are ... 
147                 // ... field of view (FOV), 
148                 // ... aspect ratio (usually set to the quotient of canvas width to canvas height) 
149                 // ... near and 
150                 // ... far. 
151                 // Near and far define the cliping planes of the view frustum. Three.js provides an 
152                 // example (http://mrdoob.github.com/three.js/examples/ 
153                 // -> canvas_camera_orthographic2.html), which allows to play around with these 
154                 // parameters. 
155                 // The camera is moved 10 units towards the z axis to allow looking to the center of 
156                 // the scene. 
157                 // After definition, the camera has to be added to the scene. 
158                 camera = new THREE.PerspectiveCamera(45, canvasWidth / canvasHeight, 1, 100); 
159                 camera.position.set(0, 0, 6); 
160                 camera.lookAt(scene.position); 
161                 scene.add(camera); 
162  
163                 // Create the cube 
164                 var boxGeometry = new THREE.BoxGeometry(2.0, 2.0, 2.0); 
165  
166                 // When the CanvasRenderer is used, you will see, that the texture has some distortions. 
167                 // To get rid of this, you only have to increase the number of cube segments. The 
168                 // WebGLRenderer doesn't needs this workaround. 
169                 //var boxGeometry = new THREE.BoxGeometry(2.0, 2.0, 2.0, 4, 4, 4); 
170  
171                 // Load an image as texture 
172                 glassTexture = new THREE.ImageUtils.loadTexture("Glass.jpg"); 
173  
174                 // Create a material, which contains the texture 
175                 // Unfortunately, the CanvasRenderer doesn't support MeshLambertMaterial in combination 
176                 // with Textures. Otherwise, the MeshBasicMaterial doesn't support lighting. As 
177                 // compromise, the CanvasRenderer will show the texture without lighting via 
178                 // MeshBasicMaterial. 
179                 var boxMaterial = new THREE.MeshLambertMaterial({ 
180                     map:glassTexture, 
181                     depthWrite: false, 
182                     transparent: true, 
183                     opacity: 0.5, 
184                     side:THREE.DoubleSide, 
185                     combine: THREE.MixOperation 
186                 }); 
187                 if(!webGLAvailable){ 
188                     boxMaterial = new THREE.MeshBasicMaterial({ 
189                         map:glassTexture, 
190                         transparent: true, 
191                         opacity: 0.5, 
192                         side:THREE.DoubleSide 
193                     }); 
194                 } 
195  
196                 // Create a mesh and insert the geometry and the material. Translate the 
197                 // whole mesh by 'zTranslation' units on the z axis. Finally add the mesh 
198                 // to the scene. 
199                 boxMesh = new THREE.Mesh(boxGeometry, boxMaterial); 
200                 boxMesh.position.set(0.0, 0.0, zTranslation); 
201                 scene.add(boxMesh); 
202  
203                 // Ambient light has no direction, it illuminates every object with the same 
204                 // intensity. If only ambient light is used, no shading effects will occur. 
205                 var ambientLight = new THREE.AmbientLight(0x101010, 1.0); 
206                 scene.add(ambientLight); 
207  
208                 // Directional light has a source and shines in all directions, like the sun. 
209                 // This behaviour creates shading effects. 
210                 var directionalLight = new THREE.DirectionalLight(0xffffff, 1.0); 
211                 directionalLight.position.set(camera.position.x, camera.position.y, camera.position.z); 
212                 scene.add(directionalLight); 
213  
214                 // Add a listener for 'keydown' events. By this listener, all key events will be 
215                 // passed to the function 'onDocumentKeyDown'. There's another event type 'keypress'. 
216                 // It will report only the visible characters like 'a', but not the function keys 
217                 // like 'cursor up'. 
218                 document.addEventListener("keydown", onDocumentKeyDown, false); 
219             } 
220  
221             /** 
222              * This function is called, when a key is oushed down.
223              */ 
224             function onDocumentKeyDown(event){ 
225                 // Get the key code of the pressed key 
226                 var keyCode = event.which; 
227  
228                 // 'F' - Toggle through the texture filters 
229                 if(keyCode == 70){ 
230                     // The CanvasRenderer doesn't support texture filters. 
231                     switch(textureFilter){ 
232                         case 0: 
233                             glassTexture.minFilter = THREE.NearestFilter; 
234                             glassTexture.magFilter = THREE.NearestFilter; 
235                             textureFilter = 1; 
236                             break; 
237                         case 1: 
238                             glassTexture.minFilter = THREE.LinearFilter; 
239                             glassTexture.magFilter = THREE.LinearFilter; 
240                             textureFilter = 2; 
241                             break; 
242                         case 2: 
243                             glassTexture.minFilter = THREE.LinearFilter; 
244                             glassTexture.magFilter = THREE.LinearMipMapNearestFilter; 
245                             textureFilter = 0; 
246                         break; 
247                     }; 
248                     glassTexture.needsUpdate = true; 
249  
250                 // 'L' - Toggle light 
251                 } else if(keyCode == 76){ 
252                     // If we would just remove the lights from the scene, or set the lights to 
253                     // invisible, we would get a black cube due to the MeshLambertMaterial (it needs 
254                     // light). So we just switch the material to toggle the light 
255                     if(lightIsOn){ 
256                         boxMesh.material = new THREE.MeshBasicMaterial({map:glassTexture}); 
257                         boxMesh.material.side = THREE.DoubleSide; 
258                         if(blendingIsOn){ 
259                             boxMesh.material.depthWrite = false; 
260                             boxMesh.material.transparent = true; 
261                             boxMesh.material.opacity = 0.5; 
262                             boxMesh.material.combine = THREE.MixOperation; 
263                         } else { 
264                             boxMesh.material.depthWrite = true; 
265                             boxMesh.material.opacity = 1.0; 
266                             boxMesh.material.combine = THREE.MultiplyOperation; 
267                         } 
268                         lightIsOn = false; 
269  
270                     } else { 
271                         boxMesh.material = new THREE.MeshLambertMaterial({map:glassTexture}); 
272                         if(!webGLAvailable){ 
273                             boxMesh.material = new THREE.MeshBasicMaterial({map:glassTexture}); 
274                         } 
275                         boxMesh.material.side = THREE.DoubleSide; 
276                         if(blendingIsOn){ 
277                             boxMesh.material.depthWrite = false; 
278                             boxMesh.material.transparent = true; 
279                             boxMesh.material.opacity = 0.5; 
280                             boxMesh.material.combine = THREE.MixOperation; 
281                         } else { 
282                             boxMesh.material.depthWrite = true; 
283                             boxMesh.material.opacity = 1.0; 
284                             boxMesh.material.combine = THREE.MultiplyOperation; 
285                         } 
286                         lightIsOn = true; 
287                     } 
288                     boxMesh.material.needsUpdate = true; 
289  
290                 // 'B' - Toggle blending 
291                 } else if(keyCode == 66){ 
292                     if(blendingIsOn){ 
293                         boxMesh.material.depthWrite = true; 
294                         boxMesh.material.opacity = 1.0; 
295                         boxMesh.material.combine = THREE.MultiplyOperation; 
296                         blendingIsOn = false; 
297                     } else { 
298                         boxMesh.material.depthWrite = false; 
299                         boxMesh.material.transparent = true; 
300                         boxMesh.material.opacity = 0.5; 
301                         boxMesh.material.combine = THREE.MixOperation; 
302                         blendingIsOn = true; 
303                     } 
304                     boxMesh.material.needsUpdate = true; 
305  
306                 // Cursor up 
307                 } else if(keyCode == 38){ 
308                     xSpeed -= 0.01; 
309  
310                 // Cursor down 
311                 } else if(keyCode == 40){ 
312                     xSpeed += 0.01; 
313  
314                 // Cursor left 
315                 } else if(keyCode == 37){ 
316                     ySpeed -= 0.01; 
317  
318                 // Cursor right 
319                 } else if(keyCode == 39){ 
320                     ySpeed += 0.01; 
321  
322                 // Page up 
323                 } else if(keyCode == 33){ 
324                     zTranslation -= 0.2; 
325  
326                 // Page down 
327                 } else if(keyCode == 34){ 
328                     zTranslation += 0.2; 
329                 } 
330             } 
331  
332             /** 
333              * Animate the scene and call rendering. 
334              */ 
335             function animateScene(){ 
336                 // Update and set the rotation around x and y axis 
337                 xRotation += xSpeed; 
338                 yRotation += ySpeed; 
339                 boxMesh.rotation.set(xRotation, yRotation, 0.0); 
340  
341                 // Apply the the translation along the z axis 
342                 boxMesh.position.z = zTranslation; 
343  
344                 // Define the function, which is called by the browser supported timer loop. If the 
345                 // browser tab is not visible, the animation is paused. So 'animateScene()' is called 
346                 // in a browser controlled loop. 
347                 requestAnimationFrame(animateScene); 
348  
349                 // Map the 3D scene down to the 2D screen (render the frame) 
350                 renderScene(); 
351             } 
352  
353             /** 
354              * Render the scene. Map the 3D world to the 2D screen.
355              */ 
356             function renderScene(){ 
357                 renderer.render(scene, camera); 
358             } 
359         </script> 
360     </body> 
361 </html>
Live example