• 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);
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
    • 这里同步代码中有两次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(() => {
          // 数据同步
          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>
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
      • 30
      • 31
      • 32
      • 33
      • 34
      • 35
      • 36
      • 37
      • 38
      • 39
      • 40
      • 41
      • 42
      • 43
      • 44
      • 45
      • 46
      • 47
      • 48
      • 49
      • 50
      • 51
      • 52
      • 53
      • 54
      • 55
      • 56
      • 57
      • 58
      • 59
      • 60
      • 61
      • 62
      • 63
      • 64
      • 65
      • 66
      • 67
      • 68
      • 69
    • 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;
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21
      • 22
      • 23
      • 24
      • 25
      • 26
      • 27
      • 28
      • 29
  • 相关阅读:
    Linux 基础入门
    中国电信增值业务是什么?一类和二类的区别是什么?
    rv1126-rv1109-RkLunch.sh
    python部署项目为什么要用Nginx和uWSGI
    Free MyBatis plugin搜索不到解决,最新2021.12.09版本下载
    ARM 版 OpenEuler 22.03 部署 KubeSphere v3.4.0 不完全指南续篇
    java文件传输简单方法
    html滑动文章标题置顶
    Hyperledger Besu环境搭建(Linux)
    交换机和路由器技术-20-动态路由协议
  • 原文地址:https://blog.csdn.net/Tyro_java/article/details/133220760