《WebGL編程指南》學(xué)習(xí)筆記22——在矩形表面貼上兩個圖片-使用多幅紋理

本系列僅作為本人學(xué)習(xí)《WebGL編程指南》這本書的筆記所用

紋理圖像的加載是異步的,無法確定哪個圖像先加載完成,所以使用g_texUnit0和g_texUnit1來判斷是否加載完成,加載完成后才開始繪圖


image.jpeg

image.jpeg

image.jpeg
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>20矩形貼兩張圖片-使用多幅紋理</title>

    <script src="./lib/cuon-matrix.js"></script>
    <script src="./lib/cuon-utils.js"></script>
    <script src="./lib/webgl-debug.js"></script>
    <script src="./lib/webgl-utils.js"></script>
  </head>
  <body onload="main()">
    <canvas id="webgl" width="400" height="400">
      不支持canvas的瀏覽器會展示這段文字
    </canvas>

    <script>
      // 頂點著色器程序
      let VSHADER_SOURCE = `
        attribute vec4 a_Position;
        attribute vec2 a_TexCoord;
        varying vec2 v_TexCoord;
        void main() {
          gl_Position = a_Position;
          v_TexCoord = a_TexCoord;
        }
      `;
      // ============================??
      // 片元著色器程序
      let FSHADER_SOURCE = `
        precision mediump float; // 精度限定詞-來指定變量的范圍和精度,這里是中等精度
        uniform sampler2D u_Sampler0;
        uniform sampler2D u_Sampler1;
        varying vec2 v_TexCoord;
        void main() {
          vec4 color0 = texture2D(u_Sampler0, v_TexCoord); // 一張圖
          vec4 color1 = texture2D(u_Sampler1, v_TexCoord); // 兩張圖
          gl_FragColor = color0 * color1; // 兩張圖合并
        }
      `;
      // ==============================??
      // 主程序
      function main() {
        let canvas = document.getElementById("webgl");
        // 獲取WebGL繪圖上下文
        let gl = getWebGLContext(canvas);
        if (!gl) {
          console.error("無法使用WebGL");
          return;
        }
        // 初始化著色器
        if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
          console.error("無法使用著色器");
          return;
        }
        // 設(shè)置頂點坐標(biāo)
        let n = initVertexBuffers(gl);
        if (n < 0) {
          console.log("無法設(shè)置點的位置");
          return;
        }
        gl.clearColor(0.0, 0.0, 0.0, 1.0);
        // 配置紋理
        if (!initTextures(gl, n)) {
          console.log('無法配置紋理');
          return;
        }
      }
      function initVertexBuffers(gl) {
        // 定義頂點坐標(biāo)和紋理坐標(biāo)
        let verticesTexCoords = new Float32Array([
          -0.5, 0.5, 0.0, 1.0,
          -0.5, -0.5, 0.0, 0.0,
          0.5, 0.5, 1.0, 1.0,
          0.5, -0.5, 1.0, 0.0,
        ]); 
      
        let n = 4; // 頂點數(shù)量
        // 1.創(chuàng)建緩沖區(qū)對象
        let vertexTexCoordBuffer = gl.createBuffer();
        if (!vertexTexCoordBuffer) {
          console.log("不能創(chuàng)建緩沖區(qū)對象");
          return -1;
        }
        // 2.將緩沖區(qū)對象綁定到目標(biāo)
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexTexCoordBuffer);
        // 3.向緩沖區(qū)對象寫入數(shù)據(jù),不能直接向緩沖區(qū)寫入數(shù)據(jù),只能向綁定的目標(biāo)輸入數(shù)據(jù)
        gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW);
        let FSIZE = verticesTexCoords.BYTES_PER_ELEMENT;
        // 獲取a_Position、a_TexCoord變量的存儲位置,分配緩沖區(qū)并開啟
        let a_Position = gl.getAttribLocation(gl.program, 'a_Position');
        if (a_Position < 0) {
          console.log("無法獲取 a_Position");
          return -1;
        }
        // 參數(shù)1:類型。 參數(shù)2:占幾個元素。 參數(shù)3:單位類型。 參數(shù)4:固定。 參數(shù)5:5個元素代表1個點。 參數(shù)6:間隔2個元素開始算
        gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 4, 0);
        gl.enableVertexAttribArray(a_Position);
        let a_TexCoord = gl.getAttribLocation(gl.program, 'a_TexCoord');
        if (a_TexCoord < 0) {
          console.log('無法獲取 a_TexCoord');
          return -1;
        }
        gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2);
        gl.enableVertexAttribArray(a_TexCoord);
        return n;
      }
      // ==============================??
      // 兩個紋理
      function initTextures(gl, n) {
        // 創(chuàng)建兩個紋理對象
        let texture0 = gl.createTexture();
        let texture1 = gl.createTexture();
        if (!texture0 || !texture1) {
          console.log('無法創(chuàng)建紋理對象');
          return false;
        }
        // 獲取u_Sampler0和u_Sampler1的存儲位置
        let u_Sampler0 = gl.getUniformLocation(gl.program, 'u_Sampler0');
        let u_Sampler1 = gl.getUniformLocation(gl.program, 'u_Sampler1');
        if (!u_Sampler0 || !u_Sampler1) {
          console.log('無法獲取u_Sampler0或u_Sampler1');
          return false;
        }
        // 創(chuàng)建兩個image對象
        let image0 = new Image();
        let image1 = new Image();
        if (!image0 || !image1) {
          console.log('無法創(chuàng)建image對象');
          return false;
        }
        // 注冊圖像加載事件的兩個響應(yīng)函數(shù)
        image0.onload = function(){ loadTexture(gl, n, texture0, u_Sampler0, image0, 0); };
        image1.onload = function(){ loadTexture(gl, n, texture1, u_Sampler1, image1, 1); };
        // 瀏覽器開始加載兩個圖像
        image0.src = './sky.jpg';
        image1.src = './circle.gif';
        return true;
      }
      // ==============================??
      // 標(biāo)記紋理單元是否已經(jīng)就緒
      let g_texUnit0 = false;
      let g_texUnit1 = false;
      // ==============================??

      // ==============================??
      // 響應(yīng)函數(shù)
      function loadTexture(gl, n, texture, u_Sampler, image, texUnit) {
        // 對紋理圖像進行y軸反轉(zhuǎn)
        gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1);
        // 激活紋理
        if (texUnit === 0) {
          gl.activeTexture(gl.TEXTURE0);
          g_texUnit0 = true;
        } else {
          gl.activeTexture(gl.TEXTURE1);
          g_texUnit1 = true;
        }
        // 綁定紋理對象到目標(biāo)上
        gl.bindTexture(gl.TEXTURE_2D, texture);
        // 配置紋理參數(shù)
        gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
        // 設(shè)置紋理圖像
        gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image);
        // 將紋理單元編號傳遞給取樣器 uniform1i不是uniformli
        gl.uniform1i(u_Sampler, texUnit);
        gl.clear(gl.COLOR_BUFFER_BIT);
        // 繪制一個矩形
        if (g_texUnit0 && g_texUnit1) {
          gl.drawArrays(gl.TRIANGLE_STRIP, 0, n);
        }
      }
      // ==============================??
    </script>
  </body>
</html>
image.jpeg

未完待續(xù)。。。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容