Advertisement
 
Tutorial
  1 <!-- ------------------------------------- 
  2   Roughly based (or inspired by) NeHe Tutorial 14   
  3   Original:  http://nehe.gamedev.net/tutorial/bitmap_fonts/17002/ 
  4    
  5   @author: rkwright@geofx.com 
  6 -------------------------------------- --> 
  7 <html xmlns="http://www.w3.org/1999/xhtml"> 
  8     <head>
  9         <title>NEHE Tutorial 14</title> 
 10         <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> 
 11  
 12         <!-- The following meta line optimizes the site for mobile devices. It sets the viewport size 
 13         to the screen size, so it will be displayed maximized, but unscaled. --> 
 14         <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1"/> 
 15         <link rel="stylesheet" type="text/css" href="../css/NEHE.css" /> 
 16  
 17         <!-- Include several libraries from THREE.js and the Scene class  --> 
 18         <script src="../js/r69/three.js" type="text/javascript"></script> 
 19         <script src="../js/r69/Detector.js" type="text/javascript"></script> 
 20         <script src="../js/r69/OrbitControls.js" type="text/javascript"></script> 
 21         <script src="../js/r69/Stats.js" type="text/javascript"></script> 
 22         <script src="../js/r69/Scene.js" type="text/javascript"></script> 
 23  
 24         <!-- include the JSON format font files we will use --> 
 25         <script src="../fonts/helvetiker_bold_italic.typeface.js"></script> 
 26         <script src="../fonts/helvetiker_italic.typeface.js"></script> 
 27         <script src="../fonts/helvetiker_bold.typeface.js"></script> 
 28         <script src="../fonts/helvetiker_regular.typeface.js"></script> 
 29     </head> 
 30     <body>     
 31         <script> 
 32             // global variables 
 33             var textGeom; 
 34          
 35             var     size = 1;                // this is actually the HEIGHT of the text. in user-space 
 36             var     height = 0.2;            // this is TOTALLY misnamed.  It is the thickness of the extruded text 
 37             var        curveSegments = 10;        // number of points on "the curve" - which curve? 
 38             var     font = "helvetiker"; 
 39             var        weight = "normal"; 
 40             var        style = "italic"; 
 41  
 42             var        bevelThickness = 0.05; 
 43             var        bevelSize = 0.05; 
 44             var     bevelEnabled = false; 
 45  
 46             var        textMat = 0; 
 47             var     extrudeMaterial = 0; 
 48             var        text= "Wowser"; 
 49  
 50             // allocate the Scene object, request orbitControls, some of 3D axes 10 units high and the stats 
 51             var nScene = new Scene( { axisHeight:10, controls:true, displayStats:true }); 
 52              
 53             // set up the THREE.js scene via our Scene object 
 54             nScene.initialize(); 
 55              
 56             // then initialize our demo's stuff 
 57             initializeDemo(); 
 58  
 59             // Animate the scene 
 60             animateScene(); 
 61  
 62             /** 
 63              * Initialize the Demo.   
 64              */ 
 65             function initializeDemo() { 
 66  
 67                 createText(); 
 68             }; 
 69                  
 70             /** 
 71              * Here we actually create the text.  Not too much to it, actually.
 72              */ 
 73             function createText() { 
 74  
 75                 // Note that one has to create a Material for both the face the side of the font. 
 76                 // Three.js has some bugs, as does the font-converter software at typface.js  
 77                 // http://typeface.neocracy.org/fonts.html.  The converter doesn't always keep the 
 78                 // same winding order for nested or adjacent paths and then three.js gets confused 
 79                 // In addition, with release 69 of three.js, you should not use smooth shading on the face  
 80                 // of the font. If you do, you will get some pretty odd artifacts.  Try it and see. 
 81                 // However, the face of the font is flat anyway, so flat shading is fine. 
 82                 // In addition, you shouldn't use Phong material on the sides.  Again, you'll get odd 
 83                 // artifacts. 
 84                 // Finally, go easy on the beveling as large bevels tend to look odd (more bugs?) 
 85                 var materialFront = new THREE.MeshPhongMaterial( { color: 0xff0000, shading: THREE.FlatShading } ); 
 86                 var materialSide = new THREE.MeshLambertMaterial( { color: 0x000088, shading: THREE.SmoothShading } ); 
 87                 var materialArray = [ materialFront, materialSide ]; 
 88  
 89                 textGeom = new THREE.TextGeometry( text , { 
 90                     size: size,                        // actually the height of the font, in user-space 
 91                     height: height,                    // THICKNESS of the extruded font, in user-space 
 92                     curveSegments: curveSegments, 
 93                     font: font,                        // name of the font 
 94                     weight: weight,                    // bold or normal 
 95                     style: style,                    // regular, italic or bold 
 96                     bevelThickness: bevelThickness, 
 97                     bevelSize: bevelSize, 
 98                     bevelEnabled: bevelEnabled, 
 99                     material: 0,                    // index in the array of the face 
100                     extrudeMaterial: 1                // index in the array of the extruded sides 
101                 }); 
102                  
103                 var textMaterial = new THREE.MeshFaceMaterial(materialArray); 
104                 var textMesh = new THREE.Mesh(textGeom, textMaterial ); 
105  
106                 textGeom.computeBoundingBox(); 
107                 textGeom.computeVertexNormals(); 
108                  
109                 nScene.addToScene(textGeom); 
110                  
111                 // get the width of the string so we can center it on the origin 
112                 textGeom.computeBoundingBox(); 
113                  
114                 var textWidth = textGeom.boundingBox.max.x - textGeom.boundingBox.min.x; 
115                  
116                 textMesh.position.set(-0.5 * textWidth, 0, 0 ); 
117                 nScene.addToScene(textMesh); 
118             } 
119  
120             /** 
121              * Animate the scene and call rendering. 
122              */ 
123             function animateScene() { 
124  
125                 // Tell the browser to call this function when page is visible 
126                 requestAnimationFrame(animateScene); 
127                  
128                 // Map the 3D scene down to the 2D screen (render the frame) 
129                 nScene.renderScene(); 
130             } 
131         </script> 
132     </body> 
133 </html>
Scene.js
  1     //some constants 
  2     var        X_AXIS = 0; 
  3     var        Y_AXIS = 1; 
  4     var        Z_AXIS = 2; 
  5      
  6 Scene = function ( parameters ) { 
  7      
  8     this.scene; 
  9     this.renderer; 
 10     this.camera; 
 11  
 12     this.controls = false; 
 13     this.orbitControls; 
 14  
 15     this.displayStats = false; 
 16     this.stats; 
 17  
 18     this.ambientLight; 
 19     this.directionalLight; 
 20  
 21     this.axisHeight = 0; 
 22  
 23     this.setParameters( parameters ); 
 24 }; 
 25  
 26 // the scene's parameters from the values JSON object 
 27 // lifted from MrDoob's implementation in three.js 
 28 Scene.prototype = { 
 29          
 30     setParameters: function( values ) { 
 31  
 32         if ( values === undefined ) return; 
 33      
 34         for ( var key in values ) { 
 35      
 36             var newValue = values[ key ]; 
 37      
 38             if ( newValue === undefined ) { 
 39                 console.warn( "NEHE: '" + key + "' parameter is undefined." ); 
 40                 continue; 
 41             } 
 42      
 43             if ( key in this ) { 
 44                 var currentValue = this[ key ]; 
 45      
 46                 if ( currentValue instanceof THREE.Color ) { 
 47                     currentValue.set( newValue ); 
 48                 } else if ( currentValue instanceof THREE.Vector3 && newValue instanceof THREE.Vector3 ) { 
 49                     currentValue.copy( newValue ); 
 50                 } else if ( key == 'overdraw' ) { 
 51                     // ensure overdraw is backwards-compatible with legacy boolean type 
 52                     this[ key ] = Number( newValue ); 
 53                 } else { 
 54                     this[ key ] = newValue; 
 55                 } 
 56             } 
 57         } 
 58     }, 
 59  
 60     initialize: function () { 
 61         // Check whether the browser supports WebGL.  
 62         if ( !Detector.webgl ) Detector.addGetWebGLMessage(); 
 63      
 64         // Create the scene, in which all objects are stored (e. g. camera, lights, geometries, ...) 
 65         this.scene = new THREE.Scene(); 
 66      
 67         // Get the size of the inner window (content area) 
 68         var canvasWidth = window.innerWidth; 
 69         var canvasHeight = window.innerHeight; 
 70      
 71         // if the caller supplied the container elm ID try to find it 
 72         var container; 
 73         var containerID; 
 74         if (containerID != null && typeof containerID != 'undefined') 
 75             container = document.getElementById(containerID); 
 76          
 77         // couldn't find it, so create it ourselves 
 78         if (container == null || typeof container == 'undefined') { 
 79             container = document.createElement( 'div' ); 
 80             document.body.appendChild( container ); 
 81         } 
 82         else { 
 83             canvasWidth = container.clientWidth; 
 84             canvasHeight = container.clientHeight; 
 85         } 
 86      
 87         // set up the camera 
 88         this.camera = new THREE.PerspectiveCamera(45, canvasWidth / canvasHeight, 0.1, 1000); 
 89         this.camera.position.set(0, 6, 6); 
 90         this.camera.lookAt(this.scene.position); 
 91         this.scene.add(this.camera); 
 92      
 93         // allocate the THREE.js renderer 
 94         this.renderer = new THREE.WebGLRenderer({antialias:true}); 
 95      
 96         // Set the background color of the renderer to black, with full opacity 
 97         this.renderer.setClearColor(0x000000, 1); 
 98      
 99         // Set the renderers size to the content areas size 
100         this.renderer.setSize(canvasWidth, canvasHeight); 
101      
102         // Get the DIV element from the HTML document by its ID and append the renderer's DOM object 
103         container.appendChild(this.renderer.domElement); 
104          
105         // Ambient light has no direction, it illuminates every object with the same 
106         // intensity. If only ambient light is used, no shading effects will occur. 
107         this.ambientLight = new THREE.AmbientLight(0x404040); 
108         this.scene.add(this.ambientLight); 
109      
110         // Directional light has a source and shines in all directions, like the sun. 
111         // This behaviour creates shading effects. 
112         this.directionalLight = new THREE.PointLight(0xffffff); 
113         this.directionalLight.position.set(250,250,250);  
114         this.scene.add(this.directionalLight); 
115          
116         // request the orbitControls be created and enabled 
117         // add the controls 
118         if (this.controls == true) 
119             this.orbitControls = new THREE.OrbitControls( this.camera, this.renderer.domElement ); 
120          
121         if ( this.axisHeight != 0 ) 
122             this.drawAxes(this.axisHeight); 
123          
124         //------ STATS --------------------     
125         // displays current and past frames per second attained by scene 
126         if (this.displayStats == true) { 
127             this.stats = new Stats(); 
128             this.stats.domElement.style.position = 'absolute'; 
129             this.stats.domElement.style.bottom = '0px'; 
130             this.stats.domElement.style.zIndex = 100; 
131             container.appendChild( this.stats.domElement ); 
132         } 
133     }, 
134  
135     addToScene: function ( obj ) { 
136         this.scene.add(obj); 
137     }, 
138  
139 /** 
140  * Render the scene. Map the 3D world to the 2D screen. 
141  */ 
142     renderScene: function() { 
143          
144         this.renderer.render(this.scene, this.camera); 
145  
146         // the orbit controls, if used, have to be updated as well 
147         if (this.orbitControls != null && typeof this.orbitControls != 'undefined')  
148             this.orbitControls.update(); 
149  
150         if (this.stats != null && typeof this.stats != 'undefined')  
151             this.stats.update(); 
152  
153 }, 
154  
155 // draw some axes 
156     drawAxis: function( axis, axisColor, axisHeight ) { 
157         var        AXIS_RADIUS   =    axisHeight/200.0; 
158         var        AXIS_HEIGHT   =    axisHeight; 
159         var        AXIS_STEP     =    axisHeight/20.0; 
160         var        AXIS_SEGMENTS = 32; 
161         var        AXIS_GRAY     = 0x777777; 
162         var        AXIS_WHITE    = 0xEEEEEE; 
163          
164         //console.log("drawAxis " + axis + " ht: " +  AXIS_HEIGHT + ", " + AXIS_STEP + " color: " + axisColor); 
165      
166         for ( i=0; i<(AXIS_HEIGHT/AXIS_STEP); i++ ) 
167         { 
168             //console.log("loop " +  i); 
169              
170             var pos = -AXIS_HEIGHT / 2 + i * AXIS_STEP; 
171      
172             if ((i & 1) == 0) 
173                 curColor = axisColor; 
174             else if (pos < 0) 
175                 curColor = AXIS_GRAY; 
176             else 
177                 curColor = AXIS_WHITE; 
178              
179             //console.log(i + " pos: " + pos + " color: " + curColor); 
180              
181             var geometry = new THREE.CylinderGeometry( AXIS_RADIUS, AXIS_RADIUS, AXIS_STEP, AXIS_SEGMENTS );  
182             var material = new THREE.MeshLambertMaterial( {color: curColor} );  
183             var cylinder = new THREE.Mesh( geometry, material );  
184              
185             pos += AXIS_STEP/2.0; 
186             if (axis == X_AXIS) 
187             { 
188                 cylinder.position.x = pos; 
189                 cylinder.rotation.z = Math.PI/2; 
190             } 
191             else if (axis == Y_AXIS) 
192             { 
193                 cylinder.rotation.y = Math.PI/2; 
194                 cylinder.position.y = pos; 
195             } 
196             else 
197             {     
198                 cylinder.position.z = pos; 
199                 cylinder.rotation.x = Math.PI/2; 
200             } 
201              
202             this.scene.add( cylinder ); 
203         }; 
204     }, 
205  
206     drawAxes: function( height ) { 
207      
208         this.drawAxis(X_AXIS, 0xff0000, height); 
209         this.drawAxis(Y_AXIS, 0x00ff00, height); 
210         this.drawAxis(Z_AXIS, 0x0000ff, height); 
211     } 
212 }
NEHE.css
  1 /* 
  2  * @author rkwright   /  www.geofx.com 
  3  */ 
  4   
  5  body { 
  6     /* Set the background color of the HTML page to black */ 
  7     background-color: #000000; 
  8  
  9     /* Hide oversized content. This prevents the scroll bars. */ 
 10     overflow: hidden; 
 11  
 12     /* Define the font and the color for the usage, which is an ordinary HTML overlay. */ 
 13     font-family: Monospace; 
 14     color: white; 
 15 }
Live example