<tfoot id="ouu4w"><rt id="ouu4w"></rt></tfoot>
  • 
    
  • <bdo id="ouu4w"></bdo>
        <cite id="ouu4w"><table id="ouu4w"></table></cite>
      • 您當前的位置: 首頁-云計算-詳情

        一起學 WebGL:紋理對象學習 天天消息

        2023-06-26 16:11:32來源:前端西瓜哥

        大家好,我是前端西瓜哥,今天我們來了解 WebGL 的紋理對象(Texture)

        紋理對象,是將像素(texels)以數組方式傳給 GPU 的對象,常見場景是貼圖,就是將圖片的數據應用到 3D 物體上。

        紋理對象創建和綁定

        先創建紋理對象:


        (相關資料圖)

        const texture = gl.createTexture(); // 創建紋理對象

        然后綁定到紋理單元:

        gl.bindTexture(gl.TEXTURE_2D, texture); // 將紋理對象綁定上去
        填充方式

        紋理是要貼到畫布的某個區域上的,并不一定剛好設置一下填充方式。

        紋理比繪制區域大,就要做縮放;紋理比繪制區域小,就要做放大;紋理沒能完全填充繪制區域,就要在水平和垂直方向進行填充。

        這些場景都需要對應設置不同的策略。

        // 縮小和放大都都使用 “最近點采樣”gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
        紋理單元

        WebGL 支持設置多個紋理單元(Texture Unit),即我們可以將多個圖片放到多個單元中,然后進行切換。

        就好像手里拿著不同的蓋章,想印哪種圖案就掏出哪個蓋上去。

        紋理單元是有上限的,至少要支持 8 個,主流瀏覽器一般支持 16 個。

        具體支持幾個,可通過下面代碼獲得。

        gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS) // 通常是 16

        默認使用 0 號紋理單元,可通過下面這一行代碼來切換紋理單元:

        gl.activeTexture(gl.TEXTURE1); // 開啟 1 號紋理單元

        注意這個要在將紋理對象綁定紋理單元之前執行。

        最后我們需要設置一下我們的紋理采樣器選擇使用哪個紋理單元:

        gl.uniform1i(u_Sampler, 0); // 開啟 0 號紋理對象

        不主動調用這個方法,默認會使用 0 號紋理單元。

        切換紋理單元是有一定的性能代價的,不建議你在短時間內不斷地切換紋理單元。簡單的渲染場景可忽略不計。

        純色紋理

        畫個純純的紅色紋理。

        // 紅色const data = new Uint8Array([  255, 0, 0]);gl.texImage2D(  gl.TEXTURE_2D, // 紋理目標,這里是二維紋理  0, // 細節級別,0 表示最高級別  gl.RGB, // 紋理內部格式,還支持其他的比如 gl.RGBA、LUMINANCE(流明)  1, // 寬(寬高的單位為像素,且為 2 的 n 次冪)  1, // 高  0, // 是否描邊。必須為 0(但 opengl 支持)  gl.RGB, // 源圖像數據格式  gl.UNSIGNED_BYTE, // 紋素(單個像素)數據類型  data // 數據數組,一個個像素點);

        主要注意的是,gl.texImage2D()方法支持函數重載,有多種傳入的參數的方式,注意分辨。具體看 官方文檔。

        這里選擇使用 gl.RGB 格式,設置了一個(255, 0, 0)的紅色顏色值。

        最后我們成功畫出一個純紅色塊。

        完整代碼:

        /** @type {HTMLCanvasElement} */const canvas = document.querySelector("canvas");const gl = canvas.getContext("webgl");const vertexShaderSrc = `attribute vec4 a_Position;attribute vec2 a_TexCoord;varying vec2 v_TexCoord;void main() { gl_Position = a_Position; v_TexCoord = a_TexCoord;}`;const fragmentShaderSrc = `precision highp float;uniform sampler2D u_Sampler;varying vec2 v_TexCoord;void main() {  gl_FragColor = texture2D(u_Sampler, v_TexCoord);}`;// 創建程序對象createProgram(gl);// 頂點坐標,紋理坐標const verticesTexCoords = new Float32Array([  // 左上點。  // 左邊兩個是頂點;右邊兩個是紋理  -0.5, 0.5, 0.0, 1,  // 左下  -0.5, -0.5, 0.0, 0.0,  // 右上  0.5, 0.5, 1, 1,  // 右下  0.5, -0.5, 1, 0.0,]);const FSIZE = verticesTexCoords.BYTES_PER_ELEMENT;// 創建緩存對象const verticesTexBuffer = gl.createBuffer();// 綁定緩存對象到上下文gl.bindBuffer(gl.ARRAY_BUFFER, verticesTexBuffer);// 向緩存區寫入數據gl.bufferData(gl.ARRAY_BUFFER, verticesTexCoords, gl.STATIC_DRAW);// 獲取 a_Position 變量地址const a_Position = gl.getAttribLocation(gl.program, "a_Position");// 將緩沖區對象分配給 a_Position 變量gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 4, 0);// 允許訪問緩存區gl.enableVertexAttribArray(a_Position);// 傳入紋理坐標位置信息const a_TexCoord = gl.getAttribLocation(gl.program, "a_TexCoord");gl.vertexAttribPointer(a_TexCoord, 2, gl.FLOAT, false, FSIZE * 4, FSIZE * 2);gl.enableVertexAttribArray(a_TexCoord);/***** 紋理對象 *****/const texture = gl.createTexture(); // 創建紋理對象const u_Sampler = gl.getUniformLocation(gl.program, "u_Sampler"); // 獲取 u_Sampler 地址// 記載圖片gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); // 翻轉紋路圖像的 y 軸gl.activeTexture(gl.TEXTURE0); // 開啟 0 號紋理單元gl.bindTexture(gl.TEXTURE_2D, texture); // 將我們的紋理對象綁定上去// 配置紋理參數gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);// 【----關鍵代碼---】配置紋理圖像const data = new Uint8Array([255, 0, 0, 0, 255, 255, 0, 255, 0, 0, 255, 0]);gl.texImage2D(  gl.TEXTURE_2D, // 紋理目標  0, // 細節級別  gl.RGB, // 紋理內部格式  1,  1,  0,  gl.RGB, // 源圖像數據格式  gl.UNSIGNED_BYTE, // 紋素數據類型  data // 數據);gl.uniform1i(u_Sampler, 0); // 開啟 0 號紋理對象/****** 繪制 ******/// 清空畫布,并指定顏色gl.clearColor(0, 0, 0, 1);gl.clear(gl.COLOR_BUFFER_BIT);// 繪制矩形,這里提供了 4 個點gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);/**** 封裝的方法 ****/function createProgram(gl) {  /**** 渲染器生成處理 ****/  // 創建頂點渲染器  const vertexShader = gl.createShader(gl.VERTEX_SHADER);  gl.shaderSource(vertexShader, vertexShaderSrc);  gl.compileShader(vertexShader);  // 創建片元渲染器  const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);  gl.shaderSource(fragmentShader, fragmentShaderSrc);  gl.compileShader(fragmentShader);  // 程序對象  const program = gl.createProgram();  gl.attachShader(program, vertexShader);  gl.attachShader(program, fragmentShader);  gl.linkProgram(program);  gl.useProgram(program);  gl.program = program;}

        線上 demo:

        https://codesandbox.io/s/1hvp4x?file=/index.js。

        多個色塊紋理

        也可以同時設置多個色塊。

        const data = new Uint8Array([  255, 0, 0, 255,   // 紅色  255, 255, 0, 255, // 黃色  0, 0, 255, 255,  // 藍色  0, 255, 0, 255,  // 綠色]);gl.texImage2D(  gl.TEXTURE_2D, // 紋理目標  0, // 細節級別  gl.RGBA, // 紋理內部格式  2,  2,  0,  gl.RGBA, // 源圖像數據格式  gl.UNSIGNED_BYTE, // 紋素數據類型  data // 數據);

        創建了 2x2 4個像素大小的紋理,并制定了這個 4 個像素點的顏色,然后被放大繪制到指定區域上。

        線上演示 demo:

        https://codesandbox.io/s/7436cs?file=/index.js。

        圖片紋理

        圖片紋理,需要加載玩圖片,將圖片對象綁定到紋理對象上。

        // 將紋理圖像分配給紋理對象gl.texImage2D(  gl.TEXTURE_2D,  0, // 細節級別  gl.RGB,  gl.RGB,  gl.UNSIGNED_BYTE,  img // Image 實例);
        結尾

        紋理對象是很常用的一個對象,用于指定區域要填充的像素。

        常見的是加載圖片,把圖片貼到三維的一個面上。也可以自己指定像素值。

        標簽:

        上一篇:亞馬遜明年或超越沃爾瑪,成美國最大零售商!|天天快看點
        下一篇:最后一頁