着色器是WebGL系统的核心,可编程图形管线主要通过着色器语言(GLSL,Graphic Library Shading Language)编程来实现各种图形渲染效果。着色器语言GLSL是一种类似C的编译语言,因此要使用着色器也需要进行编译、链接这些通用的步骤。
着色器编程通过着程序对象来管理着色器,也就是说程序对象是着色器的容器,程序对象要求至少包含顶点着色器和片元着色器。着色器的初始化流程包括如下步骤:
- 创建顶点着色器、片元着色器。
- 加载顶点着色器源码、片元着色器源码。
- 编译顶点着色器、片元着色器。
- 创建程序对象。
- 将顶点着色器、片元着色器分配给程序对象。
- 连接程序对象。
- 使用程序对象。
因为几乎所有的WebGL应用程序都要使用上面的方法来初始化着色器,可以通过编写一个辅助函数initShaders来隐藏这些细节,这里使用TypeScript语言演示如何实现。
/*
* gl: 为WebGL上下文,指定类型WebGL2RenderingContext,使用vs code编码时可以智能提示WebGL的方法
* vshaer: 传入顶点着色器源码
* fshader: 传入片元着色器源码
*/
function initShaders(gl: WebGL2RenderingContext, vshader: string, fshader: string): boolean {
// 一个程序对象必须包含顶点着色器和片元着色器
var program = createProgram(gl, vshader, fshader);
if (!program) {
console.log("程序对象创建失败!");
return false;
}
// 使用程序对象
gl.useProgram(program);
// gl添加program属性存放程序对象,为图形应用编程使用
gl["program"] = program;
return true;
}
function createProgram(gl: WebGL2RenderingContext, vshader: string, fshader: string) {
// 创建顶点着色器、片元着色
var vertex_shader = loadShader(gl, gl.VERTEX_SHADER, vshader);
var frag_shader = loadShader(gl, gl.FRAGMENT_SHADER, fshader);
if (!vertex_shader || !frag_shader) {
return null;
}
// 创建程序对象
var program = gl.createProgram();
// 程序对象附加着色器
gl.attachShader(program, vertex_shader);
gl.attachShader(program, frag_shader);
// 连接程序对象
gl.linkProgram(program);
var linked = gl.getProgramParameter(program, gl.LINK_STATUS);
if (!linked) {
var error = gl.getProgramInfoLog(program);
console.log("创建程序对象失败:" + error);
gl.deleteProgram(program);
gl.deleteShader(vertex_shader);
gl.deleteShader(frag_shader);
return null;
}
return program;
}
function loadShader(gl: WebGL2RenderingContext, type: number, source: string) {
// 创建shader
var shader = gl.createShader(type);
// shader加载源码
gl.shaderSource(shader, source);
// 编译shader
gl.compileShader(shader);
// 检查编译结果
var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (!compiled) {
var error = gl.getShaderInfoLog(shader);
console.log("着色器编译失败:" + error);
gl.deleteShader(shader);
return null;
}
return shader;
}
// 导出initShaders方法为其他模块引用
export { initShaders };
参考文献
- 《WebGL编程指南》第9章层次模型,P332。