WebGL笔记:WebGL的基本绘图原理

同步与异步绘图

  • 如果想要画出多个点,而不是每次点击只生成一个点,这时候就需要保存点击的痕迹
  • 但是如果代码中,有异步去绘制webgl的点,则会出现问题,如下关键代码
// 修改attribute 变量
gl.vertexAttrib2f(a_Position, -0.3, 0);
// 绘制顶点
gl.drawArrays(gl.POINTS, 0, 1);

// 修改attribute 变量
gl.vertexAttrib2f(a_Position, 0.3, 0);
// 绘制顶点
gl.drawArrays(gl.POINTS, 0, 1);

setTimeout(() => {
  //修改attribute 变量
  gl.vertexAttrib2f(a_Position, 0, 0);
  //绘制顶点
  gl.drawArrays(gl.POINTS, 0, 1);
}, 1000);
  • 这里同步代码中有两次drawArrays,异步代码中有一次drawArrays
  • 异步的代码会取代同步的代码,最终只会有一个点,如果移除setTimeout异步代码,则就是正常的两个点

异步绘图导致同步绘图数据丢失与解决方案

  • webgl的同步绘图的现象,其实是由webgl底层内置的颜色缓冲区导致的,这个颜色缓冲区它在电脑里会占用一块内存
  • 在使用webgl绘图的时候,是先在颜色缓冲区中画出来,这样的图像还在胸中,所以外人看不见,只有webgl系统自己知道
  • 在我们想要将图像显示出来的时候,那就照着颜色缓冲区中的图像去画,这个步骤是webgl 内部自动完成的,我们只要执行绘图命令即可
  • 颜色缓冲区中存储的图像,只在当前线程有效,我们先在js 主线程中绘图,主线程结束后,会再去执行信息队列里的异步线程
  • 在执行异步线程时,颜色缓冲区就会被webgl系统重置,之前的图像也就没了

解决方案

  • 将数据存储在一起,画图的时候,重新绘制即可,也就是用个数组就能解决问题
<canvas id="canvas">canvas>


<script id="vertexShader" type="x-shader/x-vertex">
    attribute vec4 a_Position;
    void main() {
        // 点位
        gl_Position = a_Position;
        // 尺寸
        gl_PointSize = 50.0;
    }
script>


<script id="fragmentShader" type="x-shader/x-fragment">
    void main() {
        gl_FragColor = vec4(1,1,0,1);
    }
script>

<script type="module">
  import { initShaders } from "./utils.js";

  const canvas = document.querySelector("#canvas");
  canvas.width = 200;
  canvas.height = 200;

  // 获取着色器文本
  const vsSource = document.querySelector("#vertexShader").innerText;
  const fsSource = document.querySelector("#fragmentShader").innerText;

  // 三维画笔
  const gl = canvas.getContext("webgl");

  // 初始化着色器
  initShaders(gl, vsSource, fsSource);

  // 设置attribute 变量
  const a_Position = gl.getAttribLocation(gl.program, "a_Position");

  // 声明颜色 rgba
  gl.clearColor(0, 0, 0, 1);
  // 刷底色
  gl.clear(gl.COLOR_BUFFER_BIT);

  // 存储顶点数据的数组
  const a_points = [
    { x: -0.3, y: 0 },
    { x: 0.3, y: 0 },
  ];

  render();

  setTimeout(() => {
    //修改attribute 变量
    // gl.vertexAttrib2f(a_Position, 0, 0);
    //绘制顶点
    // gl.drawArrays(gl.POINTS, 0, 1);
    a_points.push({ x: 0, y: 0 });
    render();
  }, 1000);

  // 渲染方法
  function render() {
    gl.clear(gl.COLOR_BUFFER_BIT);
    a_points.forEach(({ x, y }) => {
      gl.vertexAttrib2f(a_Position, x, y);
      gl.drawArrays(gl.POINTS, 0, 1);
    });
  }
script>

utils.js

export function initShaders(gl, vsSource, fsSource) {
  // 创建程序对象
  const program = gl.createProgram();
  // 建立着色对象
  const vertexShader = loadShader(gl, gl.VERTEX_SHADER, vsSource);
  const fragmentShader = loadShader(gl, gl.FRAGMENT_SHADER, fsSource);
  // 把顶点着色对象装进程序对象中
  gl.attachShader(program, vertexShader);
  // 把片元着色对象装进程序对象中
  gl.attachShader(program, fragmentShader);
  // 连接webgl上下文对象和程序对象
  gl.linkProgram(program);
  // 启动程序对象
  gl.useProgram(program);
  // 将程序对象挂到上下文对象上
  gl.program = program;
  return true;
}

function loadShader(gl, type, source) {
  // 根据着色类型,建立着色器对象
  const shader = gl.createShader(type);
  // 将着色器源文件传入着色器对象中
  gl.shaderSource(shader, source);
  // 编译着色器对象
  gl.compileShader(shader);
  // 返回着色器对象
  return shader;
}

你可能感兴趣的:(Canvas,Webgl,Three.js,webgl)