WebGL——绘制点

227 阅读2分钟

WebGL 绘制点流程

  1. 初始化webgl
  2. 初始化着色器shader
  3. 处理数据,将数据带入着色器
  4. 绘制

初始化webgl

let webgl;

const glDiv = document.getElementById("webgl");

// 获取webgl上下文
webgl = glDiv.getContext("webgl");

// 定义webgl可视域范围
webgl.viewport(0, 0, glDiv.clientWidth, glDiv.clientHeight);

初始化shader

// 顶点着色器代码 attribute接收位置参数 uniform接收映射矩阵
const vertexString = `
  attribute vec4 a_position;
  void main(void){
    gl_Position = a_position;
    gl_PointSize = 60.0;
  }
`;

// 片元着色器代码
const fragmentString = `
  void main(void){
    gl_FragColor = vec4(0.0, 0.0, 1.0, 1.0);
  }
`;


// 创建顶点着色器  片元着色器
const vsShader = webgl.createShader(webgl.VERTEX_SHADER);
const fsShader = webgl.createShader(webgl.FRAGMENT_SHADER);

// 设置着色器代码源
webgl.shaderSource(vsShader, vertexString);
webgl.shaderSource(fsShader, fragmentString);

// 编译着色器代码
webgl.compileShader(vsShader);
webgl.compileShader(fsShader);

// 创建webgl容器 (项目)
const program = webgl.createProgram();

// 绑定项目和着色器
webgl.attachShader(program, vsShader);
webgl.attachShader(program, fsShader);

// 链接webgl和项目
webgl.linkProgram(program);

// 使用项目
webgl.useProgram(program);

// 储存项目 方便后面使用
webgl.program = program;

着色器变量赋值(传参,数据处理)

// 定义浮点 坐标数组
const pointPosition = new Float32Array([0.5, 0.5, 0.0, 1.0]);

// 获取a_position变量 attribute
const aPosition = webgl.getAttribLocation(webgl.program, "a_position");

// a_position变量赋值
webgl.vertexAttrib4fv(aPosition, pointPosition);

绘制点

// 重置背景颜色
webgl.clearColor(0.0, 0.0, 0.0, 1.0);

// 清除颜色缓冲区
webgl.clear(webgl.COLOR_BUFFER_BIT | webgl.DEPTH_BUFFER_BIT);

// 绘制  类型,数组起始位置,绘制个数
webgl.drawArrays(webgl.POINTS, 0, 1);

扩展1:绑定鼠标事件动态绘制

webgl初始化和着色器初始化保持不变,数据缓冲区代码发生改变


// 绘制点坐标数组
const points = [];

// 获取a_position变量 attribute
const aPosition = webgl.getAttribLocation(webgl.program, "a_position");

const glDiv = document.getElementById("webgl");
glDiv.addEventListener("click", e => {
  const x = e.offsetX; // 距离画布横向距离
  const y = e.offsetY; // 距离画布纵向距离
  const x_size = e.target.clientWidth / 2; // gl坐标系x轴长度
  const y_size = e.target.clientHeight / 2; // gl坐标系y轴长度

  const gl_x = (x - x_size) / x_size;
  const gl_y = (y_size - y) / y_size;

  points.push(gl_x); // x轴坐标
  points.push(gl_y); // y轴坐标
  points.push(0); // z轴坐标
  points.push(1); // 齐次坐标

  // 定义浮点数组
  const pointPosition = new Float32Array(points);

  // 创建缓冲区对象
  const pointBuffer = webgl.createBuffer();

  // 将缓冲区绑定到webgl.ARRAY_BUFFER目标上  webgl.ARRAY_BUFFER表示缓冲区对象中包含了顶点的数据
  webgl.bindBuffer(webgl.ARRAY_BUFFER, pointBuffer);

  // 向缓冲区写入数据(不能直接向缓冲区写入数据,只能向“目标”写入数据,所以第一个参数是webgl.ARRAY_BUFFER,所以如果要向缓冲区写入数据 必须先绑定目标
  // 第三个参数标识如何使用数据
  // 1.gl.STATIC_DRAW   只写入一次数据,但需要绘制很多次
  // 2.gl.STREAM_DRAW   只写入一次数据,然后绘制若干次
  // 3.gl.DYNAMTC_DRAW  会写入多次数据,并绘制很多次
  webgl.bufferData(
    webgl.ARRAY_BUFFER, // buffer类型
    pointPosition, // 数据
    webgl.STATIC_DRAW // 静态数据
  );

  // 将缓冲区对象分配给aPosition
  webgl.vertexAttribPointer(
    aPosition, // 变量名
    4, // 一个点需要4个数据
    webgl.FLOAT, // 浮点类型
    false, // 是否转置
    4 * 4, // 一个点需要4个数据 * 4个字节
    0 * 4 // 从第几个偏移算起 0 * 4个字节
  );
  
  // 链接aPosition变量与分配给他的缓冲区对象 (开启,使得这次分配真正有效)
  webgl.enableVertexAttribArray(aPosition);

  // 重置颜色
  webgl.clearColor(0.0, 0.0, 0.0, 1.0);

  // 清除颜色缓冲区
  webgl.clear(webgl.COLOR_BUFFER_BIT | webgl.DEPTH_BUFFER_BIT);

  // 绘制  类型,数组起始位置,绘制个数
  webgl.drawArrays(webgl.POINTS, 0, points.length / 4);
});