Advertisement
arealloudbird

terrain.js

Oct 18th, 2018
167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. /**
  2.  * @fileoverview Terrain - A simple 3D terrain using WebGL
  3.  * @author Eric Shaffer
  4.  */
  5.  
  6. /** Class implementing 3D terrain. */
  7. class Terrain{  
  8. /**
  9.  * Initialize members of a Terrain object
  10.  * @param {number} div Number of triangles along x axis and y axis
  11.  * @param {number} minX Minimum X coordinate value
  12.  * @param {number} maxX Maximum X coordinate value
  13.  * @param {number} minY Minimum Y coordinate value
  14.  * @param {number} maxY Maximum Y coordinate value
  15.  */
  16.     constructor(div,minX,maxX,minY,maxY){
  17.         this.div = div;
  18.         this.minX=minX;
  19.         this.minY=minY;
  20.         this.maxX=maxX;
  21.         this.maxY=maxY;
  22.  
  23.         this.size = div+1;
  24.         this.max = this.size-1;
  25.         this.map = new Float32Array(this.size * this.size);
  26.  
  27.         // Allocate vertex array
  28.         this.vBuffer = [];
  29.         // Allocate triangle array
  30.         this.fBuffer = [];
  31.         // Allocate normal array
  32.         this.nBuffer = [];
  33.         // Allocate array for edges so we can draw wireframe
  34.         this.eBuffer = [];
  35.         console.log("Terrain: Allocated buffers");
  36.  
  37.         this.generateHeightMap(0.001);
  38.         console.log("Terrain: Generated Heightmap");
  39.        
  40.         this.generateTriangles();
  41.         console.log("Terrain: Generated triangles");
  42.        
  43.         this.generateLines();
  44.         console.log("Terrain: Generated lines");
  45.        
  46.         // Get extension for 4 byte integer indices for drwElements
  47.         var ext = gl.getExtension('OES_element_index_uint');
  48.         if (ext ==null){
  49.             alert("OES_element_index_uint is unsupported by your browser and terrain generation cannot proceed.");
  50.         }
  51.     }
  52.    
  53.     /**
  54.     * Set the x,y,z coords of a vertex at location(i,j)
  55.     * @param {Object} v an an array of length 3 holding x,y,z coordinates
  56.     * @param {number} i the ith row of vertices
  57.     * @param {number} j the jth column of vertices
  58.     */
  59.     setVertex(v,i,j)
  60.     {
  61.         //Your code here
  62.         var vid = 3*(i*(this.div+1) + j);
  63.         this.vbuffer[vid] = v[0];
  64.         this.vbuffer[vid+1] = v[1];
  65.         this.vbuffer[vid+2] = v[2];
  66.     }
  67.    
  68.     /**
  69.     * Return the x,y,z coordinates of a vertex at location (i,j)
  70.     * @param {Object} v an an array of length 3 holding x,y,z coordinates
  71.     * @param {number} i the ith row of vertices
  72.     * @param {number} j the jth column of vertices
  73.     */
  74.     getVertex(v,i,j)
  75.     {
  76.         //Your code here
  77.         var vid = 3*(i*(this.div+1) + j);
  78.         v[0] = this.vbuffer[vid];
  79.         v[1] = this.vbuffer[vid+1];
  80.         v[2] = this.vbuffer[vid+2];
  81.     }
  82.    
  83.     /**
  84.     * Send the buffer objects to WebGL for rendering
  85.     */
  86.     loadBuffers()
  87.     {
  88.         // Specify the vertex coordinates
  89.         this.VertexPositionBuffer = gl.createBuffer();
  90.         gl.bindBuffer(gl.ARRAY_BUFFER, this.VertexPositionBuffer);      
  91.         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.vBuffer), gl.STATIC_DRAW);
  92.         this.VertexPositionBuffer.itemSize = 3;
  93.         this.VertexPositionBuffer.numItems = this.numVertices;
  94.         console.log("Loaded ", this.VertexPositionBuffer.numItems, " vertices");
  95.    
  96.         // Specify normals to be able to do lighting calculations
  97.         this.VertexNormalBuffer = gl.createBuffer();
  98.         gl.bindBuffer(gl.ARRAY_BUFFER, this.VertexNormalBuffer);
  99.         gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(this.nBuffer),
  100.                   gl.STATIC_DRAW);
  101.         this.VertexNormalBuffer.itemSize = 3;
  102.         this.VertexNormalBuffer.numItems = this.numVertices;
  103.         console.log("Loaded ", this.VertexNormalBuffer.numItems, " normals");
  104.    
  105.         // Specify faces of the terrain
  106.         this.IndexTriBuffer = gl.createBuffer();
  107.         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.IndexTriBuffer);
  108.         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(this.fBuffer),
  109.                   gl.STATIC_DRAW);
  110.         this.IndexTriBuffer.itemSize = 1;
  111.         this.IndexTriBuffer.numItems = this.fBuffer.length;
  112.         console.log("Loaded ", this.numFaces, " triangles");
  113.    
  114.         //Setup Edges  
  115.         this.IndexEdgeBuffer = gl.createBuffer();
  116.         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.IndexEdgeBuffer);
  117.         gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint32Array(this.eBuffer),
  118.                   gl.STATIC_DRAW);
  119.         this.IndexEdgeBuffer.itemSize = 1;
  120.         this.IndexEdgeBuffer.numItems = this.eBuffer.length;
  121.        
  122.         console.log("triangulatedPlane: loadBuffers");
  123.     }
  124.    
  125.     /**
  126.     * Render the triangles
  127.     */
  128.     drawTriangles(){
  129.         gl.bindBuffer(gl.ARRAY_BUFFER, this.VertexPositionBuffer);
  130.         gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, this.VertexPositionBuffer.itemSize,
  131.                          gl.FLOAT, false, 0, 0);
  132.  
  133.         // Bind normal buffer
  134.         gl.bindBuffer(gl.ARRAY_BUFFER, this.VertexNormalBuffer);
  135.         gl.vertexAttribPointer(shaderProgram.vertexNormalAttribute,
  136.                            this.VertexNormalBuffer.itemSize,
  137.                            gl.FLOAT, false, 0, 0);  
  138.    
  139.         //Draw
  140.         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.IndexTriBuffer);
  141.         gl.drawElements(gl.TRIANGLES, this.IndexTriBuffer.numItems, gl.UNSIGNED_INT,0);
  142.     }
  143.    
  144.     /**
  145.     * Render the triangle edges wireframe style
  146.     */
  147.     drawEdges(){
  148.    
  149.         gl.bindBuffer(gl.ARRAY_BUFFER, this.VertexPositionBuffer);
  150.         gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, this.VertexPositionBuffer.itemSize,
  151.                          gl.FLOAT, false, 0, 0);
  152.  
  153.         // Bind normal buffer
  154.         gl.bindBuffer(gl.ARRAY_BUFFER, this.VertexNormalBuffer);
  155.         gl.vertexAttribPointer(shaderProgram.vertexNormalAttribute,
  156.                            this.VertexNormalBuffer.itemSize,
  157.                            gl.FLOAT, false, 0, 0);  
  158.    
  159.         //Draw
  160.         gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this.IndexEdgeBuffer);
  161.         gl.drawElements(gl.LINES, this.IndexEdgeBuffer.numItems, gl.UNSIGNED_INT,0);  
  162.     }
  163. /**
  164.  * Fill the vertex and buffer arrays
  165.  */    
  166. generateTriangles()
  167. {
  168.     //Your code here
  169.     var x_amount = (this.maxX - this.minX) / this.div;
  170.     var y_amount = (this.maxY - this.minY) / this.div; 
  171.  
  172.     for (var i = 0; i <= this.div; i++) {
  173.         for (var j = 0; j <= this.div; j++) {
  174.             this.vBuffer.push(j*x_amount + this.minX);
  175.             this.vBuffer.push(this.minY + i*y_amount);
  176.             this.vBuffer.push(this.getHeightMap(i,j)+0.5);
  177.  
  178.  
  179.             this.nBuffer.push(0);
  180.             this.nBuffer.push(0);
  181.             this.nBuffer.push(1);
  182.         }
  183.     }
  184.  
  185.     for (var i = 0; i < this.div; i++) {
  186.         for (var j = 0; j < this.div; j++) {
  187.  
  188.             var vid = i*(this.div+1) + j;
  189.  
  190.             this.fBuffer.push(vid);
  191.             this.fBuffer.push(vid + this.div+1);
  192.             this.fBuffer.push(vid + this.div+2);
  193.  
  194.             this.fBuffer.push(vid);
  195.             this.fBuffer.push(vid+1);
  196.             this.fBuffer.push(vid + this.div+2);
  197.         }
  198.     }
  199.    
  200.     this.numVertices = this.vBuffer.length/3;
  201.     this.numFaces = this.fBuffer.length/3;
  202. }
  203.  
  204. generateHeightMap(roughness)
  205. {
  206.     this.setHeightMap(0       ,0       ,Math.random() *-1);
  207.     this.setHeightMap(this.max,0       ,Math.random() * 0);
  208.     this.setHeightMap(this.max,this.max,Math.random() *-1);
  209.     this.setHeightMap(0       ,this.max,Math.random() * 1);
  210.  
  211.     this.diamondSquare(this.max, roughness);
  212. }
  213.  
  214. diamondSquare(size, roughness)
  215. {
  216.     var x, y, half = size / 2;
  217.     var scale = roughness * size;
  218.     if (half < 1) return;
  219.  
  220.     for (y = half; y < this.max; y += size) {
  221.         for (x = half; x < this.max; x += size) {
  222.             this.diamond(x, y, half, Math.random() * scale * 2 - scale);
  223.         }
  224.     }
  225.  
  226.     for (y = 0; y <= this.max; y += half) {
  227.         for (x = (y + half) % size; x <= this.max; x += size) {
  228.             this.square(x, y, half, Math.random() * scale * 2 - scale);
  229.         }
  230.     }
  231.  
  232.     this.diamondSquare(size / 2, roughness);
  233. }
  234.  
  235. square(x, y, size, offset) {
  236.     var top    = this.getHeightMap(x       ,y - size);      // top
  237.     var right  = this.getHeightMap(x + size,y       );      // right
  238.     var bottom = this.getHeightMap(x       ,y + size);      // bottom
  239.     var left   = this.getHeightMap(x - size,y       );      // left
  240.  
  241.     var ave = (top + right + bottom + left) / 4;
  242.  
  243.     this.setHeightMap(x, y, ave + offset);
  244. }
  245.  
  246. diamond(x, y, size, offset) {
  247.     var ul = this.getHeightMap(x - size,y - size);   // upper left
  248.     var ur = this.getHeightMap(x + size,y - size);   // upper right
  249.     var lr = this.getHeightMap(x + size,y + size);   // lower right
  250.     var ll = this.getHeightMap(x - size,y + size);   // lower left
  251.  
  252.     var ave = (ul + ur + lr + ll) / 4;
  253.  
  254.     this.setHeightMap(x, y, ave + offset);
  255. }
  256.  
  257. getHeightMap(x, y)
  258. {
  259.     if (x < 0 || x > this.max || y < 0 || y > this.max) return -1;
  260.     return this.map[x + this.size * y];
  261. }
  262.  
  263. setHeightMap(x, y, val)
  264. {
  265.     this.map[x + this.size * y] = val;
  266. }
  267.  
  268. /**
  269.  * Print vertices and triangles to console for debugging
  270.  */
  271. printVBuffer()
  272. {
  273.     for(var i=0;i<this.numVertices;i++) {
  274.         console.log("v ", this.vBuffer[i*3], " ",
  275.                           this.vBuffer[i*3 + 1], " ",
  276.                           this.vBuffer[i*3 + 2], " ");             
  277.     }
  278. }
  279.  
  280. printFBuffer()
  281. {
  282.     for(var i=0;i<this.numFaces;i++) {
  283.         console.log("f ", this.fBuffer[i*3], " ",
  284.                           this.fBuffer[i*3 + 1], " ",
  285.                           this.fBuffer[i*3 + 2], " ");
  286.     }
  287. }
  288.  
  289. /**
  290.  * Generates line values from faces in faceArray
  291.  * to enable wireframe rendering
  292.  */
  293. generateLines()
  294. {
  295.     var numTris=this.fBuffer.length/3;
  296.     for(var f=0;f<numTris;f++)
  297.     {
  298.         var fid=f*3;
  299.         this.eBuffer.push(this.fBuffer[fid]);
  300.         this.eBuffer.push(this.fBuffer[fid+1]);
  301.        
  302.         this.eBuffer.push(this.fBuffer[fid+1]);
  303.         this.eBuffer.push(this.fBuffer[fid+2]);
  304.        
  305.         this.eBuffer.push(this.fBuffer[fid+2]);
  306.         this.eBuffer.push(this.fBuffer[fid]);
  307.     }
  308.    
  309. }
  310.    
  311. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement