webgl 影像處理 加速計算

webgl 影像處理

webgl 不僅僅可以用來進行圖形可視化, 它還能進行影像處理

影像處理1—數據傳輸

webgl 進行圖形處理的第一步: 傳輸數據到 GPU

下圖為傳輸點數據到 GPU 並進行相應渲染的結果

image-20210917225715565

數據傳輸過程

  1. 創建 canvas 元素, 用來承接 GPU 生成的數據
  2. 獲取 context, program 用於操作數據和使用相應 API
  3. 初始化著色器, 將寫的著色器編譯進 program 總
  4. 發送數據, 將頂點數據, uv 數據, 等等數據, 均可以通過 sendData 方法將數據傳輸到 glsl 中的變數上
    1. 創建緩衝區
    2. 綁定緩衝區
    3. 向緩衝區中添加數據
    4. 將數據與 glsl 中的變數綁定
    5. 傳輸數據
    6. 所有傳輸數據的流程與此基本類似
  5. 清除之前的顏色, 清除顏色緩衝區, 畫出自己想要的圖形

下一階段

當前階段實現了將基本數據傳輸給 GPU

下一步是將 影像數據 傳輸到 GPU, GPU 接收到影像資訊後獲取每個像素點的顏色值, 通過卷積重置像素, 初步實現 webgl 的圖形處理功能

程式碼實現

// 兩種著色器
const VSHADER_SOURCE = `
  attribute vec4 a_Position;
  attribute vec2 uv;
  varying vec2 vUv;
  void main(){
    // 進行插值計算
    vUv = uv;
    gl_Position = a_Position;
  }
`;

const FSHADER_SOURCE = `
  // 片元著色器中一定要聲明精度
  precision mediump float;
  varying vec2 vUv;
  void main(){
    gl_FragColor = vec4(vUv.x, vUv.y, 0.6, 1.0);
  }
`;

init();

function init() {
  const canvas = document.createElement("canvas");
  canvas.width = 200;
  canvas.height = 200;
  document.body.appendChild(canvas);

  // 獲取 gl 環境
  const gl = canvas.getContext("webgl");
  if (!gl) {
    console.log("Fail to init content");
    return;
  }

  // webgl 程式
  const programe = gl.createProgram();

  // 初始化著色器
  initShader(gl, VSHADER_SOURCE, FSHADER_SOURCE, programe);

  // 發送數據
  sendData("a_Position", 2, [-1, 1, -1, -1, 1, -1, 1, 1], gl, programe);

  sendData("uv", 2, [0, 1, 0, 0, 1, 0, 1, 1], gl, programe);

  // 刷新顏色
  gl.clearColor(0.0, 0.0, 0.0, 1.0);
  // 清除
  gl.clear(gl.COLOR_BUFFER_BIT);
  // 畫圖形
  gl.drawArrays(gl.TRIANGLE_FAN, 0, 4);
}

// 初始化著色器
function initShader(gl, VSHADER_SOURCE, FSHADER_SOURCE, programe) {
  // 創建 shader
  const vertexShader = gl.createShader(gl.VERTEX_SHADER);
  // 綁定資源
  gl.shaderSource(vertexShader, VSHADER_SOURCE);
  // 編譯著色器
  gl.compileShader(vertexShader);
  const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER, FSHADER_SOURCE);
  gl.shaderSource(fragmentShader, FSHADER_SOURCE);
  gl.compileShader(fragmentShader);

  // 常規流程
  gl.attachShader(programe, vertexShader);
  gl.attachShader(programe, fragmentShader);
  gl.linkProgram(programe);
  gl.useProgram(programe);
}

// 發送數據到 GPU
function sendData(name, size, arr, gl, programe) {
  // 獲取地址空間
  const variate = gl.getAttribLocation(programe, name);
  if (variate < 0) {
    console.log(`Failed to get the location of ${name}`);
    return;
  }
  const variates = new Float32Array(arr);
  // 1. 創建快取區
  const buffer = gl.createBuffer();
  if (!buffer) {
    console.log("Failed to create buffer");
  }
  // 2. 綁定快取區
  gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
  // 3. 向緩衝區中添加數據
  gl.bufferData(gl.ARRAY_BUFFER, variates, gl.STATIC_DRAW);
  // 4. 將緩衝區與 glsl 中變數綁定
  gl.vertexAttribPointer(variate, size, gl.FLOAT, false, 0, 0);
  // 5. 開始傳輸
  gl.enableVertexAttribArray(variate);
}
Tags: