Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

WebGL(壹) 着色器程序的创建

  WebGL是个入门比较难的东西,难就难在它的工作流程复杂上。普通的2D绘图,只要创建了绘图对象就可以直接画出来。但是WebGL的性质并不是绘图对象,而是一个提供显卡操作的接口。我们只是用它来操作GPU和显存,所以WebGL就比传统的2D绘图多了很多流程。
  要使用WebGL,我们要从浏览器上创建一个WebGL对象,和2D绘图一样也是从CANVAS标签开始的。但是目前WebGL的支持程度并不高(至少IE还暂未支持),所以我们还需要考虑浏览器兼容的问题。CANVAS元素上有getContext方法,我们在做2D绘图时也是先调用这个方法获取2D绘图对象的。WebGL也类似,但是它的名称暂时不叫“webgl”。像很多CSS3的样式需要前缀一样,目前获取WebGL对象也需要前缀。所以我们现在必须使用“experimental-webgl”来获取。这里要注意的是这个字符串是区分大小写的,必须全用小写否则取不到对象。
<canvas id="canvas"></canvas>
<script>
//获取WebGL对象
var webgl=canvas.getContext("experimental-webgl");
//......
//其它代码
</script>
  获取到WebGL对象以后我们就可以利用它来对显卡指手划脚了。不过接下来才是麻烦的地方,也就是显卡本身的工作流程问题。显卡是如何工作的呢?我们先来想想电脑是如何工作的吧。如果只有一个操作系统,不许用任何其它程序,那这个电脑基本就是废的,我们什么也做不了。我们平时使用电脑就是在上面运行各种应用程序来做自己需要的事情。你可以把显卡比作一台电脑,而WegGL对象是操作系统,只有这两个东西我们当然没法使用,还需要应用程序。但是显卡本身不使用硬盘的,无法储存应用程序,需要我们在运行时创建应用程序,这就相当于程序现写现用。知道了这些,我们就知道WebGL的第一步应该干什么了,当然是做出个显卡上的程序了
//创建程序(仅仅是创建而已)
var program=webgl.createProgram();
  其实吧,WebGL就是OpenGL的“Web精简版”,而OpenGL的API本身不是面向对象的,全是函数式的。所以WebGL也有个很大坑,我实在忍不住不吐槽它。WebGL看似是封装的很好的对象,比如上面这句创建程序的代码,这就有很大误导性。createProgram这个方法是在webgl这个对象上调用的,但是返回值的program却和webgl这个对象没有半毛钱关系。这个createProgram作为webgl的方法只是为了更好的把OpenGL移植到面向对象的JavaScript中而已。所以,有一大堆的方法和常量被直接丢进了webgl这个对象中,以后会出现很多类似面向过程的方法,心里明白就好。
  既然WebGL本质不是面向对象的,很多东西咱就不称为“对象”了,而称为“句柄”。上面的代码创建了这个program这个句柄以后,初始的它只是个空壳,里面什么都没有,所以要先为它添加功能。我们要明白,它是一个程序。程序就是一堆二进制指令,我们当然不能直接写出二进制的东西,需要使用某种编程语言写出来后再编译才能变成程序。也就是说,为这个program添加功能,实际上就是为它编写代码,然后再编译。(很复杂吧?WebGL就是这么复杂,所以说入门难= =。)既然要咱写代码,那就得问是用什么编程语言了,还有代码需要做什么工作,还有需要开发文档。一个个回答吧,这是“GLSL(OpenGL着色语言)”;需要做的是一般是矩阵与向量的处理,复杂的也有逻辑处理;至于文档嘛,谷歌上能搜到GLSL的手册,也有在线版本,简单的程序直接就能看明白,文档只是参考用。
  这个用着色语言写成的程又叫做着色器程序,和我们平时在操作系统上使用的程序还是有很大差别的。着色器程序工作很单一,无非就是操作坐标和操作颜色。因此,根据这个两功能,我们又把着色器程序分为两个部分,一个是操作坐标的称为“顶点着色器”,另一个是操作颜色的称为“片段着色器”。可能“着色器”这个名词有点玄乎吧,不要胡思乱想,叫这么名字完全是历史原因,就像键盘上的回车键为什么回车键一样老土。总之只要把它们理解为程序就可以了。由于我们把片段着色器和顶点着色器分开了,所以对他们是分别写代码和分别编译。至于为什么要这么麻烦的把它分开,当然是有分开的优点了。如果我们需要改变一个程序的片段着色器就不用连着把顶点着色器也重新编译,这个在以后的操作中会使用到的。
  说了一大堆概念的东西,现在来说说最关键的问题,创建着色器程序的例子呢?好啦,下面就是例子
var vs,fs,vs_s,fs_s;

//创建顶点着色器和片段着色器
vs=webgl.createShader(webgl.VERTEX_SHADER);
fs=webgl.createShader(webgl.FRAGMENT_SHADER);

//着色器程序的源码
vs_s="attribute vec4 p;void main(){gl_Position=p;}";
fs_s="void main(){gl_FragColor=vec4(1.0,0.0,0.0,1.0);}";

//把源码添加进着色器
webgl.shaderSource(vs,vs_s);
webgl.shaderSource(fs,fs_s);

//编译着色器
webgl.compileShader(vs);
webgl.compileShader(fs);

//把着色器添加到程序中
webgl.attachShader(program,vs);
webgl.attachShader(program,fs);

//把这两个着色器程序链接成一个完整的程序
webgl.linkProgram(program);
  这个代码很蛋疼吧?完全是面向过程的,不纠结这个了。制作一个着色器程序就和我们平时写程序的步骤一样:先创建一个文件(创建着色器)、编写代码(为着色器添加源码)、把代码编译为obj(编译着色器)、把obj链接成exe(添加到程序中并链接)。可能是现在的编程语言太智能化了,都是一条龙服务。但是写过C语言程序的一定对这个步骤不陌生,这就是应用程序开发的标准步骤。完成这个我们就做好了一个完整的着色器程序。上面的着色器源码的具体含义以后再说了,这就是一个最简单的着色器程序。
  好啦,暂时先到这儿吧,内容也不少了。至于这个程序怎么用,咱留点悬念下一篇再说。

参考:
  http://www.opengl.org/sdk/docs/man3/xhtml/
网名:
34.203.245.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^