WebGL - 示例 從文件中加載並使用不同着色器

因爲對不同的場景以及不同的材質需要使用不同的着色器,因此需要使用多個着色器,而不是單個,單個着色器是無法繪製出很複雜的場景,因爲有的物體沒有紋理而有的有紋理以及別的效果

1、外部文件加載着色器

着色器語言就是 GLSL格式的代碼,我們可以先把頂點和片元着色器分別寫在.glsl後綴名的文件中,如果你的編譯器支持這種語法檢測,那麼代碼就會有顏色,而不僅僅是字符串樣式顯示,儘管着色器代碼本身就是字符串

下面是將要繪製的單色立方體的着色器文件

single_vertex_shader.glsl

// 頂點着色器
attribute vec4 a_Position;
attribute vec4 a_Normal;
uniform mat4 u_MvpMatrix;
uniform mat4 u_NormalMatrix;
varying vec4 v_Color;

void main(){

    vec3 lightDirection = vec3(0.0, 0.0, 1.0); // 燈光的位置 在世界座標系中
    vec4 color = vec4(0.5, 0.5, 0.8, 1.0);// 表面顏色
    gl_Position = u_MvpMatrix * a_Position; // 計算後的頂點座標
    vec3 normal = normalize(vec3(u_NormalMatrix * a_Normal));//標準化法向量
    float nDot = max(dot(normal, lightDirection), 0.0);
    v_Color = vec4(color.rgb * nDot, color.a);
    
}

single_fragment_shader.glsl

precision mediump float;
varying vec4 v_Color;
void main(){
    gl_FragColor = v_Color
}

從外部文件加載着色器,其實就是加載.glsl文件,讀取裏面的數據,然後通過頂點着色器和片元着色器創建程序對象

關於如何加載外部文件的方法,在上一篇文章中有介紹,你也可以直接去我的gitee上倉庫的lib目錄直接下載加載器

2、創建程序對象

加載完.glsl文件之後,就可以使用這兩個着色器程序了,創建program對象,下面是兩個程序對象,通過四個着色器代碼創建得到的

var singleProgram = createProgram(gl, single_vertex_shader, single_fragment_shader);
var textureProgram = createProgram(gl, texture_vertex_shader,texture_fragment_shader);

3、獲取變量存儲地址

採用javascript對象屬性的方式,把每個變量的存儲地址掛載到程序對象上,便於使用

// 獲取 singleProgram 中的 attribute 和 uniform 變量存儲位置
singleProgram.a_Position = gl.getAttribLocation(singleProgram, 'a_Position');
singleProgram.a_Normal = gl.getAttribLocation(singleProgram, 'a_Normal');
singleProgram.u_MvpMatrix = gl.getUniformLocation(singleProgram, 'u_MvpMatrix');
singleProgram.u_NormalMatrix = gl.getUniformLocation(singleProgram, 'u_NormalMatrix');

// 獲取 textureProgram 中的 attribute 和 uniform 變量存儲位置
textureProgram.a_Position = gl.getAttribLocation(textureProgram, 'a_Position');
textureProgram.a_Normal = gl.getAttribLocation(textureProgram, 'a_Normal');
textureProgram.a_TexCoord = gl.getAttribLocation(textureProgram, 'a_TexCoord');
textureProgram.u_MvpMatrix = gl.getUniformLocation(textureProgram, 'u_MvpMatrix');
textureProgram.u_NormalMatrix = gl.getUniformLocation(textureProgram, 'u_NormalMatrix');
textureProgram.u_Sampler = gl.getUniformLocation(textureProgram, 'u_Sampler');

4、設置頂點顏色以及法線信息

因爲創建的是兩個立方體,所以它們的頂點數據和頂點索引以及法線數據都是可以共用的

var cube = initVertexBuffers(gl);
if (!cube) {
    console.log('failed to set the vertex information');
    return false;
}

上面通過initVertexBuffers()方法來設置頂點信息

設置完公用的頂點信息後,一個立方體是需要加載貼圖的,因此需要把貼圖的數據給加載到貼圖立方體的片元着色器上,此處是通過initTexture(gl, program)方法來進行設置

var texture = initTextures(gl, textureProgram);
if (!texture) {
    console.log('failed to intialize the texture.');
    return false;
}

設置完以上數據之後,就可以開始繪製

因爲是三維物體,有z軸深度,需要開啓深度

gl.enable(gl.DEPTH_TEST)
// 設置canvas清空後的顏色
gl.clearColor(0.0, 0.5, 0.5, 1.0)

5、設置視圖矩陣參數

var viewProjMatrix = new Matrix4();
viewProjMatrix.setPerspective(30.0, canvas.width / canvas.height, 1.0, 100.0)
viewProjMatrix.lookAt(0.0, 0.0, 15.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0);

下面就可以在循環渲染方法中,進行幀刷新渲染

實際上在真正的項目開發過程中,重複這些步驟是很繁瑣的,對一些反覆的操作封裝比較好的引擎例如three.js它隱藏了webgl的內部執行流程,同時也內置了很多的着色器,每一種材質以及燈光的添加都對應了一種着色器,這些着色器是可以進行修改的,並且three.js也支持自己去寫着色器以及原生webgl代碼

https://ithanmang.gitee.io/webgl-notes/home/07-高級技術示例/08-使用不同着色器.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章