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


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的冪次方問題相關配置,文中也已經給出


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM