WebGL编程指南案例解析之多数据存储于一个缓冲区以及着色器通信

//顶点着色器往片元着色器传值
//多个参数值存于一个缓冲对象中


var vShader = `
    attribute vec4 a_Position;
    attribute float a_PointSize;
    attribute vec4 a_Color;
    varying vec4 v_Color;
    void main(){
        gl_Position = a_Position;
        gl_PointSize = a_PointSize;
        v_Color = a_Color;
    }
`;

var fShader = `
//设定默认精度
    precision mediump float;
    varying vec4 v_Color;
    void main(){
        gl_FragColor = v_Color;
    }
`;



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;
    }

    //用指定颜色填充webgl容器,就是设置背景
    gl.clearColor(0.4, 0.5, 0.0, 1.0);
    gl.clear(gl.COLOR_BUFFER_BIT);



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



    function initVertexBuffers(gl){
        var verticesSizes =  new Float32Array([
            0.0,0.5,10.0,1.0,0.0,0.0,
            -0.5,-0.5,20.0,0.0,1.0,0.0,
            0.5,-0.5,30.0,0.0,0.0,1.0
        ]);
        var n = 3;//点的个数

        //创建缓冲区对象
        var vertexSizeBuffer = gl.createBuffer();
        if(!vertexSizeBuffer){
            console.log('Failed to create the buffer object!');
            return -1;
        }

        //将缓冲区对象绑定到目标ARRAY_BUFFER
        gl.bindBuffer(gl.ARRAY_BUFFER,vertexSizeBuffer);
        //往ARRAY_BUFFER
        gl.bufferData(gl.ARRAY_BUFFER,verticesSizes,gl.STATIC_DRAW);


        var fsize = verticesSizes.BYTES_PER_ELEMENT;
        console.log(fsize);




        //获取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 * 6,0);
        //开启着色器对缓冲区数据的访问
        gl.enableVertexAttribArray(a_Position);

        var a_PointSize = gl.getAttribLocation(gl.program,'a_PointSize');
        if (a_PointSize < 0) {
            console.log('Failed to get the storage location of a_Position');
            return -1;
        }
        //将缓冲区对象分配给a_PointSize变量
        //这里的3表示每个顶点数据由3个float组成,所以两个点之间的字节量为fsize*3
        //偏移量为fsize*2,1表示只取1个数据
        //比如下面的数据表示从一个顶点中(0.0,0.5,10.0)顶点数据量为单个数据量字节长*3
        //从第fsize*2个字节开始取数据,取1个数据(数据长度为fsize)
        gl.vertexAttribPointer(a_PointSize,1,gl.FLOAT,false,fsize * 6,fsize * 2);
        //开启着色器对缓冲区数据的访问
        gl.enableVertexAttribArray(a_PointSize);

        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变量
        //这里的3表示每个顶点数据由3个float组成,所以两个点之间的字节量为fsize*3
        //偏移量为fsize*2,1表示只取1个数据
        //比如下面的数据表示从一个顶点中(0.0,0.5,10.0)顶点数据量为单个数据量字节长*3
        //从第fsize*2个字节开始取数据,取1个数据(数据长度为fsize)
        gl.vertexAttribPointer(a_Color,3,gl.FLOAT,false,fsize * 6,fsize * 3);
        //开启着色器对缓冲区数据的访问
        gl.enableVertexAttribArray(a_Color);

        return n;
    }
}


main();

注意:

①首先顶点着色器接收三个外来数据,position、size、color(我们最终画一个三角形,所以这里的size其实是没用上的);

②我们将三个数据拼在一起作为一条数据,所以每6个数值为一个顶点携带的数据,所以我们每次读取6 * size 个字节;

③对于这6 * size个字节,根据(偏移量,数据长度)来为三个属性取值定位:

  a_Position:(size * 0 , 2);

  a_PointSize:(size * 2 , 1);

  a_Color:(size * 3 , 3)

④对于 varying vec4 v_Color 我们看到,两个着色器中都会有,在顶点着色器中该变量在main()方法中赋值之后,用于输出

输出给谁用?当然是片元着色器咯,所以在片元着色器中该变量用于接收属性值。

有一点需要注意,用于两种着色器自定义数据通信的变量,类型和名称都必须一样。

猜你喜欢

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