1. 程式人生 > >原生webgl學習(四) WebGL繪製矩形

原生webgl學習(四) WebGL繪製矩形

上節課筆者繪製了一個顏色隨頂點位置變化的三角形,實現平移、旋轉和縮放變換的矩陣計算,並提供了一個可供互動的選單欄工具:原生webgl學習(三) WebGL中的矩陣運算:平移、旋轉和縮放

在前面我們已經畫了兩次三角形了,這次,改變一些套路,我們畫矩形。畫矩形的程式碼跟上一節大同小異,程式碼解釋可以參考上一節:原生webgl學習(三) WebGL中的矩陣運算:平移、旋轉和縮放,唯一不同的是頂點座標發生了改變,利用兩個三角形構成一個矩形,只需要將程式碼中的頂點稍作修改即可:

let positions = [
        -150, -100,
         150, -100,
        -150,  100,
         150, -100,
        -150,  100,
         150,  100
    ];

在畫圖的時候gl.drawArrays的引數稍作修改即可,由於頂點陣列長度增加,由原來的3個頂點變為6個頂點,故count應變為6,在這裡提供一種更加友好的方法,可以根據陣列的長度畫圖:

 //這樣一來對所有陣列都適用,三維的為positions.length / 3
 let primitiveType = gl.TRIANGLES;
 let offset3 = 0;
 let count = positions.length / 2;
 gl.drawArrays(primitiveType, offset3, count);//畫圖

這個demo的程式碼在你們下載的資料夾下的chapter-02裡面的color-triangle-02.html,執行效果如下:

大家要注意,這個demo的矩形的顏色並不會隨著頂點的位置的變化而變化,那是由於在JavaScript程式碼裡面,已經提前設定好頂點的顏色,所以著色器程式碼也要稍微修改一下:

<script id="vertex-shader" type="x-shader/x-vertex">
    attribute vec2 a_position;
    attribute vec4 a_color;
    uniform mat3 u_matrix;
    varying vec4 v_color;

    void main() {
        vec4 offset = vec4(0.1, 0.1, 0, 1);
        gl_Position = vec4((u_matrix * vec3(a_position, 1)).xy, 0, 1) + offset;
        v_color = a_color;
    }
</script>
<script id="fragment-shader" type="x-shader/x-fragment">
    precision mediump float;
    varying vec4 v_color;
    void main() {
        gl_FragColor = v_color;
    }
</script>

 頂點著色器裡面定義了一個用於接收來自JavaScript程式碼顏色資訊的attribute變數:a_color,在JavaScript程式碼中,需要獲取到這個變數的位置:

 let colorAttributeLocation = gl.getAttribLocation(program, 'a_color');

 為其建立緩衝區,並寫入資料:

 gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
 setColor(gl, 1);

//設定顏色,alpha為透明度
 function setColor(gl, alpha = 1) {
      gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
            Math.random(), Math.random(), Math.random(), alpha,
            Math.random(), Math.random(), Math.random(), alpha,
            Math.random(), Math.random(), Math.random(), alpha,
            Math.random(), Math.random(), Math.random(), alpha,
            Math.random(), Math.random(), Math.random(), alpha,
            Math.random(), Math.random(), Math.random(), alpha
      ]), gl.STATIC_DRAW);
   }

接下來要建立著色器中的a_color與上述緩衝區之間的連結,並取出緩衝區的資料:

 //建立著色器中attribute顏色變數與緩衝區之間的連線
  gl.enableVertexAttribArray(colorAttributeLocation);
  gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
  const size2 = 4;//2維座標:每次迭代執行提取兩個單位資料
  const type2 = gl.FLOAT;//每個單位的資料型別是32位浮點型;如果為Uint8Array的8位陣列,要設定為gl.UNSIGNED_BYTE
  const normalize2 = false;//不需要歸一化資料
  const stride2 = 0;//每次迭代前進大小* sizeof(型別)以獲得下一個位置
  const offset2 = 0;//從緩衝起始位置開始讀取
  //到指定的緩衝區取出資料
  gl.vertexAttribPointer(colorAttributeLocation, size2, type2, normalize2, stride2, offset2);

更多的細節請讀者自行看程式碼,裡面有詳細的註釋。這裡有一個問題,我們要畫矩形和幹嘛,有什麼用?這裡筆者想到了一個比較有趣的應用,利用三角形和矩形構建中文簡體字,下一節將帶領大家實現這個騷操作,敬請期待!