webgl入门也挺麻烦的,需要了解JavaScript脚本编辑语言,需要会Html,需要懂点Opengl,还要有懂些计算机图形学的知识。做得精还需要会编写shader。
当然,这些都可以慢慢学,而且webgl看似难入门,其实把它各个部分割裂开,也挺简单的。当然,JavaScript和Html知识是必备的技能。
编辑器还是选择强大的visual studio。然后创建TypeScript的Html项目。这里创建这个项目就可以直接在chrome上查看结果,很方便,不用搞什么服务器什么的。
好,来看第一个部分,创建几何图形。
首先在index.html里写入主体代码。这里写了两个着色器,顶点着色器和片面着色器,当然也可以放在其他地方。然后,确定画布大小。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <title>TypeScript HTML App</title> <link rel="stylesheet" href="app.css" type="text/css" /> <script src="app.js"></script> <script id="shader-vs"> attribute vec3 v3Position; void main(void) { gl_Position = vec4(v3Position, 1.0); } </script> <script id="shader-fs"> precision mediump float; void main(void) { gl_FragColor = vec4(0.0, 1.0, 1.0, 1.0); } </script> <script type="text/javascript" src="Common/gl-matrix.js"></script> <script type="text/javascript" src="Common/initShaders.js"></script> <script type="text/javascript" src="Common/webgl_utils.js"></script> <script type="text/javascript" src="Test/test001.js"></script> <script> function Init() { var canvas = document.getElementById('gl-canvas'); webgl = canvas.getContext("webgl"); webgl.viewport(0, 0, canvas.clientWidth, canvas.clientHeight); InitGeometry(webgl); } </script> </head> <body onload='Init()'> <canvas id="gl-canvas" width="512" height="512"></canvas> </body> </html>
接下来创建着色器,并应用着色器到程序中,这部分可以不用细究,后面再学。这部分是initshader.js.
function initShaderToWebgl(webgl, v3PositionIndex) { vertexShaderObject = webgl.createShader(webgl.VERTEX_SHADER); fragmentShaderObject = webgl.createShader(webgl.FRAGMENT_SHADER); webgl.shaderSource(vertexShaderObject, getShaderSource("shader-vs")); webgl.shaderSource(fragmentShaderObject, getShaderSource("shader-fs")); webgl.compileShader(vertexShaderObject); webgl.compileShader(fragmentShaderObject); if (!webgl.getShaderParameter(vertexShaderObject, webgl.COMPILE_STATUS)) { alert("error:vertexShaderObject"); return; } if (!webgl.getShaderParameter(fragmentShaderObject, webgl.COMPILE_STATUS)) { alert("error:fragmentShaderObject"); return; } programObject = webgl.createProgram(); webgl.attachShader(programObject, vertexShaderObject); webgl.attachShader(programObject, fragmentShaderObject); webgl.bindAttribLocation(programObject, v3PositionIndex, "v3Position"); webgl.linkProgram(programObject); if (!webgl.getProgramParameter(programObject, webgl.LINK_STATUS)) { alert("error:programObject"); return; } webgl.useProgram(programObject); } // // 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 getShaderSource(scriptID) { var shaderScript = document.getElementById(scriptID); if (shaderScript == null) return ""; var sourceCode = ""; var child = shaderScript.firstChild; while (child) { if (child.nodeType == child.TEXT_NODE) sourceCode += child.textContent; child = child.nextSibling; } return sourceCode; }
最后就是他的几何部分,卸载test001.js中。
var webgl = null; var vertexShaderObject = null; var fragmentShaderObject = null; var programObject = null; var triangleBuffer = null; var v3PositionIndex = 0; function InitGeometry(webgl) { var jsArrayData = [ 0.0, 1.0, 0.0,//上顶点 -1.0, -1.0, 0.0,//左顶点 1.0, -1.0, 0.0 ];//右顶点 render(webgl, v3PositionIndex, jsArrayData); //开启着色器中的顶点属性 webgl.enableVertexAttribArray(v3PositionIndex); //描述顶点数组中的数据形式 webgl.vertexAttribPointer(v3PositionIndex, 3, webgl.FLOAT, false, 0, 0); //画三角形 webgl.drawArrays(webgl.TRIANGLES, 0, 3); } function render(webgl, v3PositionIndex, jsArrayData) { //初始化定义shader initShaderToWebgl(webgl, v3PositionIndex); initBuffer(webgl, jsArrayData); webgl.clearColor(0.0, 0.0, 0.0, 1.0); webgl.clear(webgl.COLOR_BUFFER_BIT); } //创建缓冲区并绑定顶点数据 function initBuffer(webgl, jsArrayData) { triangleBuffer = webgl.createBuffer(); webgl.bindBuffer(webgl.ARRAY_BUFFER, triangleBuffer); webgl.bufferData(webgl.ARRAY_BUFFER, new Float32Array(jsArrayData), webgl.STATIC_DRAW); }
webgl_utils.js用来写各种小工具。gl-matrix.js用来存放矩阵计算的方法。暂时用不上。
最后结果:
现在来画几条线,这个就简单了,直接在上面的InitGeometry()方法里修改,比如我要画四条直线,那就是8个点。只需要在jsArrayData里添加点即可,另外,需要把drawArray里的3改为8,另外用上webgl.LINES的模式。更多样式请参考:https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/drawArrays
各个实例请参考:http://www.cocoachina.com/ios/20170710/19798.html
function InitGeometry(webgl) { var jsArrayData = [ -0.5, -0.5, 0.0, -0.5, 0.5, 0.0, -0.5, 0.5, 0.0, 0.5, 0.5, 0.0, 0.5, 0.5, 0.0, 0.5, -0.5, 0.0, 0.5, -0.5, 0.0, -0.5, -0.5, 0.0, ];//右顶点 render(webgl, v3PositionIndex, jsArrayData); //开启着色器中的顶点属性 webgl.enableVertexAttribArray(v3PositionIndex); //描述顶点数组中的数据形式 webgl.vertexAttribPointer(v3PositionIndex, 3, webgl.FLOAT, false, 0, 0); //画直线 webgl.drawArrays(webgl.LINES, 0, 8); }
讲得比较简单,最好结合书和视频教程来看。但是把各个部分分隔开,还是很好理解的。