什么是webgl着色器 (参考框图说明webgl渲染流程)

着色器是WebGL系统的核心,可编程图形管线主要通过着色器语言(GLSL,Graphic Library Shading Language)编程来实现各种图形渲染效果。着色器语言GLSL是一种类似C的编译语言,因此要使用着色器也需要进行编译、链接这些通用的步骤。

着色器编程通过着程序对象来管理着色器,也就是说程序对象是着色器的容器,程序对象要求至少包含顶点着色器和片元着色器。着色器的初始化流程包括如下步骤:

  1. 创建顶点着色器、片元着色器。
  2. 加载顶点着色器源码、片元着色器源码。
  3. 编译顶点着色器、片元着色器。
  4. 创建程序对象。
  5. 将顶点着色器、片元着色器分配给程序对象。
  6. 连接程序对象。
  7. 使用程序对象。

因为几乎所有的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。