WebGL | 青训营笔记

59 阅读2分钟

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

Why WebGL / Why GPU

  • WebGL是什么?

    • GPU ≠ WebGL ≠ 3D
  • WebGL为什么不像其他前端技术那么简单?

Modern Graphics System

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

The Pipeline

管线:数据——>处理——>帧缓存——>渲染像素

GPU

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

WebGL Startup

  1. 创建WebGL上下文

    // Create WebGL Context
    const canvas = document.querySelector('canvas')
    const gl = canvas.getContext('webgl')
    function create3DContext(canvas, options) {
        const names = ['webgl', 'experimental-webgl', 'webkit-3d', 'moz-webgl']
        if (options.webgl2) names.unshift('webgl2')
        let context = null
        for (let ii = 0; ii < names.length; ++i) {
            try {
                context = canvas.getContext(names[ii], options)
            } catch (e) {
                // no-empty
            }
            if (context) {
                break;
            }
        }
        return context
    }
    
  2. 创建WebGL Program

    const vertex = `
      attribute vec2 position;
      varying vec4 color;
    ​
      void main() {
        gl_PointSize = 1.0;
        gl_Position = vec4(position, 1.0, 1.0);
        color = vec4(0.5 * (vec2(1.0) + position), 0.0, 1.0);
      }
    `
        const fragment = `
      precision mediump float;
      varying vec4 color;
    ​
      void main()
      {
        // gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);
        gl_FragColor = color;
      }
    `
        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);
        const program = gl.createProgram()
        gl.attachShader(program, vertexShader)
        gl.attachShader(program, fragmentShader)
        gl.linkProgram(program)
        gl.useProgram(program)
    
  3. 将数据存入缓存区

    // Data to Frame Buffer
    const points = new Float32Array([-1, -1, 0, 1, 1, -1])
    const bufferId = gl.createBuffer()
    gl.bindBuffer(gl.ARRAY_BUFFER, bufferId)
    gl.bufferData(gl.ARRAY_BUFFER, points, gl.STATIC_DRAW)
    
  4. 读取缓冲区数据到GPU

    // Frame Buffer to GPU
    const vPosition = gl.getAttribLocation(program, 'position')
    gl.vertexAttribPointer(vPosition, 2, gl.FLOAT, false, 0, 0)
    gl.enableVertexAttribArray(vPosition)
    
  5. GPU执行WebGL程序,输出结果

    // Output
    gl.clear(gl.COLOR_BUFFER_BIT)
    gl.drawArrays(gl.TRIANGLES, 0, points.length / 2)
    

为什么WebGL那么难 ?

  • 2D

    const canvas = document.querySelector('canvas')
    const ctx = canvas.getContext('2d')
    ctx.beginPath()
    ctx.moveTo(200, 0)
    ctx.lineTo(400, 400)
    ctx.lineTo(0, 400)
    ctx.fillStyle = 'red'
    ctx.fill()
    
  • Mesh.js

    const canvas = document.querySelector('canvas')
    const renderer = new Renderer(canvas)
    const figure = new Figure2D()
    figure.beginPath()
    figure.moveTo(200, 0)
    figure.lineTo(400, 400)
    figure.lineTo(0, 400)
    const mesh = new Mesh2D(fugure, canvas)
    mesh.setFill({
        color: [1, 0, 0, 1]
    })
    renderer.drawMeshes([mesh])
    

3D Matrix

3D标准模型有四个齐次矩阵(mat4)

  1. 投影矩阵 Projection Matrix
  2. 模型矩阵 Model Matrix
  3. 视图矩阵 View Matrix
  4. 法向量矩阵 Normal Matrix