webGL入门-2

107 阅读4分钟

使用缓冲区绘制多个点

缓冲区对象是webG L系统中的一块内存区域,可以一次性地向缓冲区对象中填充大量点顶点数据,然后将这些数据保存在其中,供顶点着色器使用

  1. 创建顶点数据

    /* 
        类型化数组类型
        Float32Array: 32位浮点型数组
        Float64Array: 64位浮点型数组
        Int8Array: 8位整型数组
        Uint8Array: 8位无符号整型数组
        Uint8ClampedArray: 8位无符号整型固定数组
        Int16Array: 16位整型数组
        Uint16Array: 16位无符号整型数组
        Int32Array: 32位整型数组
        Uint32Array: 32位无符号整型数组
        */
    const points = new Float32Array([
      0.0, 0.5,
      -0.5, -0.5,
      0.5, -0.5
    ])
    
  2. 创建缓冲区对象

// 创建缓冲区对象
const buffer = gl.createBuffer()
  1. 绑定缓冲区对象

    // 将缓冲区对象绑定到目标
    // gl.ARRAY_BUFFER => 顶点缓冲区对象
    // gl.ELEMENT_ARRAY_BUFFER => 索引缓冲区对象
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
    
  2. 将数据写入缓冲区对象

    // 向缓冲区对象中写入数据 target data type
    // gl.STATIC_DRAW => 只写入一次数据,但需要绘制很多次
    // gl.STREAM_DRAW => 只写入一次数据,然后绘制若干次
    // gl.DYNAMIC_DRAW => 多次写入数据,然后绘制很多次
    gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW)
    
  3. 将缓冲区对象分配给一个attribute变量

    // 将缓冲区对象分配给 attribute 变量
    // gl.vertexAttribPointer(location, size, type, normalized, stride, offset) 
    // location => 指定待分配 attribute 变量的存储位置
    // size => 指定缓冲区中每个顶点的分量个数,1-4
    // type => 指定数据格式
    // normalized => 是否将非浮点型的数据归一化到[0, 1]或[-1, 1]区间
    // stride => 指定相邻两个顶点间的字节数,默认为0
    // offset => 指定缓冲区对象中的偏移量(以字节为单位)
    gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, 0, 0)
    

    实现流程

image-20230810110247743.png

  1. 开启attribute变量

    // 连接 a_Position 变量与分配给它的缓冲区对象
    gl.enableVertexAttribArray(a_Position)
    // gl.disableVertexAttribArray(a_Position) // 禁用缓冲区对象
    

数据偏移

image-20230810115153071.png

// 获取 attribute 变量的存储位置
const a_Position = gl.getAttribLocation(program, 'a_Position')
const a_PointSize = gl.getAttribLocation(program, 'a_PointSize')
const points = new Float32Array([
  0.0, 0.5, 10.0,
  -0.5, -0.5, 20.0,
  0.5, -0.5, 30.0
])
// 创建缓冲区对象
const buffer = gl.createBuffer()
gl.bindBuffer(gl.ARRAY_BUFFER, buffer)
gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW)
const FSIZE = points.BYTES_PER_ELEMENT // 一个类型化数组中的元素所占的字节数
gl.vertexAttribPointer(a_Position, 2, gl.FLOAT, false, FSIZE * 3, 0)
gl.enableVertexAttribArray(a_Position)
​
​
gl.vertexAttribPointer(a_PointSize, 1, gl.FLOAT, false, FSIZE * 3, FSIZE * 2)
gl.enableVertexAttribArray(a_PointSize)

多图形绘制

// gl.drawArrays(gl.LINES, 0, 3) // 奇数个顶点,会自动忽略最后一个顶点
// gl.drawArrays(gl.LINE_STRIP, 0, 3) // 绘制连续线段
// gl.drawArrays(gl.LINE_LOOP, 0, 3) // 绘制连续线段,闭合
// gl.drawArrays(gl.TRIANGLES, 0, 6) // 绘制三角形,顶点时3点倍数
// gl.drawArrays(gl.TRIANGLE_FAN, 0, 4) // 绘制飘带状三角形
//gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4) // 绘制条带状三角带

图形平移-着色器

// 顶点着色器
const VERTEX_SHADER = `
    // attribute 变量 => 只传递顶点数据,默认值为 vec4(1.0, 0.0, 0.0, 1.0)
    attribute vec4 a_Position;
    attribute float a_PointSize;
    attribute float a_translate;
      void main() {
        // 设置坐标 x y z w(齐次坐标) => (x/w, y/w, z/w)
        gl_Position = vec4(a_Position.x + a_translate,a_Position.y,a_Position.z,1.0);
        gl_PointSize = a_PointSize;
      }
    `
// 获取 平移变量的存储位置
const a_translate = gl.getAttribLocation(program, 'a_translate')
// 。。。 启动缓冲区
let x = -1;
setInterval(() => {
  x += 0.01
  if (x > 1) {
    x = -1
  }
  gl.vertexAttrib1f(a_translate, x)
  gl.clear(gl.COLOR_BUFFER_BIT)
  gl.drawArrays(gl.TRIANGLES, 0, 3) 
}, 100)

图形缩放-着色器

在顶点着色器中使用缩放变量乘以对应顶点坐标

   // 顶点着色器
    const VERTEX_SHADER = `
    attribute vec4 a_Position;
    attribute float a_PointSize;
    attribute float a_scale;
      void main() {
        gl_Position = vec4(a_Position.x * a_scale ,a_Position.y,a_Position.z,1.0);
        gl_PointSize = a_PointSize;
      }
    `

图形旋转-着色器

// 顶点着色器
const VERTEX_SHADER = `
    attribute vec4 a_Position;
    attribute float a_PointSize;
    attribute float a_deg;
      void main() {
        gl_Position.x = a_Position.x * cos(a_deg) - a_Position.y *          sin(a_deg);
        gl_Position.y = a_Position.x * sin(a_deg) + a_Position.y *          cos(a_deg);
        gl_Position.z = a_Position.z;
        gl_Position.w = 1.0;
        gl_PointSize = a_PointSize;
      }
    `

图形平移-平移矩阵

矩阵:纵横排列的数据表格(m行n列)

类别:行主序,列主序

原理先挖坑,后续填上

// 顶点着色器
const VERTEX_SHADER = `
    attribute vec4 a_Position;
    attribute float a_PointSize;
    uniform mat4 u_Translate; //声明矩阵偏移变量
      void main() {
        gl_Position = u_Translate * a_Position;
      }
    `
// 获取 平移变量的存储位置
const u_Translate = gl.getUniformLocation(program, 'u_Translate')
// 创建矩阵函数
function getTranslateMatrix (x = 0, y = 0, z = 0) { //
  const matrix = new Float32Array([
    1.0, 0.0, 0.0, 0.0,
    0.0, 1.0, 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    x, y, z, 1.0,
  ])
  return matrix
}
// 使用
function animation () {
  x += 0.01
  if (x > 1) {
    x = -1
  }
  const matrix = getTranslateMatrix(x, x, 0)
  gl.uniformMatrix4fv(u_Translate, false, matrix) // 参数:指定uniform存储位置,是否转置,在webgl中恒为false,矩阵数组
  // gl.vertexAttrib1f(a_translate, x)
  gl.clear(gl.COLOR_BUFFER_BIT)
  gl.drawArrays(gl.TRIANGLES, 0, 3)
  requestAnimationFrame(animation)
}
animation()

图形缩放-缩放矩阵

// 创建矩阵函数
function getScaleMatrix (x = 1, y = 1, z = 1) { //
  const matrix = new Float32Array([
    x, 0.0, 0.0, 0.0,
    0.0, y, 0.0, 0.0,
    0.0, 0.0, z, 0.0,
    0.0, 0.0, 0.0, 1.0,
  ])
  return matrix
​
}

图形旋转-旋转矩阵

// 创建绕z轴旋转的矩阵函数
function getRotateMatrix (deg) { //
  const matrix = new Float32Array([
    Math.cos(deg), Math.sin(deg), 0.0, 0.0,
    -Math.sin(deg), Math.cos(deg), 0.0, 0.0,
    0.0, 0.0, 1.0, 0.0,
    0.0, 0.0, 0.0, 1.0,
  ])
  return matrix
​
}

复合矩阵

// 矩阵复合函数
function getMinMatrix(A, B) {
  const result = new Float32Array(16);
  for (let i = 0; i < 4; i++) {
    result[i] =
      A[i] * B[0] + A[i + 4] * B[1] + A[i + 8] * B[2] + A[i + 12] * B[3];
    result[i + 4] =
      A[i] * B[4] + A[i + 4] * B[5] + A[i + 8] * B[6] + A[i + 12] * B[7];
    result[i + 8] =
      A[i] * B[8] + A[i + 4] * B[9] + A[i + 8] * B[10] + A[i + 12] * B[11];
    result[i + 12] =
      A[i] * B[12] + A[i + 4] * B[13] + A[i + 8] * B[14] + A[i + 12] * B[15];
  }
  return result;
}
​