WebGL编程起步
Posted 前端乖乖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WebGL编程起步相关的知识,希望对你有一定的参考价值。
上篇文章简单介绍了WebGL的一些相关概念、现状以及工作原理,没有涉及到具体编码,本文将使用WebGL的相关技术来实现一个简单的效果示例,从而让大家了解WebGL编程的基本流程和关键操作。最后,还介绍了一些WebGL的库和框架,恰当的使用这些第三方框架,可以大大提高我们的工作效率。
开发流程
WebGL的开发过程主要包括以下几个步骤:
1.准备容器
WebGL要在页面上执行相关的渲染,必须依赖一个特定的容器,在html5中,使用的是Canvas作为容器。
<body onload="start()"> <canvas id="glcanvas" width="640" height="480"> Your browser doesn't appear to support the HTML5 canvas element. </canvas> </body>
如上所示,我们在HTML中添加了一个canvas元素,并且设置了onload事件作为入口,后续的所有业务逻辑都会在start函数中进行处理。
//WebGL全局变量var gl;function start() { var canvas = document.getElementById("glcanvas"); //初始化上下文 gl = initGL(canvas); //初始化着色器 initShaders(); //生成/加载模型数据 initBuffers(); //设置擦除颜色为黑色,透明度不透明 gl.clearColor(0.0, 0.0, 0.0, 1.0); //开启“深度测试”,z-缓存 gl.enable(gl.DEPTH_TEST); //渲染 drawScene(); }
从上面的代码可以看出,我们整个的过程主要包含了四个比较重要的阶段:初始化上下文、初始化着色器、加载模型数据和渲染。下面会对这几个过程做详细介绍。
2.初始化上下文
initGL方法主要用来初始化WebGL的绘制环境:
function initGL(canvas) { gl=null; try { //尝试创建标准上下文,如果失败,回退到试验性上下文 gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl"); } catch(e) {} //如果没有GL上下文,马上放弃 if (!gl) { alert("Unable to initialize WebGL. Your browser may not support it."); } }
需要注意的是,我们为了得到WebGL上下文,需要使用canvas的getContext方法,这里有两个参数值可以使用:webgl或者experimental-webgl。不同浏览器环境下使用的参数不一样,具体可参照WebGL - 3D Canvas graphics。
3.初始化着色器
在3D场景的开发过程中会涉及到非常多的计算过程(颜色、位置等),为了提高效率,使用了硬件加速,这个时候GPU的强大计算能力得到了运用。但是,怎样告诉它正确执行相关计算逻辑呢?答案是着色器。着色器告诉相关计算单元做什么,而着色器语言(GLSL)来告诉它们怎么做。
The OpenGL ES Shading Language
一般情况下,我们在HTML中定义着色器,然后在代码中获取并使用。
<script id="shader-fs" type="x-shader/x-fragment">
precision mediump float;
varying vec4 vColor;
void main(void) {
gl_FragColor = vColor;
}
</script>
<script id="shader-vs" type="x-shader/x-vertex">
attribute vec3 aVertexPosition;
attribute vec4 aVertexColor;
uniform mat4 uMVMatrix;
uniform mat4 uPMatrix;
varying vec4 vColor;
void main(void) {
gl_Position = uPMatrix * uMVMatrix * vec4(aVertexPosition, 1.0);
vColor = aVertexColor;
}
</script>
上文的代码中定义了两个着色器:片段着色器和顶点着色器。
顶点着色器定义了模型中顶点的位置和颜色信息。
片段着色器通过差值的方法来处理WebGL中像素的相关数据,这里定义了像素上颜色的计算方法。
我们在initShaders方法中来查找使用着色器:
var shaderProgram;
function initShaders() {
var fragmentShader = getShader(gl, "shader-fs"); var vertexShader = getShader(gl, "shader-vs");
//创建着色器 shaderProgram = gl.createProgram(); gl.attachShader(shaderProgram, vertexShader); gl.attachShader(shaderProgram, fragmentShader); //链接着色器程序 gl.linkProgram(shaderProgram);
//检查着色器是否成功连接 if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS)) {
alert("Could not initialise shaders"); }
//连接成功后激活渲染器程序 gl.useProgram(shaderProgram); shaderProgram.vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
//启用顶点缓冲区数组 gl.enableVertexAttribArray(shaderProgram.vertexPositionAttribute); shaderProgram.vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor"); gl.enableVertexAttribArray(shaderProgram.vertexColorAttribute); shaderProgram.pMatrixUniform = gl.getUniformLocation(shaderProgram, "uPMatrix"); shaderProgram.mvMatrixUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix"); }
上述代码加载了模型数据,并且通过一系列的绑定操作和相关设置,告诉GPU如何去处理相关的渲染过程。
这里使用了一个工具函数getShader,它的作用是从DOM中获取定义的相关着色器程序,并返回编译好的渲染器程序:
function getShader(gl, id) {
var shaderScript, theSource, currentChild, shader; shaderScript = document.getElementById(id); if (!shaderScript) {
return null; }
//获取着色器的文本内容保存到theSource theSource = ""; currentChild = shaderScript.firstChild; while(currentChild) {
if (currentChild.nodeType == currentChild.TEXT_NODE){ theSource += currentChild.textContent; } currentChild = currentChild.nextSibling; } //创建顶点着色器或片段着色器 if (shaderScript.type == "x-shader/x-fragment") { shader = gl.createShader(gl.FRAGMENT_SHADER); } else if (shaderScript.type == "x-shader/x-vertex") { shader = gl.createShader(gl.VERTEX_SHADER); } else { //非法类型返回null return null; } gl.shaderSource(shader, theSource); //编译着色器代码 gl.compileShader(shader); //检查是否编译成功 if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader)); return null; } //成功后返回编译好的着色器 return shader; }
4.生成/加载模型数据
下面的initBuffers函数来将模型数据加载到缓冲器中,这样将顶点位置和颜色数据在上下文中准备就绪,随后才可以进行下一步的渲染操作。
var triangleVertexPositionBuffer;
var triangleVertexColorBuffer;
function initBuffers() { triangleVertexPositionBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer);
var vertices = [
0.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0 ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW); triangleVertexPositionBuffer.itemSize = 3; triangleVertexPositionBuffer.numItems = 3; triangleVertexColorBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexColorBuffer);
var colors = [
1.0, 0.0, 0.0, 1.0,
0.0, 1.0, 0.0, 1.0,
0.0, 0.0, 1.0, 1.0 ]; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(colors), gl.STATIC_DRAW); triangleVertexColorBuffer.itemSize = 4; triangleVertexColorBuffer.numItems = 3; }
5.渲染
经过上一步的模型数据准备后,就可以直接通过WegGL来进行渲染了。下面的drawScene方法,对3D模型进行了一些基本设置,然后根据缓冲区中的相关数据,来绘制出相应的效果。
function drawScene() { gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); pMatrix = okMat4Proj(45.0, gl.viewportWidth / gl.viewportHeight, 0.1, 100.0); mvMatrix = okMat4Trans(-1.5, 0.0, -7.0); gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexPositionBuffer); gl.vertexAttribPointer(shaderProgram.vertexPositionAttribute, triangleVertexPositionBuffer.itemSize, gl.FLOAT, false, 0, 0); gl.bindBuffer(gl.ARRAY_BUFFER, triangleVertexColorBuffer); gl.vertexAttribPointer(shaderProgram.vertexColorAttribute, triangleVertexColorBuffer.itemSize, gl.FLOAT, false, 0, 0); setMatrixUniforms(); gl.drawArrays(gl.TRIANGLES, 0, triangleVertexPositionBuffer.numItems); }
至此,一个完整的WebGL程序基本开发完毕了,通过上面的过程我们发现,使用原生的WebGL来进行特殊场景的开发简直就是一种折磨。我们需要了解各种实现细节和专业知识,这对于非专业的开发人员是一种极大的挑战。所以,自然而然就有大量的类库和框架出现,来简化我们的开发过程,提高我们的工作效率。
点击这里可以看到用three.js来实现的上文效果
WebGL库和框架
下面简单介绍一些WebGL的类库或者框架:
three.js,这是一个低复杂、轻量级的开源框架,也是目前应用最广泛的3D框架,模型文件支持多种格式,渲染器的选择也非常灵活,方便使用者快速开发各种效果。
PhiloGL,这也是一个开源框架,注重性能,拥有非常强大的接口,比较适合数据可视化和游戏开发。
Babylon.js,这是一款非常适合作为游戏引擎的开源框架,让WebGL的使用更加简单、强大,非常适合游戏开发。
SceneJS,这一开源框架的特点在于,对于高精度的细节控制非常好,适合的领域有工程学、医学建模等。
CopperLicht,这是一个非常出色的3D引擎,并且带有编辑器,唯一的缺点是,他不是开源的,如果商用需要购买。
前端圈--打造专业的前端技术会议
为web前端开发者提供技术分享和交流的平台
打造一个良好的前端圈生态,推动web标准化的发展
官网:http://fequan.com
投稿:content@fequan.com
走进名企系列是促进公司与前端从业人员零距离的交流,建立起沟通的桥梁,让前端工程师共同成长,为前端人业人员打造一个良好的生态圈。
以上是关于WebGL编程起步的主要内容,如果未能解决你的问题,请参考以下文章