初识WebGL | 青训营笔记

110 阅读4分钟

这是我参与「第四届青训营 」笔记创作活动的的第13天

1. 概述

WebGL 是什么?

WebGL(全写Web Graphics Library)是一种3D绘图协议,这种绘图技术标准允许把JavaScript和OpenGL ES 2.0结合在一起,通过增加OpenGL ES 2.0的一个JavaScript绑定,WebGL可以为HTML5 Canvas提供硬件3D加速渲染,这样Web开发人员就可以借助系统显卡来在浏览器里更流畅地展示3D场景和模型了,还能创建复杂的导航和数据视觉化。显然,WebGL技术标准免去了开发网页专用渲染插件的麻烦,可被用于创建具有复杂3D结构的网站页面,甚至可以用来设计3D网页游戏等等。

WebGL 为什么不像其他前端技术那么简单?

因为 WebGL 的技术栈和传统的 Web 前端技术有极大的差别。相对而言,传统 Web 前端使用的 API 比较高级,不存在太多需要理解的底层原理和概念,而 WebGL 的核心是 OpenGL,它是 OpenGL 在 Web 上的实现。OpenGL 是通过操作 GPU 来完成图形绘制渲染的,因此它的 API 相对比较底层,使用起来较为繁琐,这使得一些习惯于前端开发的工程师很难适应,所以就会觉得学习门槛较高。

2. Modern Graphics System 现代图形系统

组成

image.png

  • 光栅(Raster):几乎所有的现代图形系统都是基于光栅来绘制图形的,光栅就是指构成图像的像素阵列。
  • 像素(Pixel):一个像素对应图像上的一个点,它通常保存图像上的某个具体位置的颜色等信息。
  • 帧缓存(Frame Buffer):在绘图过程中,像素信息被存放于帧缓存中,帧缓存是一块内存地址。
  • CPU(Central Processing Unit):中央处理单元,负责逻辑计算。
  • GPU(Graphics Processing Unit):图形处理单元,负责图形计算。

图形渲染的过程

image.png

  1. 轮廓提取 / meshing
  2. 光栅化
  3. 帧缓存
  4. 渲染

渲染管线 The Pipeline

image.png 处理单元为什么要分成CPU和GPU

image.png

我们知道CPU的一个核心在同一时间内,只能处理一个任务,就像一个管道,不能并行处理;CPU的核心数越多(8核,16核)等,可以并行处理很多任务,但是CPU的核心数不可能成千上万;当我们处理图形渲染的任务时,假如处理一张图片(800x600),像素个数48w,我们只需要算出每个像素在当前位置上的颜色即可;但是我们如果用CPU来处理的话,就像在管道里边塞了一堆沙子,而我们却需要一个一个的进行串行处理,这不能忍。

image.png

我们可以使用GPU来处理这一堆沙子,GPU的特点:

  • GPU由大量的小运算单元构成
  • 每个运算单元只负责处理很简单的计算
  • 每个运算单元彼此独立
  • 因此所有计算可以并行处理

这样就像是有多个管道了:

image.png

3. OpenGL 与 WebGL

image.png WebGL是OpenGL的子集,是在浏览器上的一种实现;OpenGL是一种图形渲染引擎。

4. 使用WebGL绘制三角形

image.png 步骤:

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

  1. 创建 WebGL 上下文
<canvas style="width:500px; height:500px;"></canvas>
const canvas = document.querySelector('canvas');
const gl = canvas.getContext('webgl');

适配老版本的创建 WebGL 上下文

image.png


  1. 书写着色器 The Shaders

WebGL 中有两个着色器:

  1. Vertex Shader 顶点着色器 主要用于处理图形的轮廓
  2. Fragment Shader 片元着色器 处理轮廓后,点光栅化后,把像素点映射到片段着色器上,进行颜色的处理。

Vertex Shader

image.png

Fragment Shader

image.png


  1. 利用顶点着色器和片元着色器创建 WebGL Program 程序

image.png

        //创建顶点着色器
        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);

        //创建program
        const program = gl.createProgram();
        gl.attachShader(program, vertexShader);
        gl.attachShader(program, fragmentShader);
        gl.linkProgram(program);
        gl.useProgram(program);

理解WebGL中的坐标系

image.png

WebGL 中的坐标系以canvas中心点为原点,分为x, y, z三轴,三维坐标系。

归一化:x, y, z轴默认长度最大值为1,最小值为-1


  1. 通过类型数组(Typed Array),把三个点存储到32位浮点型的数组中
const points = new Float32Array([
      -1,-1,
       0,1,
       1,-1
]);

Data to Frame Buffer 把数据送到帧缓冲区

const bufferId = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER,bufferId);
gl.bufferData(gl.ARRAY_BUFFER,points,gl.STATIC_DRAW);

  1. 帧缓冲区到GPU

送到缓冲区的数据会通过顶点着色器和片段着色器去执行WebGL的progrem

image.png


  1. 输出到页面
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, points.length / 2);

image.png

5. 推荐资源

  1. The book of shaders
  2. Mesh.js
  3. glsl-doodle
  4. SpriteJS
  5. ThreeJS
  6. ShaderToy