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的幂次方问题相关配置,文中也已经给出

猜你喜欢

转载自www.cnblogs.com/eco-just/p/10680575.html