本人最近正在学习WebGL,所以想借着自己写《Cocos2D-X OpenGLES 2.0教程系列》的同时再应用到WebGL上面来。一来可以加深自己的理解,二来也可以对比两者的差别,提高学习效率。WebGL目前各大厂商都在推,就连微软也开始重视这项技术了,不得不说这是一项不小的进步。而最近我看到一篇文章,讲到《为什么要使用WebGL来做图形学的研究》,深受启发。而且javascript编写OpenGL代码也非常地方便和简洁。另外,js在编写3D程序方面,它的性能是可以和C媲美的。

话不多说,让我们开始吧。

Note: 建议使用Chrome和最新版本的Firefox, Safari来实践此教程。具体有哪些现代浏览器支持WebGL,请查看此网页

声明:由于我是边学边写教程,如果读者有发现错误或者不正确的地方,欢迎批评指正。

创建OpenGL画布

首先,新建一个html文件并加入以下代码:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
<html>
    <canvas id ='c' width='480' height='320'</canvas>
    <script>
        var canvas = document.getElementById('c');
        var names = ["webgl",
                  "experimental-webgl",
                  "webkit-3d", 
                  "moz-webgl"];
      for (var i = 0; i < names.length; ++i) {
          try {
              gl = canvas.getContext(names[i]);
          } 
          catch(e) {}
          if (gl) break;
      }
      if (gl == null){
         alert("WebGL is not available");
      }
gl.clearColor(0,0,0.8,1);
gl.clear(gl.COLOR_BUFFER_BIT);
    </script>
  </html>

使用浏览器运行,你将得到下列结果:(注意下图是WebGL绘制出来的哦,因为你右键是看不到“保存图片”的选项的,以后再也不用费事去截图了!)

创建VBO并且准备顶点数据

1
2
3
4
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
var vertices = [-0.5, -0.5, 0.5, -0.5, 0, 0.5];
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices),gl.STATIC_DRAW);

可以看出,这些函数跟OpenGLES很类似。只是glGenBuffer被重合名为createBuffer了。然后所有OpenGL的函数都位于webgl context对象之中了。

编写Vertex Shader和Fragment Shader

1
2
3
4
5
//setup for the vertex shader and fragment shader
var vs = 'attribute vec2 pos;' +
'void main(){ gl_Position = vec4(pos,0,1);}';
var fs = 'precision mediump float;' +
'void main(){ gl_FragColor = vec4(0,0.8,0,1);}';

这里我们把vertex shader和fragment shader写到两个字符串vs和fs中。因为比较简单,所以才这样做。如果shader很复杂,建议把shader文件单独放置在对应的文件中。

编写Shader Program

接下来,我们需要编译,链接并最终生成我们的shader program,具体代码如下:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
function createShader(str, type){
  var shader = gl.createShader(type);
  gl.shaderSource(shader,str);
  gl.compileShader(shader);
  if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
    throw gl.getShaderInfoLog(shader);
  }
  return shader;
}
function createProgram(vstr,fstr){
  var program = gl.createProgram();
  var vshader = createShader(vstr,gl.VERTEX_SHADER);
  var fshader = createShader(fstr, gl.FRAGMENT_SHADER);
  gl.attachShader(program,vshader);
  gl.attachShader(program,fshader);
  gl.linkProgram(program);
  if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
    throw gl.getProgramInfoLog(program);
  }
  return program;
}
//创建shader program
var program = createProgram(vs,fs);
gl.useProgram(program);

发送顶点数据给Vertex Shader

首先,我们要获取Vertex attribute的location。接着,激活该attribute,最后调用vertexAttribPointer来传递顶点数据。

1
2
3
program.vertexPosAttrib = gl.getAttribLocation(program,'pos');
gl.enableVertexAttribArray(program.vertexPosAttrib);
gl.vertexAttribPointer(program.vertexPosAttrib, 2, gl.FLOAT, false, 0, 0);

绘制三角形

最后,我们调用drawArrays来绘制三角形。

1
gl.drawArrays(gl.TRIANGLES,0,3); 

最终运行结果:

结语

可以看到,一个完整的WebGL绘制三角形的代码与一个OpenGLES 2.0的代码非常类似,但是写起来却非常爽。更重要的是,我们可以用浏览器来实时调试看效果。省去了c++等静态语言的编译链接时间。

本文源码仓库地址:https://git.oschina.net/zilongshanren/Learning-WebGL

推荐阅读