<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      WebGL簡易教程(四):顏色

      1. 概述

      在上一篇教程《WebGL簡易教程(三):繪制一個三角形(緩沖區對象)》中,通過使用緩沖區對象(buffer object)來向頂點著色器傳送數據。那么,如果這些數據(與頂點相關的數據,如法向量、顏色等)需要繼續傳送到片元著色器該怎么辦呢?

      例如這里給三角形的每個頂點賦予不同的顏色,繪制一個彩色的三角形。這個時候就需要用到之前(《WebGL簡易教程(二):向著色器傳輸數據》)介紹過的varying變量了。

      2. 示例:繪制三角形

      改進上一篇中繪制三角形(HelloTriangle.js)的代碼:

      // 頂點著色器程序
      var VSHADER_SOURCE =
        'attribute vec4 a_Position;\n' + // attribute variable
        'attribute vec4 a_Color;\n' +
        'varying vec4 v_Color;\n' +
        'void main() {\n' +
        '  gl_Position = a_Position;\n' + // Set the vertex coordinates of the point
        '  v_Color = a_Color;\n' +
        '}\n';
      
      // 片元著色器程序
      var FSHADER_SOURCE = 
        'precision mediump float;\n' +
        'varying vec4 v_Color;\n' +
        'void main() {\n' +
        '  gl_FragColor = v_Color;\n' +
        '}\n';
      
      function main() {
        // 獲取 <canvas> 元素
        var canvas = document.getElementById('webgl');
      
        // 獲取WebGL渲染上下文
        var gl = getWebGLContext(canvas);
        if (!gl) {
          console.log('Failed to get the rendering context for WebGL');
          return;
        }
      
        // 初始化著色器
        if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) {
          console.log('Failed to intialize shaders.');
          return;
        }
      
        // 設置頂點位置
        var n = initVertexBuffers(gl);
        if (n < 0) {
          console.log('Failed to set the positions of the vertices');
          return;
        }
      
        // 指定清空<canvas>的顏色
        gl.clearColor(0.0, 0.0, 0.0, 1.0);
      
        // 清空<canvas>
        gl.clear(gl.COLOR_BUFFER_BIT);
      
        // 繪制三角形
        gl.drawArrays(gl.TRIANGLES, 0, n);
      }
      
      function initVertexBuffers(gl) {
        // 頂點坐標和顏色
        var verticesColors = new Float32Array([    
           0.0,  0.5,  1.0,  0.0,  0.0, 
          -0.5, -0.5,  0.0,  1.0,  0.0, 
           0.5, -0.5,  0.0,  0.0,  1.0, 
        ]);
      
        //
        var n = 3; // 點的個數
        var FSIZE = verticesColors.BYTES_PER_ELEMENT;   //數組中每個元素的字節數
      
        // 創建緩沖區對象
        var vertexBuffer = gl.createBuffer();
        if (!vertexBuffer) {
          console.log('Failed to create the buffer object');
          return -1;
        }
      
        // 將緩沖區對象綁定到目標
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
        // 向緩沖區對象寫入數據
        gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
      
        //獲取著色器中attribute變量a_Position的地址 
        var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
        if (a_Position < 0) {
          console.log('Failed to get the storage location of a_Position');
          return -1;
        }
        // 將緩沖區對象分配給a_Position變量
        gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 5*FSIZE, 0);
      
        // 連接a_Position變量與分配給它的緩沖區對象
        gl.enableVertexAttribArray(a_Position);
      
        //獲取著色器中attribute變量a_Color的地址 
        var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
        if(a_Color < 0) {
          console.log('Failed to get the storage location of a_Color');
          return -1;
        }
        // 將緩沖區對象分配給a_Color變量
        gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 5, FSIZE * 2);
        // 連接a_Color變量與分配給它的緩沖區對象
        gl.enableVertexAttribArray(a_Color);  
      
        // 解除綁定
        gl.bindBuffer(gl.ARRAY_BUFFER, null);
      
        return n;
      }
      

      1) 數據的組織

      與之前的例子相似,數據仍然通過緩沖區傳遞到頂點著色器。在頂點著色器中,定義了兩個attribute變量,分別代表位置和顏色信息:

      // 頂點著色器程序
      var VSHADER_SOURCE =
        'attribute vec4 a_Position;\n' + // attribute variable
        'attribute vec4 a_Color;\n' +
      …
        '}\n';
      

      這意味著需要向頂點著色器傳遞兩次數據。這里采取的做法仍然是一次性向緩沖區寫入位置和顏色等所有的數據,然后分批次傳入頂點著色器:

        // 創建緩沖區對象
        var vertexBuffer = gl.createBuffer();
        if (!vertexBuffer) {
          console.log('Failed to create the buffer object');
          return -1;
        }
      
      // 將緩沖區對象綁定到目標
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
        // 向緩沖區對象寫入數據
        gl.bufferData(gl.ARRAY_BUFFER, verticesColors, gl.STATIC_DRAW);
      
        //獲取著色器中attribute變量a_Position的地址 
        var a_Position = gl.getAttribLocation(gl.program, 'a_Position');
        if (a_Position < 0) {
          console.log('Failed to get the storage location of a_Position');
          return -1;
        }
        // 將緩沖區對象分配給a_Position變量
        gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 5*FSIZE, 0);
      
        // 連接a_Position變量與分配給它的緩沖區對象
        gl.enableVertexAttribArray(a_Position);
      
        //獲取著色器中attribute變量a_Color的地址 
        var a_Color = gl.getAttribLocation(gl.program, 'a_Color');
        if(a_Color < 0) {
          console.log('Failed to get the storage location of a_Color');
          return -1;
        }
        // 將緩沖區對象分配給a_Color變量
        gl.vertexAttribPointer(a_Color, 3, gl.FLOAT, false, FSIZE * 5, FSIZE * 2);
        // 連接a_Color變量與分配給它的緩沖區對象
        gl.enableVertexAttribArray(a_Color);  
      

      可以看到創建緩沖區對象、將緩沖區對象綁定到目標、向緩沖區對象寫入數據這三個步驟都是一致的。但分配attribute變量和連接attribute變量這兩個步驟分別進行了兩次。其中的關鍵點就在于gl.vertexAttribPointer()這個函數。之前使用這個函數都是使用的默認值,這里通過設置步進和偏移值,分別訪問了緩沖區中不同的數據。

      通過gl.vertexAttribPointer()函數定義可以知道,傳送到緩沖區的數據是2(size)的位置數據和3(size)的顏色數據,所以步進參數stride都是5(size)。第一次傳送位置數據的時候是從初始位置開始的,所以offset是0;而第二次傳送顏色數據的時候需要偏移第一個位置數據,所以offfset是2(size)。

      2) varying變量

      在之前的教程(《WebGL簡易教程(二):向著色器傳輸數據》)中提到,可以傳送數據給片元著色器,來給繪制場景賦予顏色。但是這里卻通過緩沖區把數據傳遞給了頂點著色器。因此,在這里給頂點著色器和片元著色器,分別定義了一個相同的varying變量:

      // 頂點著色器程序
      var VSHADER_SOURCE =
        …
        'varying vec4 v_Color;\n' +
        'void main() {\n' +
        …
        '  v_Color = a_Color;\n' +
        '}\n';
      
      // 片元著色器程序
      var FSHADER_SOURCE = 
        …
        'varying vec4 v_Color;\n' +
        'void main() {\n' +
        '  gl_FragColor = v_Color;\n' +
        '}\n';
      

      varying變量表達的正是一種可變的變量,它的作用就是從頂點著色器向片元著色器傳輸數據。在頂點著色器的main函數中,將從緩沖區對象中獲取的attribute變量a_Color賦值給預先定義的varying變量v_Color;同時在片元著色器中又定義了一個同類型同名的varying變量v_Color,那么頂點著色器中該變量的值就會自動傳入到片元著色器中。最后在片元著色器的main函數中將該值傳入到gl_FragColor中,就得到最終的結果了。其示意圖如下:

      3. 結果

      最后的運行結果如下,最后會發現得到了一個顏色平滑過渡的,三個角各是紅、綠、藍顏色的三角形:

      4. 理解

      1) 圖形裝配和光柵化

      更進一步思考下,這里雖然給每個頂點賦予的顏色值,但是為什么三角形的表面都賦予了顏色,并且是平滑過渡的效果呢?其實這里省略了頂點著色器與片元著色器之間數據傳輸細節——圖形裝配和光柵化。

      點組成線,線組成面,將孤立的點組成基本圖形(圖元)的過程就是圖形裝配。圖形裝配的輸入數據就是頂點著色器中gl_Position得到的值,由gl.drawArrays()中第一個參數值來確定裝配成什么樣的圖元。在這個例子中,頂點著色器告訴WebGL系統,準備了三個點,WebGL通過圖像裝配,將其裝配成三角形。

      知道裝配的圖形還是不夠的,理論上的三角形是連續不斷的圖形,而一般的圖形顯示設備都是離散的片元(像素)。圖像轉換成片元,就是光柵化的過程。

      圖形裝配和光柵化的示意圖如下:

      2) 內插過程

      在第二節詳解示例中的代碼時,提到了頂點著色器和片元著色都定義了相同的varying變量v_Color,數據就會從頂點著色器傳入到片元著色器。但其實兩者雖然同名,但并不是一回事。在頂點著色器中,這個varying變量是與頂點相關的值,而經過圖形裝配和光柵化后,片元著色器的varying變量就是與片元相關的值了。并且,這個值是經過內插過程得到的。

      在這個例子中,給三個頂點賦予了三個不同的顏色值。WebGL就根據三個頂點的顏色值內插了三角形中每個片元(像素)的顏色值,并傳遞給片元著色器。所謂內插過程,可以想象成一條漸變色帶,知道確定了起止顏色,就能獲取中間任意位置的顏色。

      5. 參考

      本來部分代碼和插圖來自《WebGL編程指南》。

      代碼和數據地址

      上一篇
      目錄
      下一篇

      posted @ 2019-09-14 17:46  charlee44  閱讀(2809)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 国产精品视频午夜福利| 久久99精品久久久久久9| 久久精品国产福利一区二区| 久久精品夜夜夜夜夜久久| 精品日韩人妻中文字幕| 亚洲一区av无码少妇电影| 国产高清视频一区二区三区| 国产一区在线观看不卡| 色综合久久一区二区三区| 日韩一区二区三区女优丝袜| 玩弄漂亮少妇高潮白浆| 尚义县| 丰满人妻熟妇乱精品视频| 国产不卡在线一区二区| 国产成人无码aa片免费看| 国产伦视频一区二区三区| 亚洲AV成人无码久久精品| 成人啪精品视频网站午夜| 亚洲精品一区二区三区蜜| 日本一区二区三区在线播放| 无码人妻久久一区二区三区app| 亚洲成人午夜排名成人午夜| 国产亚洲av手机在线观看| 麻豆久久久9性大片| 亚洲av成人一区在线| 中文字幕一区二区三区久久蜜桃 | 免费视频欧美无人区码| 亚洲 日韩 国产 制服 在线| 布拖县| 亚洲蜜臀av乱码久久| 国产亚洲精品在av| 公天天吃我奶躁我的在| 日日碰狠狠添天天爽不卡| 精精国产xxxx视频在线| 一区二区三区四区激情视频| 在线中文字幕国产一区| 青青青青久久精品国产| 成人午夜福利精品一区二区 | 免费国产又色又爽又黄的网站| 欧洲亚洲国内老熟女超碰| 国产乱子伦视频在线播放|