Advertisement
 
Tutorial
  1 <!--  
  2   NeHe Tutorial 11 
  3   Original:  http://http://nehe.gamedev.net/tutorial/flag_effect_(waving_texture)/16002/ 
  4    
  5   @author: rkwright@geofx.com 
  6  --> 
  7  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> 
  8 <html xmlns="http://www.w3.org/1999/xhtml"> 
  9     <head>
 10         <title>NEHE Tutorial 11</title> 
 11         <meta http-equiv="content-type" content="text/html; charset=UTF-8"/> 
 12  
 13         <!-- The following meta line optimizes the site for mobile devices. It sets the viewport size 
 14         to the screen size, so it will be displayed maximized, but unscaled. --> 
 15         <meta name="viewport" content="width=device-width, height=device-height, initial-scale=1"/> 
 16         <link rel="stylesheet" type="text/css" href="../css/NEHE.css" /> 
 17  
 18         <!-- Include several libraries from THREE.js and the Scene class  --> 
 19         <script src="../js/r69/three.js" type="text/javascript"></script> 
 20         <script src="../js/r69/Detector.js" type="text/javascript"></script> 
 21         <script src="../js/r69/OrbitControls.js" type="text/javascript"></script> 
 22         <script src="../js/r69/Stats.js" type="text/javascript"></script> 
 23         <script src="../js/r69/Scene.js" type="text/javascript"></script> 
 24          
 25         <!-- the shaders --> 
 26         <script id="vertexShader" type="x-shader/x-fragment"> 
 27             // create two shared variable for the VS and FS containing the normal and the uv coords 
 28             varying vec3         vNormal; 
 29             varying vec2         vUv; 
 30             attribute float      displacement; 
 31             uniform float        amplitude; 
 32          
 33             void main() { 
 34                 // set the variables passed (behind the scenes) by three.js to our 
 35                 // "varying" variables, which makes them available to the other shader 
 36                 vNormal = normal; 
 37                 vUv = uv; 
 38                 // find the position of the vertex as a function of its current position 
 39                 // and the displacement * amplitude - which makes it wave 
 40                 vec3 newPosition = position + normal * vec3(displacement * amplitude); 
 41                 gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0); 
 42             } 
 43         </script> 
 44              
 45         <script id="fragmentShader" type="x-shader/x-vertex"> 
 46             // create the shared variables. which are set in the fragment shader 
 47             varying vec3         vNormal; 
 48             varying vec2         vUv; 
 49             uniform sampler2D     texImage; 
 50      
 51             void main(void) { 
 52                  
 53                 gl_FragColor = texture2D(texImage, vUv); 
 54             } 
 55         </script> 
 56      
 57     <!-- --------------------------------------------------------------- --> 
 58  
 59     </head> 
 60     <body>     
 61         <script> 
 62             var uniforms; 
 63             var texture; 
 64             var frameCounter = 0; 
 65      
 66             // allocate the Scene object, request orbitControls, some of 3D axes 10 units high and the stats 
 67             var nScene = new Scene( { axisHeight:10, controls:true, displayStats:true }); 
 68              
 69             // set up the THREE.js scene via our Scene object 
 70             nScene.initialize(); 
 71              
 72             // then initialize our demo's stuff 
 73             initializeDemo(); 
 74             // Animate the scene 
 75             animateScene(); 
 76             /** 
 77              * Initialize the Demo.  This is NeHe #11: http://nehe.gamedev.net/tutorial/flag_effect_%28waving_texture%29/16002/
 78              * Create a image mapped texture which is then oscillated (in a sine wave)
 79              */ 
 80             function initializeDemo() { 
 81                  
 82                 // now go create the mesh 
 83                 createMesh(); 
 84             }; 
 85              
 86             function createMesh() { 
 87                 // load the image as a texture 
 88                 texture = new THREE.ImageUtils.loadTexture("data/Tim.bmp"); 
 89                  
 90                 // all we need is a simple planar mesh. 9 by 9 units with 45x45 verticies 
 91                 var planeGeometry = new THREE.PlaneGeometry(9,9,45,45); 
 92                 // add a uniform for the amplitude and the texture.  These are read-only  
 93                 // variables that get passed to our shaders 
 94                 uniforms = { 
 95                         amplitude:    { type: 'f', value: 0 }, 
 96                         texImage:    { type: 't', value: texture } 
 97                 }; 
 98                  
 99                 // these are variables with one per vertex 
100                 var attributes = { 
101                         displacement: { 
102                             type: 'f', // a float 
103                             value: []  // an empty array 
104                         } 
105                 }; 
106                  
107                 // now populate the array of attributes.  This creates a simple parametric  
108                 // surface with the shape of a sine wave 
109                 var verts  = planeGeometry.vertices; 
110                 var values = attributes.displacement.value; 
111          
112                 for ( var y=0; y<46; y++ ) { 
113                     for ( var x=0; x<46; x++ ) { 
114                         var sVal = Math.sin((((x/5.0)*40.0)/360.0)*Math.PI*2.0); 
115                         var index = x + 46 * y; 
116                         values[index] =  sVal; 
117                     } 
118                 } 
119                 // find the shaders 
120                 var vs = document.getElementById("vertexShader").textContent; 
121                 var fs = document.getElementById("fragmentShader").textContent; 
122                 // and create our shader material... 
123                 var shaderMaterial = new THREE.ShaderMaterial({ 
124                         uniforms:         uniforms,    // pass the "uniforms" vars 
125                         attributes:     attributes,    // and the attributes 
126                         side:THREE.DoubleSide,        // want the texture on both sides of the wave 
127                         vertexShader:   vs,            // pointers to the shaders 
128                         fragmentShader: fs 
129                     }); 
130                  
131                 // finally create the mesh and add it to the scene 
132                 var mesh = new THREE.Mesh( planeGeometry, shaderMaterial); 
133                 nScene.addToScene(mesh); 
134             } 
135              
136             /** 
137              * Animate the scene and call rendering. 
138              */ 
139             function animateScene() { 
140                 // Tell the browser to call this function when page is visible 
141                 requestAnimationFrame(animateScene); 
142                 // update the amplitude based on the frame value. Taking the sine merely 
143                 // causes the value to vary from -1..1.  When multiplied by the displacement 
144                 // this causes the the wave to be slowly inverted back and forth 
145                 uniforms.amplitude.value = Math.sin(frameCounter); 
146                  
147                 // bump the frame counter 
148                 frameCounter += 0.1; 
149                  
150                 // Map the 3D scene down to the 2D screen (render the frame) 
151                 nScene.renderScene(); 
152             } 
153         </script> 
154     </body> 
155 </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