WebGL学习笔记(二):利用缓冲区动态绘制多个点

上一个程序中,只实现了静态的单点绘制的,点的位置和颜色都是写死在着色器中的。如果想要动态的显示点,将交互添加进去,我们就需要实现使用 JavaScript 向着色器中传值,这就需要使用到缓冲区。在上一个程序基础上,实现点击时生成随机颜色点的效果。

一、修改着色器代码

我们需要将着色器中创建几个变量。着色器中一共有三种变量类型

  1. attribute: 只能在顶点着色器中声明和使用,常用来存放顶点坐标,顶点颜色,法线等。
  2. uniform: 既可以在顶点着色器中使用,也可以在片元着色器中使用,常用来存放变化矩阵,光照参数等。
  3. varying: 用于从顶点着色器向片元着色器中传递参数。
//顶点着色器源码
var vertexShaderSource = `
    //设置浮点数精度为中等精度
    precision mediump float;
    //接收点在 canvas 坐标系上的坐标 (x, y)
    attribute vec2 a_Position;
    //接收 canvas 的宽高尺寸
    attribute vec2 a_Screen_Size;
    //接收 JavaScript 颜色值
    attribute vec4 a_Color;
    //将颜色值转递给片元着色器
    varying vec4 v_Color;
    void main(){
        //将 canvas 坐标转换至裁剪坐标系
        vec2 position = (a_Position / a_Screen_Size) * 2.0 - 1.0; 
        position = position * vec2(1.0, -1.0);
        gl_Position = vec4(position, 0, 1);
        //将接收到颜色传给 v_Color,
        v_Color = a_Color;
        //声明要绘制的点的大小。
        gl_PointSize = 5.0;
    }
`

//片元着色器源码
var fragmentShaderSource = `
    //设置浮点数精度为中等精度
    precision mediump float;
    //接收顶点着色器中传来的颜色值
    varying vec4 v_Color;
    void main(){
        gl_FragColor = v_Color;
    }
`
二、JavaScript 操作着色器中的变量
  • getAttribLocation(program, name):从 WebGLProgram 中获取指定属性的索引
  • vertexAttrib[1234]f[v]:为 attribute 变量赋值。
  • uniform[1234][fi][v]:为 uniform 变量赋值。

我们需要将 canvas 的长宽信息传入着色器中,用于将 canvas 坐标转换为 WebGL 的裁剪坐标,在着色器中,我们定义了 a_Screen_Size 用与存放这个信息。在 JavaScript 中,我们首先获取到这个变量,再通过 vertexAttrib2f 为它赋值。

//从着色器程序中获取 a_Screen_Size 的索引
var a_Screen_Size = gl.getAttribLocation(program, 'a_Screen_Size');
//将画布的宽高传入 a_Screen_Size
gl.vertexAttrib2f(a_Screen_Size, canvas.width, canvas.height);
三、使用缓冲区为变量赋值

使用上面一种方法为变量赋值存在一个问题,不能同时传入多个值,比如画三角形时,需要多个点同时参与,这种方法就行不通了。我们这个程序只需要画点,不使用缓冲区也可以实现,但是每次画点都需要遍历一遍存放信息的数组,每次循环都需要在 JavaScript 中为着色器变量赋一次值,效率比较低。为了同时传入多个顶点值和提高效率,我们需要使用缓冲区。
使用缓冲区需要以下步骤:

  1. 创建缓冲区
    创建缓冲区的函数为 createBuffer(), 我们为位置信息和颜色信息都创建一个缓冲区。

    var postionBuffer = gl.createBuffer();
    var colorBuffer = gl.createBuffer();
    
  2. 获取并启用变量

    var a_Position = gl.getAttribLocation(program, 'a_Position');
    var a_Color = gl.getAttribLocation(program,'a_Color');
    gl.enableVertexAttribArray(a_Position);
    gl.enableVertexAttribArray(a_Color);
    
  3. 绑定缓冲区并设置变量从缓冲区获取数据的规则
    这一步主要涉及到两个函数,bindBuffer 和 vertexAttribPointer。bindBuffer 用于绑定缓冲区,即指定当前使用哪一个缓冲区。vertexAttribPointer 则用于设置从缓冲区读取数据的规则,同时,它将变量与当前缓冲区绑定起来了,这个方法有 6 个参数, 更详细的内容可以参考 MDN。

    1. index: 指定要修改的顶点属性的索引
    2. size: 指定每个顶点属性的组成数量, 如 a_Postion 需要两个属性(横纵坐标),a_Color 需要四个属性(RGBA)
    3. type: 指定每个顶点属性的数据类型, 如 a_Postion 和 a_Color 都是浮点数类型的,所以使用 gl.FLOAT
    4. normalized: 当转换为浮点数时是否应该将整数归一化到特定的范围
    5. stride: 以字节为单位指定脸书顶点属性开始之间的偏移量,我们数据是连续的,所以可以设置为 0
    6. offset: 指定顶点属性数组中第一部分的字节偏移量
    gl.bindBuffer(gl.ARRAY_BUFFER, postionBuffer);
    gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0);
    gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
    gl.vertexAttribPointer(a_Color, 4, gl.FLOAT, false, 0, 0);
    
  4. 向缓冲区中填入数据并重新渲染
    之前几步我们已经准备好了缓冲区,并将变量与缓冲区相关联,设置好了读取规则了,现在就需要准备缓冲区里的数据。
    首先,定义两个空的数组用于保存位置和颜色的信息

    //创建保存点位置的数组
    var position = [];
    //创建保存颜色信息的数组
    var color = [];
    

    我们再给 canvas 绑定一个点击事件

    canvas.onclick = function(e){
        //将坐标存入数组
        position.push(e.pageX, e.pageY);
        //将随机生成的颜色存入数组
        color.push(Math.random(), Math.random(), Math.random(), 0);
    
        //向 postionBuffer 缓冲区中写入数据
        gl.bindBuffer(gl.ARRAY_BUFFER, postionBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(position), gl.STATIC_DRAW);
    
        //向 colorBuffer 缓冲区中写入数据
        gl.bindBuffer(gl.ARRAY_BUFFER, colorBuffer);
        gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(color), gl.STATIC_DRAW);
    
        //清空画布
        gl.clear(gl.COLOR_BUFFER_BIT);
        //重绘画布上的点
        gl.drawArrays(gl.POINTS, 0, position.length/2);
    }
    

    当我们点击时,就会将点击位置加入 position 数组,同时生成一个随机的颜色存入 color 数组。之后,我们就将数组中的数组传入缓冲区中。通过 bindBuffer 选择一个缓冲区,再通过 bufferData 将数组传入当前缓冲区。缓冲区有了数据之后,我们再进行绘图,调用 drawArrays 方法,其中第三个参数为需要画的点的个数,开始绘图时,就会按照我们设置的规则依次从缓冲区中取点了。

四. 完整代码
```



```

你可能感兴趣的:(WebGL,js,WebGL,缓冲区)