webgl 影像處理
webgl 不僅僅可以用來進行圖形視覺化, 它還能進行影像處理
影像處理1---資料傳輸
webgl 進行圖形處理的第一步: 傳輸資料到 GPU
下圖為傳輸點資料到 GPU 並進行相應渲染的結果
資料傳輸過程
- 建立 canvas 元素, 用來承接 GPU 生成的資料
- 獲取 context, program 用於運算元據和使用相應 API
- 初始化著色器, 將寫的著色器編譯進 program 總
- 傳送資料, 將頂點資料, uv 資料, 等等資料, 均可以通過 sendData 方法將資料傳輸到 glsl 中的變數上
- 建立緩衝區
- 繫結緩衝區
- 向緩衝區中新增資料
- 將資料與 glsl 中的變數繫結
- 傳輸資料
- 所有傳輸資料的流程與此基本類似
- 清除之前的顏色, 清除顏色緩衝區, 畫出自己想要的圖形
下一階段
當前階段實現了將基本資料傳輸給 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);
}