概念
WebGL API 的 WebGLShader 可以是一个顶点着色器(vertex shader)或片元着色器(fragment shader)。
每个 WebGLProgram 都需要这两种类型的着色器。
创建流程
要创建一个 WebGLShader 需要使用 WebGLRenderingContext.createShader,通过 WebGLRenderingContext.shaderSource() 然后挂接GLSL源代码 , 最后调用 WebGLRenderingContext.compileShader() 完成着色器(shader)的编译。
function createShader (gl, sourceCode, type) {
// 调用 WebGLRenderingContext 的 createShader 方法,创建一个 WebGLShader 对象
// type 有两种类型,分别是 gl.VERTEX_SHADER 和 gl.FRAGMENT_SHADER
var shader = gl.createShader( type );
// 挂载 glsl 源码
gl.shaderSource( shader, sourceCode );
// 编译挂接了源码以后的 shader
gl.compileShader( shader );
// 获取编译 shader 的状态,是否编译成功了
// 这个方法可以还能获取shader 的一些别的信息,比如是否已经将 shader 删除,shader 的类型等等,具体可以参考下面的链接:
// https://developer.mozilla.org/zh-CN/docs/Web/API/WebGLRenderingContext/getShaderParameter
if ( !gl.getShaderParameter(shader, gl.COMPILE_STATUS) ) {
// 获取 shader 的信息,如果编译过程中没有任何问题的话,获得的 info 为一个空的字符串
var info = gl.getShaderInfoLog( shader );
throw "Could not compile WebGL program. \n\n" + info;
}
return shader;
}
此时 WebGLShader 仍不是可用的形式,他需要被添加到一个 WebGLProgram 里后才能够使用。
WebGLShader 的理解
WebGLShader 实例化以后,其实是一个空对象,不信可以打开 chrome 控制台看一下,你会发现里面干净的什么都没有。
那么我们就能明白过来,其实这一块,并不是采用我们熟悉的 js 的面型对象的编程方式构建的,至于为什么要这样构建,那就只能去问规范编制的人了。
所以,有些初看不是很好理解的地方,我们才能明白为什么要这么用了。
比如为什么创建 shader 用这个方式:
var shader = gl.createShader( type ); // 创建
gl.shaderSource( shader, sourceCode ); // 挂载源码
gl.compileShader( shader ); // 编译 shader
如果用 JavaScript 的眼光来看的话,明显感觉这样写好多余啊,直接这样简化一下,岂不是更简单:
var shader = new gl.Shader(type, sourceCode); // 实例化
shader.compile(); // 编译
现在我只能提出这个疑问,无法解答。
也就是说,我们要习惯各种不同的编程语言的变成习惯,孰优孰劣我们无从判断,也许只有等我们站到了一定的高度以后,才能对这个问题给出满意的答案吧。