05《跟月影学可视化》学习笔记@初看WebGL

·  阅读 562

使用 WebGL 绘图,必须要和内存、GPU 打交道,真正控制图形输出的每一个细节。

一、WebGL 最基本的概念

计算机图形系统

二、WebGL 绘制图形

  1. 创建 WebGL 上下文;
  2. 创建 WebGL 程序;
  3. 将数据存入缓冲区;
  4. 将缓冲区数据读取到 GPU
  5. GPU 执行 WebGL 程序,输出结果。

1. 创建 WebGL 上下文

const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');
复制代码

2. 创建 WebGL 程序

创建一个 WebGLProgram 对象,给 GPU 最终运行着色器的程序。

  1. 编写着色器

    着色器是用 GLSL 编程语言编写的代码片段。

    // 顶点着色器:负责处理图形的顶点信息。
     const vertex = `
       attribute vec2 position;
    
       void main() {
         gl_PointSize = 1.0;
         gl_Position = vec4(position, 1.0, 1.0);
       }
     `;
     // 片元着色器:负责处理图形的像素信息。
     const fragment = `
       precision mediump float;
    
       void main() {
         gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
       }
     `;
    复制代码
    在绘图的时候,WebGL 是以顶点和图元来描述图形几何信息的。
    • 顶点:几何图形的顶点。

      顶点着色器Vertex Shader):负责处理图形的顶点信息。
      可以改变顶点的信息,如:点的坐标、法线方向、材质等,从而该百年绘制出来的图形的形状或者大小等。

    • 图元:WebGL 可直接处理的图形单元(其他非图元的图形最终必须要转换为图元才可以被 WebGL 处理)。由 WebGL 的绘图模式决定,有点、线、三角形等。

      片元着色器Fragment Shader):负责处理图形的像素信息。
      对指定图元中的像素点着色(处理光栅化后的像素信息)。

      光栅化过程:WebGL 从顶点着色器和图元提取像素点给片元着色器执行代码的过程。

  2. 创建 shader 对象
    const vertexShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertexShader, vertex);
    gl.compileShader(vertexShader);
     
    const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragmentShader, fragment);
    gl.compileShader(fragmentShader);
    复制代码
  3. 创建 WebGLProgram 对象
    // 添加shader对象,然后链接到WebGL上下文对象上。
    const program = gl.createProgram();
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    gl.linkProgram(program);
    复制代码
  4. 启用 WebGLProgram 对象
    gl.useProgram(program);
    复制代码

3. 将数据存入缓冲区

WebGL 的坐标系是一个右手坐标系。

WebGL 使用的数据需要用类型数组定义。

  1. 使用类型数组定义顶点(默认为 Float32Array 类型化数组)
    const points = new Float32Array([
      -1, -1,
      0, 1,
      1, -1,
    ]);
    复制代码
  2. 将定义好的数据写入WebGL缓存区

    a, 创建一个缓存对象;
    b, 绑定为当前操作对象;
    c, 把当前的数据写入缓存对象。

    const bufferId = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
    gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);
    复制代码

4. 将缓冲区数据读取到 GPU

const vPosition = gl.getAttribLocation(program, 'position');
gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0);
gl.enableVertexAttribArray(vPosition);
复制代码

5. 执行着色器程序完成绘制

gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, points.length / 2);
复制代码

GPU 并行计算
不论图形中有多少个像素点,着色器程序在 GPU 中就会被同时执行多少次。

三、顶点着色器的作用

  1. 通过 gl_Position 设置顶点;
    // 将原有三角形的周长缩小为原来的一半
    const vertex = `
      attribute vec2 position;
      
      void main() {
        gl_PointSize = 1.0;
        gl_Position = vec4(position * 0.5, 1.0, 1.0);
      }
    `;
    复制代码
  2. 通过定义 varying 变量,向片元着色器传递数据。
    // 将数据通过varying变量传给片元着色器
    const vertex = `
      attribute vec2 position;
      varying vec3 color;
      
      void main() {
        gl_PointSize = 1.0;
        color = vec3(0.5 + position *0.5, 0.0);
        gl_Position = vec4(position * 0.5, 1.0, 1.0);
      }
    `;
    复制代码

四、WebGL 绘图步骤简图

WebGL绘制图形5大步

五、其他

仅供交流学习。demo

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>WebGL版三角形</title>
</head>

<body>
  <canvas></canvas>

  <script>
    // 1. 创建WebGL上下文
    const canvas = document.querySelector('canvas');
    const gl = canvas.getContext('webgl');

    // 2. 创建WebGL程序:一个WebGLProgram对象,给GPU最终运行着色器的程序。
    // 顶点着色器:负责处理图形的顶点信息。
    const vertex = `
      attribute vec2 position;
      varying vec3 color;

      void main() {
        gl_PointSize = 1.0;
        // 线性插值:让像素点的颜色均匀渐变。
        color = vec3(0.5 + position * 0.5, 0.0);
        gl_Position = vec4(position * 0.5, 1.0, 1.0);
      }
    `;
    // 创建shader对象
    const vertexShader = gl.createShader(gl.VERTEX_SHADER);
    gl.shaderSource(vertexShader, vertex);
    gl.compileShader(vertexShader);

    // 片元着色器:负责处理图形的像素信息。
    const fragment = `
      precision mediump float;
      varying vec3 color;

      void main() {
        // gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
        gl_FragColor = vec4(color, 1.0);
      }
    `;
    // 创建shader对象
    const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
    gl.shaderSource(fragmentShader, fragment);
    gl.compileShader(fragmentShader);

    // 创建WebGLProgram对象:添加shader对象,然后链接到WebGL上下文对象上。
    const program = gl.createProgram();
    gl.attachShader(program, vertexShader);
    gl.attachShader(program, fragmentShader);
    gl.linkProgram(program);

    // 启用WebGLProgram对象
    gl.useProgram(program);

    // 3. 将数据存入缓冲区
    // 使用类型数组定义顶点(默认为Float32Array类型化数组)
    const points = new Float32Array([
      -1, -1,
      0, 1,
      1, -1,
    ]);

    // 将定义好的数据写入WebGL缓存区:创建一个缓存对象 》绑定为当前操作对象 》把当前的数据写入缓存对象。
    const bufferId = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, bufferId);
    gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW);

    // 4. 将缓冲区数据读取到GPU:获取顶点着色器中的position变量地址 》给变量设置长度和类型 》激活变量。
    const vPosition = gl.getAttribLocation(program, 'position');
    gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0);
    gl.enableVertexAttribArray(vPosition);

    // 5. 执行着色器程序完成绘制
    gl.clear(gl.COLOR_BUFFER_BIT);
    gl.drawArrays(gl.TRIANGLES, 0, points.length / 2);
  </script>
</body>

</html>
复制代码
分类:
前端
标签:
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改