const VSHADER_SOURCE = `attribute vec4 a_Position; attribute vec2 a_TexCoord; uniform mat4 translation; varying vec2 v_TexCoord; void main() { gl_Position = translation * a_Position; v_TexCoord = a_TexCoord; }`; const FSHADER_SOURCE = `precision mediump float; uniform sampler2D u_Sampler; varying vec2 v_TexCoord; void main() { gl_FragColor = texture2D(u_Sampler, v_TexCoord); }`; let imgData = null; let mtrData = null; let gl = null; function init(output) { var canvas = document.createElement('canvas'); canvas.width = output.width; canvas.height = output.height; gl = canvas.getContext('webgl') || canvas.getContext('experimental-webgl'); // 初始化之前先加载图片 if (!initShaders(gl, VSHADER_SOURCE, FSHADER_SOURCE)) { return; } } function main(opt) { const { imageData, mtr, output, input } = opt; mtrData = mtr; imgData = imageData; gl.clearColor(0, 0, 0, 1); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); const n = initVertexBuffers(gl); initTextures(gl, n, 0); let outputData = new Uint8Array(output.width * output.height * 4); gl.readPixels(0, 0, output.width, output.height, gl.RGBA, gl.UNSIGNED_BYTE, outputData); return outputData; } function initVertexBuffers(gl) { // 顶点坐标和纹理图像坐标 const vertices = new Float32Array([ // webgl坐标,纹理坐标 -1.0, 1.0, 0.0, 0.0, 1.0, -1.0, -1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0, 1.0, -1.0, 0.0, 1.0, 0.0 ]); const FSIZE = vertices.BYTES_PER_ELEMENT; const vertexBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); const aPosition = gl.getAttribLocation(gl.program, 'a_Position'); const aTexCoord = gl.getAttribLocation(gl.program, 'a_TexCoord'); var xformMatrix = new Float32Array([ mtrData[0][0], mtrData[1][0], 0.0, 0.0, mtrData[0][1], mtrData[1][1], 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, mtrData[0][2], mtrData[1][2], 0.0, 1.0 ]); var translation = gl.getUniformLocation(gl.program, 'translation'); gl.uniformMatrix4fv(translation, false, xformMatrix); gl.vertexAttribPointer(aPosition, 3, gl.FLOAT, false, FSIZE * 5, 0); gl.enableVertexAttribArray(aPosition); gl.vertexAttribPointer(aTexCoord, 2, gl.FLOAT, false, FSIZE * 5, FSIZE * 3); gl.enableVertexAttribArray(aTexCoord); return 4; } function initTextures(gl, n, index) { // 创建纹理对象 const texture = gl.createTexture(); const uSampler = gl.getUniformLocation(gl.program, 'u_Sampler'); // WebGL纹理坐标中的纵轴方向和PNG,JPG等图片容器的Y轴方向是反的,所以先反转Y轴 gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, 1); // 激活纹理单元,开启index号纹理单元 gl.activeTexture(gl[`TEXTURE${index}`]); // 绑定纹理对象 gl.bindTexture(gl.TEXTURE_2D, texture); // 配置纹理对象的参数 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR); // 将纹理图像分配给纹理对象 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, imgData); // 将纹理单元编号传给着色器 gl.uniform1i(uSampler, index); // 绘制 gl.drawArrays(gl.TRIANGLE_STRIP, 0, n); return; } function initShaders(gl, vshader, fshader) { var vertexShader = createShader(gl, vshader, gl.VERTEX_SHADER); var fragmentShader = createShader(gl, fshader, gl.FRAGMENT_SHADER); var program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); if (!program) { console.log('无法创建程序对象'); return false; } gl.linkProgram(program); gl.useProgram(program); gl.program = program; return true; } function createShader(gl, sourceCode, type) { // Compiles either a shader of type gl.VERTEX_SHADER or gl.FRAGMENT_SHADER var shader = gl.createShader(type); gl.shaderSource(shader, sourceCode); gl.compileShader(shader); if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) { var info = gl.getShaderInfoLog(shader); throw 'Could not compile WebGL program. \n\n' + info; } return shader; } export default { main, init };