1. 程式人生 > >WebGL編程指南案例解析之加載紋理(貼圖)

WebGL編程指南案例解析之加載紋理(貼圖)

res 片元 .text nload urn tex onload 不同 active

var vShader = `
    attribute vec4 a_Position;
    attribute vec2 a_TexCoord;
    varying vec2 v_TexCoord;
    void main(){
        gl_Position = a_Position;
        v_TexCoord = a_TexCoord;
    }
`;

var fShader = `
    //設定默認精度
    #ifdef GL_ES
    precision mediump float;
    #endif
uniform sampler2D u_Sampler; varying vec2 v_TexCoord; void main(){ gl_FragColor = texture2D(u_Sampler,v_TexCoord); } `; 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,fShader)){ console.log(Failed to initialize shaders.); return; } var n = initVertexBuffers(gl); if(n < 0){ console.log(
Failed to set the positions of the vertices!); return; } if(!initTextures(gl,n)){ console.log(Failed to initialize textures.); return; } //用指定顏色填充webgl容器,就是設置背景 gl.clearColor(0.4, 0.5, 0.0, 1.0); function initVertexBuffers(gl){ var verticesTex = 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 ]); var n = 4;//點的個數 //創建緩沖區對象 var vertexTexBuffer = gl.createBuffer(); if(!vertexTexBuffer){ console.log(Failed to create the buffer object!); return -1; } //將數據添加到緩沖區(綁定在緩沖區對象上) gl.bindBuffer(gl.ARRAY_BUFFER,vertexTexBuffer); gl.bufferData(gl.ARRAY_BUFFER,verticesTex,gl.STATIC_DRAW); var fsize = verticesTex.BYTES_PER_ELEMENT; //獲取shaderProgram中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,fsize * 4,0); gl.enableVertexAttribArray(a_Position); var a_TexCoord = gl.getAttribLocation(gl.program,a_TexCoord); if (a_TexCoord < 0) { console.log(Failed to get the storage location of a_TexCoord); return -1; } //將緩沖區對象分配給a_TexCoord變量並開啟訪問 gl.vertexAttribPointer(a_TexCoord,2,gl.FLOAT,false,fsize * 4,fsize * 2); gl.enableVertexAttribArray(a_TexCoord); return n; } //初始化紋理圖片,通過image傳入 function initTextures(){ //創建紋理對象 var texture = gl.createTexture(); //讀取u_Sampler存儲位置 var u_Sampler = gl.getUniformLocation(gl.program,u_Sampler); var image = new Image(); image.onload = function(){ loadTexture(gl,n,texture,u_Sampler,image); } image.src = ../image/demo.jpg; return true; } //加載紋理 function loadTexture(gl,n,texture,u_Sampler,image){ //對問題圖像進行y軸反轉 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL,1); //開啟0號紋理單元 gl.activeTexture(gl.TEXTURE0); //向target綁定紋理對象 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); //處理圖片像素非2的冪次方的配置 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); //配置紋理圖像 gl.texImage2D(gl.TEXTURE_2D,0,gl.RGB,gl.RGB,gl.UNSIGNED_BYTE,image); //將0號紋理傳遞給著色器 gl.uniform1i(u_Sampler,0); gl.clear(gl.COLOR_BUFFER_BIT); // Clear <canvas> gl.drawArrays(gl.TRIANGLE_STRIP, 0, n); } } main();

技術分享圖片

註意:

①每個頂點著色器數據(-0.5, 0.5, 0.0, 1.0)前兩個表示webgl的坐標系,後兩個表示紋理坐標系;

技術分享圖片

②頂點著色器需要傳入兩個參數數據源a_Position、a_TexCoord,分別代表webgl頂點坐標和紋理坐標;

③對於紋理坐標,無論是頂點坐標系輸入輸出(a_TexCoord,v_TexCoord)還是片元著色器用於輸入的v_TexCoord類型都是vec2,是二維的,別搞錯了

④對於片元著色器uniform sampler2D u_Sampler;該變量的數據傳遞和以往不同,將紋理全部處理完畢之後,通過如下方法傳遞該紋理到片元著色器

gl.uniform1i(u_Sampler,0);

⑤因為加載紋理可能是異步的,所以渲染方法必須在加載紋理結束(配置完紋理並數據傳遞完畢)之後

//將0號紋理傳遞給著色器
        gl.uniform1i(u_Sampler,0);

        gl.clear(gl.COLOR_BUFFER_BIT);   // Clear <canvas>

        gl.drawArrays(gl.TRIANGLE_STRIP, 0, n); 

⑥圖片尺寸非2的冪次方問題相關配置,文中也已經給出

WebGL編程指南案例解析之加載紋理(貼圖)