JavaScript-WebGL學習筆記
阿新 • • 發佈:2018-11-19
對有DX/OpenGL基礎的人,通過下面的程式碼可以快速有一個WebGL概念
示例有兩個檔案組成
webgl.html
<html> <head> <!-- Date: 2018-3-16 Author: kagula Prologue: 對已經有DirectX/OpenGL基礎的,通過這裡的程式碼快速對WebGl有個概念! Description: 用兩個三角形拼出一個彩色的正方形. Original: [1]https://developer.mozilla.org/en-US/docs/Web/API/WebGL_API/Tutorial/Using_shaders_to_apply_color_in_WebGL 測試環境 [1]Chrome 65.0.3325.162 [2]nginx 1.12.2 --> <title>第一個Webgl程式</title> <meta charset="utf-8"> <!-- gl-matrix version 2.4.0 from http://glmatrix.net/ --> <script type="text/javascript" src="/gl-matrix-min.js"></script> <script type="text/javascript" src="/kagula/webgl_helper.js"></script> </head> <body> <canvas id="glCanvas" width="640" height="480"></canvas> </body> </html> <script> main(); //弄4個頂點, 4個顔色, 用來演示render流程! function initBuffers(gl) { // Create a buffer for the square's positions. const positionBuffer = gl.createBuffer(); // Select the positionBuffer as the one to apply buffer // operations to from here out. gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer); // Now create an array of positions for the square. const positions = [ 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, -1.0, -1.0, ]; // Now pass the list of positions into WebGL to build the // shape. We do this by creating a Float32Array from the // JavaScript array, then use it to fill the current buffer. gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(positions), gl.STATIC_DRAW); //給每個頂點弄一個顔色 const colors = [ 1.0, 1.0, 1.0, 1.0, // white 1.0, 0.0, 0.0, 1.0, // red 0.0, 1.0, 0.0, 1.0, // green 0.0, 0.0, 1.0, 1.0, // blue ]; const colorBuffer = gl.createBuffer();//建立gl快取,但是不指定快取型別. gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);//指定olorBuffer的型別為gl.ARRAY_BUFFER //緩衝區物件中的資料只指定1次,但是常常使用。這種模式下,OpenGL會將資料放在能夠快速渲染的地方。 gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW); return { position: positionBuffer, color: colorBuffer, }; } function main() { //選擇器的使用 //http://www.runoob.com/jsref/met-document-queryselector.html const canvas = document.querySelector("#glCanvas"); // Initialize the GL context const gl = canvas.getContext("webgl"); // Only continue if WebGL is available and working if (!gl) { alert("Unable to initialize WebGL. Your browser or machine may not support it."); return; } // Vertex shader program const vsSource = ` attribute vec4 aVertexPosition; attribute vec4 aVertexColor;//從外部拿到顏色,不做任何處理,丟給vColor. uniform mat4 uModelViewMatrix; uniform mat4 uProjectionMatrix; //從aVertexColor拿到的顏色直接給vColor, //由vColor傳給Fragment Shader. varying lowp vec4 vColor; void main() { gl_Position = uProjectionMatrix * uModelViewMatrix * aVertexPosition; vColor = aVertexColor;//什麼都不做,只是為了把從外部得到的color傳遞給Fragment Shader. } `; // Fragment shader, 相當於pixel shader const fsSource = ` varying lowp vec4 vColor;//從vertex shader得到的顏色放在這裡。 void main() { //gl_FragColor = vec4(1.0, 1.0, 1.0, 1.0); gl_FragColor = vColor;//直接使用從vertex shader傳過來的資料。 } `; //裝配shader到shaderProgram中去 const shaderProgram = initShaderProgram(gl, vsSource, fsSource); //為了讓外部的資料能統一傳到shanderProgram中去,新建programInfo物件。 //vertexPosition => aVertexPosition位置 //projectionMatrix => uProjectionMatrix位置 //modelViewMatrix => uModelViewMatrix位置 //... const programInfo = { program: shaderProgram, attribLocations: { vertexPosition: gl.getAttribLocation(shaderProgram, 'aVertexPosition'), vertexColor: gl.getAttribLocation(shaderProgram, 'aVertexColor'), }, uniformLocations: { projectionMatrix: gl.getUniformLocation(shaderProgram, 'uProjectionMatrix'), modelViewMatrix: gl.getUniformLocation(shaderProgram, 'uModelViewMatrix'), }, }; //initBuffers(gl)返回要render的vertex. drawScene(gl, programInfo, initBuffers(gl)); }//main </script>
webgl_helper.js
// Initialize a shader program, so WebGL knows how to draw our data function initShaderProgram(gl, vsSource, fsSource) { const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource); const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource); // Create the shader program const shaderProgram = gl.createProgram(); gl.attachShader(shaderProgram, vertexShader); gl.attachShader(shaderProgram, fragmentShader); gl.linkProgram(shaderProgram); // If creating the shader program failed, alert if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) { alert('Unable to initialize the shader program: ' + gl.getProgramInfoLog(shaderProgram)); return null; } return shaderProgram; } // creates a shader of the given type, uploads the source and // compiles it. function loadShader(gl, type, source) { const shader = gl.createShader(type); // Send the source to the shader object gl.shaderSource(shader, source); // Compile the shader program gl.compileShader(shader); // See if it compiled successfully if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { alert('An error occurred compiling the shaders: ' + gl.getShaderInfoLog(shader)); gl.deleteShader(shader); return null; } return shader; } function drawScene(gl, programInfo, buffers) { gl.clearColor(0.0, 0.0, 0.0, 1.0); // Clear to black, fully opaque gl.clearDepth(1.0); // Clear everything gl.enable(gl.DEPTH_TEST); // Enable depth testing gl.depthFunc(gl.LEQUAL); // Near things obscure far things // Clear the canvas before we start drawing on it. gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); // Create a perspective matrix, a special matrix that is // used to simulate the distortion of perspective in a camera. // Our field of view is 45 degrees, with a width/height // ratio that matches the display size of the canvas // and we only want to see objects between 0.1 units // and 100 units away from the camera. const fieldOfView = 45 * Math.PI / 180; // in radians const aspect = gl.canvas.clientWidth / gl.canvas.clientHeight; const zNear = 0.1; const zFar = 100.0; const projectionMatrix = mat4.create(); // note: glmatrix.js always has the first argument // as the destination to receive the result. mat4.perspective(projectionMatrix, fieldOfView, aspect, zNear, zFar); // Set the drawing position to the "identity" point, which is // the center of the scene. const modelViewMatrix = mat4.create(); // Now move the drawing position a bit to where we want to // start drawing the square. mat4.translate(modelViewMatrix, // destination matrix modelViewMatrix, // matrix to translate [-0.0, 0.0, -6.0]); // amount to translate // Tell WebGL how to pull out the positions from the position // buffer into the vertexPosition attribute. { // gl.ARRAY_BUFFER => 指向 => buffers.position gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position); //指定源資料格式. //https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/vertexAttribPointer gl.vertexAttribPointer( programInfo.attribLocations.vertexPosition, 2,// pull out 2 values per iteration //Must be 1, 2, 3, or 4. 比如說頂點{x,y}要選2,{x,y,z}要選3,顏色{r,g,b,a}要選4 gl.FLOAT,// the data in the buffer is 32bit floats false,// don't normalize 0,//stride, how many bytes to get from one set of values to the next 0);//how many bytes inside the buffer to start from //源資料填充到gl //tell WebGL that this attribute should be filled with data from our array buffer. //gl.ARRAY_BUFFER => 資料傳到 => programInfo.attribLocations.vertexPosition gl.enableVertexAttribArray( programInfo.attribLocations.vertexPosition); } // Tell WebGL how to pull out the colors from the color buffer // into the vertexColor attribute. { //buffers.color => 資料傳到 => gl.ARRAY_BUFFER gl.bindBuffer(gl.ARRAY_BUFFER, buffers.color); //設定programInfo.attribLocations.vertexColor格式 gl.vertexAttribPointer( programInfo.attribLocations.vertexColor, 4,//size of {r g b a} = 4. gl.FLOAT, false,//normalize 0,//stride 0);//offset //gl.ARRAY_BUFFER => 資料傳到 => programInfo.attribLocations.vertexColor gl.enableVertexAttribArray( programInfo.attribLocations.vertexColor); } // Tell WebGL to use our program when drawing gl.useProgram(programInfo.program); // Set the shader uniforms //projectionMatrix => programInfo.uniformLocations.projectionMatrix gl.uniformMatrix4fv( programInfo.uniformLocations.projectionMatrix, false,//A GLboolean specifying whether to transpose the matrix. Must be false. projectionMatrix); //modelViewMatrix => programInfo.uniformLocations.modelViewMatrix gl.uniformMatrix4fv( programInfo.uniformLocations.modelViewMatrix, false, modelViewMatrix); //資料準備好後可以draw了. { const offset = 0; const vertexCount = 4; //開始處理已經在gl中的頂點資料 //gl.TRIANGLE_STRIP模式復用前面兩個頂點, 所以這裡告訴gl, render兩個三角形. gl.drawArrays(gl.TRIANGLE_STRIP, offset, vertexCount); } }