1. 程式人生 > >40 WebGL著色器和著色器程式物件:initShader()函式的內部流程

40 WebGL著色器和著色器程式物件:initShader()函式的內部流程

首先將initShaders()函式的相關程式碼貼出:

/**
 * Create a program object and make current
 * @param gl GL context
 * @param vshader a vertex shader program (string)
 * @param fshader a fragment shader program (string)
 * @return true, if the program object was created and successfully made current
 */
function initShaders(gl, vshader, fshader) {
    var program = createProgram(gl, vshader, fshader);
    if (!program) {
        console.log('無法建立程式物件');
        return false;
    }

    gl.useProgram(program);
    gl.program = program;

    return true;
}

/**
 * Create the linked program object
 * @param gl GL context
 * @param vshader a vertex shader program (string)
 * @param fshader a fragment shader program (string)
 * @return created program object, or null if the creation has failed
 */
function createProgram(gl, vshader, fshader) {
    // 建立著色器物件
    var vertexShader = loadShader(gl, gl.VERTEX_SHADER, vshader);
    var fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fshader);
    if (!vertexShader || !fragmentShader) {
        return null;
    }

    // 建立程式物件
    var program = gl.createProgram();
    if (!program) {
        return null;
    }

    // 為程式物件分配頂點著色器和片元著色器
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);

    // 連線著色器
    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(fragmentShader);
        gl.deleteShader(vertexShader);
        return null;
    }
    return program;
}

/**
 * 建立著色器物件
 * @param gl GL context
 * @param type the type of the shader object to be created
 * @param source shader program (string)
 * @return created shader object, or null if the creation has failed.
 */
function loadShader(gl, type, source) {
    // 建立著色器物件
    var shader = gl.createShader(type);
    if (shader == null) {
        console.log('無法建立著色器');
        return null;
    }

    // 設定著色器原始碼
    gl.shaderSource(shader, source);

    // 編譯著色器
    gl.compileShader(shader);

    // 檢查著色器的編譯狀態
    var compiled = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
    if (!compiled) {
        var error = gl.getShaderInfoLog(shader);
        console.log('Failed to compile shader: ' + error);
        gl.deleteShader(shader);
        return null;
    }

    return shader;
}
initShaders()函式將呼叫createProgram()函式,後者負責建立一個連線好的程式物件。

createProgram()函式則又會呼叫loadShader()函式,後者負責建立一個編譯好的著色器物件。

下面講解一下這三個函式相關的作用:

initShaders():

首先呼叫createProgram()函式建立一個連線好的程式物件,然後告訴WebGL系統來使用這個程式物件,最後將程式悐設為gl物件的program屬性。

createProgram():

通過呼叫loadShader()函式,建立頂點著色器和片元著色器的著色器物件。loadShader()函式返回的著色器物件已經制定過原始碼並已經成功編譯了。

createProgram()函式自己負責建立程式物件,然後將前面撞見的頂點著色器和片元著色器分配給程式物件。

接著,該函式連線程式物件,並檢查是否連線成功。如果連線成功,就返回程式物件。

loadShader():

loadShader()函式首先建立了一個著色器物件,然後為改著色器物件指定原始碼,並進行編譯,接著檢查編譯是否成功,如果編譯成功,沒有出錯,就返回著色器物件。