认识 Canvas 和 WebGL

751 阅读5分钟

Canvas 和 WebGL 入门教程

在前端开发中,绘图已经成为一种重要的技能,而 CanvasWebGL 是实现图形绘制的两个重要工具。本文将带你入门 CanvasWebGL,帮助你理解如何使用它们在浏览器中绘制图形。


一、Canvas 入门

Canvas 是 HTML5 提供的一个绘图容器,可以用于图形、动画和游戏开发。通过 Canvas API,你可以直接使用 JavaScript 绘制图像、矩形、圆形等图形。

1. 基本结构

首先,在 HTML 文件中添加一个 canvas 标签,并设置它的宽度和高度。

<canvas id="myCanvas" width="500" height="500"></canvas>

2. 获取绘图上下文

要在 canvas 上绘图,我们需要获取绘图上下文。一般使用 2D 上下文 (getContext('2d')),然后通过这个上下文调用各种绘图方法。

const canvas = document.getElementById('myCanvas');
const ctx = canvas.getContext('2d');

3. 绘制基本图形

  • 绘制矩形

    ctx.fillStyle = 'blue';
    ctx.fillRect(50, 50, 100, 100);
    
  • 绘制线条

    ctx.beginPath();
    ctx.moveTo(200, 200);
    ctx.lineTo(300, 300);
    ctx.stroke();
    
  • 绘制圆形

    ctx.beginPath();
    ctx.arc(150, 150, 50, 0, Math.PI * 2);
    ctx.fillStyle = 'red';
    ctx.fill();
    

二、WebGL 入门

WebGL 是基于 OpenGL ES 2.0 的一个 JavaScript API,支持硬件加速的 3D 绘图,适合开发游戏、数据可视化和 3D 应用。相比 CanvasWebGL 能渲染更为复杂和高性能的图形。

1. 基本结构

Canvas 一样,首先需要在 HTML 中添加 canvas 标签:

<canvas id="webglCanvas" width="500" height="500"></canvas>

2. 获取 WebGL 上下文

使用 getContext('webgl') 方法获取 WebGL 上下文:

const canvas = document.getElementById('webglCanvas');
const gl = canvas.getContext('webgl');

if (!gl) {
  console.log("WebGL not supported, falling back on experimental-webgl");
  gl = canvas.getContext("experimental-webgl");
}

3. 创建和编译着色器

WebGL 中,绘图通过顶点着色器(vertex shader)和片段着色器(fragment shader)进行。以下代码展示了如何创建和编译一个简单的着色器:

const vertexShaderSource = `
  attribute vec2 position;
  void main() {
    gl_Position = vec4(position, 0.0, 1.0);
  }
`;

const fragmentShaderSource = `
  precision mediump float;
  uniform vec4 color;
  void main() {
    gl_FragColor = color;
  }
`;

function createShader(gl, type, source) {
  const shader = gl.createShader(type);
  gl.shaderSource(shader, source);
  gl.compileShader(shader);
  return shader;
}

const vertexShader = createShader(gl, gl.VERTEX_SHADER, vertexShaderSource);
const fragmentShader = createShader(gl, gl.FRAGMENT_SHADER, fragmentShaderSource);

attribute vec2 position;

  • 含义position 是一个二维向量(vec2),表示顶点的坐标。

  • 来源attribute 是用于从 CPU 传递给 GPU 顶点着色器的数据。它通常由用户通过 WebGL API 设置,比如通过缓冲区传递顶点数据。

  • 数据类型:二维向量(vec2),通常表示顶点在 2D 平面中的位置,例如 (x, y)

void main()

  • 含义:这是顶点着色器的主函数,GPU 会为每个顶点调用一次。

gl_Position = vec4(position, 0.0, 1.0);

  • 作用:定义顶点在裁剪空间的坐标。

    • gl_Position 是内建变量,表示顶点在裁剪空间中的坐标,是一个四维向量(vec4)。

    • vec4(position, 0.0, 1.0) 将二维的 position 转换为四维向量:

      • x, y:来自传入的 position
      • z = 0.0:假设顶点位于 z=0 平面。
      • w = 1.0:用于齐次坐标的规范化。
  • 结果:将二维顶点坐标 position 映射到 OpenGL 的裁剪空间,其中 z 坐标为 0.0

precision mediump float;

  • 含义:定义浮点数的精度。

    • precision:用于指定变量(如 float 类型)的精度。
    • mediump:表示中等精度(medium precision)。
  • 用途:片段着色器中的浮点数计算可能影响最终渲染结果,因此需要明确指定精度。常用的精度有:

    • lowp:低精度,适合节能或性能优先的简单计算。
    • mediump:中等精度,适合大部分常规用途。
    • highp:高精度,通常用于需要高细节的效果(如 3D 渲染的深度计算等)。

在片段着色器中,中等精度通常够用,尤其是对于颜色计算。

4. 创建着色器程序并绘制三角形

将着色器链接到一个着色器程序中,然后在画布上绘制一个简单的三角形。

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

const positionBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, positionBuffer);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
  0, 0.5,
  -0.5, -0.5,
  0.5, -0.5
]), gl.STATIC_DRAW);

const positionLocation = gl.getAttribLocation(program, "position");
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);

const colorLocation = gl.getUniformLocation(program, "color");
gl.uniform4f(colorLocation, 1.0, 0.0, 0.0, 1.0); // 红色

gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 3);

gl.drawArrays

  • 功能:WebGL 的绘制函数,基于顶点缓冲区中的数据绘制图形。

  • 签名

    gl.drawArrays(mode, first, count);
    
    • mode:指定绘制的图元类型,例如点、线、三角形。
    • first:从顶点缓冲区中的哪个索引开始读取数据。
    • count:要绘制的顶点数量。

参数说明

gl.drawArrays(gl.TRIANGLES, 0, 3);
  1. gl.TRIANGLES

    • 含义:绘制三角形。

    • 工作原理

      • 每 3 个连续的顶点定义一个三角形。
      • 如果顶点数量不是 3 的倍数,多余的顶点将被忽略。
    • 示例

      • 如果缓冲区中有顶点数据 [v0, v1, v2, v3, v4, v5]

        • 第一个三角形:[v0, v1, v2]
        • 第二个三角形:[v3, v4, v5]
  2. 0

    • 含义:从顶点缓冲区的第一个顶点开始读取。
    • 作用:指定从第 0 个顶点开始绘制。
  3. 3

    • 含义:绘制 3 个顶点。

    • 作用

      • GPU 将读取缓冲区中的前 3 个顶点。
      • 因为 modegl.TRIANGLES,这 3 个顶点将组成一个三角形。

三、Canvas 和 WebGL 的区别与选择

特性CanvasWebGL
绘制维度2D2D 和 3D
性能适合简单图形,性能较低硬件加速,高性能
使用难度简单,适合初学者较复杂,适合需要高性能的项目
适用场景简单图表、动画游戏、3D 数据可视化、复杂动画

选择 Canvas 还是 WebGL 主要取决于项目需求:如果仅需绘制简单的图表或动画,可以选择 Canvas;如果需要绘制复杂的 3D 场景或高性能动画,则 WebGL 是更好的选择。


四、进阶学习

学习 CanvasWebGL 的基础后,你可以逐步深入探索一些高级技术和工具:

  • Canvas 高级技术:掌握 Canvas API 的高级特性,如图像处理、动画优化、路径和文本处理等。
  • WebGL 框架:可以学习 Three.js 等 WebGL 框架,简化 3D 图形渲染工作,并进一步探索 GLSL 着色器编程。

希望通过本教程,你能更好地理解 CanvasWebGL,并灵活运用它们在网页中绘制图形。