久しぶりにWebGLで遊んでみた。とはいっても二次元の画像処理だけど。やったのはエンボスフィルタだと思われる。以下が元の画像とフィルター後の画像。その下にソースコードを載せる
<!DOCTYPE html> <html> <head> <title></title> <script> window.onload = function() { var image = new Image(); image.src = "./bakeneko.png"; image.addEventListener('load', function() { render(image); }, false); } function render(image){ var canvas = document.getElementById("canvas"); var gl = canvas.getContext("experimental-webgl"); var vertexShader = createShader(gl, "2d-vertex-shader", gl.VERTEX_SHADER); var fragmentShader = createShader(gl, "2d-fragment-shader", gl.FRAGMENT_SHADER); program = createProgram(gl, vertexShader, fragmentShader); setTexCood(gl, program); setTexture(gl, image); setResolution(gl, program, canvas); setImageSize(gl, program, image); setPosition(gl, program, image); gl.drawArrays(gl.TRIANGLES, 0, 6); } function setTexCood(gl, program){ var texCoordLocation = gl.getAttribLocation(program, "a_texCoord"); var texCoordBuffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, texCoordBuffer); gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ 0.0, 0.0, 1.0, 0.0, 0.0, 1.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0]), gl.STATIC_DRAW); gl.enableVertexAttribArray(texCoordLocation); gl.vertexAttribPointer(texCoordLocation, 2, gl.FLOAT, false, 0, 0); } function setTexture(gl, image){ var texture = gl.createTexture(); 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.NEAREST); gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); } function setResolution(gl, program, canvas){ var resolutionLocation = gl.getUniformLocation(program, "u_resolution"); gl.uniform2f(resolutionLocation, canvas.width, canvas.height); } function setImageSize(gl, program, image){ var sizeLocation = gl.getUniformLocation(program, "u_size"); gl.uniform2f(sizeLocation, image.width, image.height); } function setPosition(gl, program, image){ var positionLocation = gl.getAttribLocation(program, "a_position"); var buffer = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, buffer); gl.enableVertexAttribArray(positionLocation); gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0); setRectangle(gl, 0, 0, image.width, image.height); } function setRectangle(gl, x, y, width, height) { var x1 = x; var x2 = x + width; var y1 = y; var y2 = y + height; gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([ x1, y1, x2, y1, x1, y2, x1, y2, x2, y1, x2, y2]), gl.STATIC_DRAW); } function createShader(gl, shaderId, type) { var shader = gl.createShader(type); var source = document.getElementById(shaderId).innerHTML; gl.shaderSource(shader, source); gl.compileShader(shader); return shader; } function createProgram(gl, vertexShader, fragmentShader){ var program = gl.createProgram(); gl.attachShader(program, vertexShader); gl.attachShader(program, fragmentShader); gl.linkProgram(program); if (!gl.getProgramParameter(program, gl.LINK_STATUS)) { alert(gl.getShaderInfoLog(vertexShader)); alert(gl.getShaderInfoLog(fragmentShader)); } gl.useProgram(program); return program; } </script> <script id="2d-vertex-shader" type="x-shader/x-vertex"> attribute vec2 a_position; attribute vec2 a_texCoord; uniform vec2 u_resolution; varying vec2 v_texCoord; void main() { vec2 zeroToOne = a_position / u_resolution; vec2 zeroToTwo = zeroToOne * 2.0; vec2 clipSpace = zeroToTwo - 1.0; gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1); v_texCoord = a_texCoord; } </script> <script id="2d-fragment-shader" type="x-shader/x-fragment"> precision mediump float; uniform sampler2D u_image; uniform vec2 u_size; varying vec2 v_texCoord; void main() { float weight[9]; vec2 offset[9]; float dx = 1.0 / u_size.x; float dy = 1.0 / u_size.y; for(int i = 0; i < 3; i++){ for(int j = 0; j < 3; j++){ offset[i + j * 3] = vec2(float(-(2 / 2 + i)) * dx, float(-(2 / 2 + i)) * dy); } } for(int i = 0; i < 3; i++){ weight[i * 3] = -1.0; weight[i * 3 + 1] = 0.0; weight[i * 3 + 2] = 1.0; } vec3 col = vec3(0.0); for(int j = 0; j < 9; j++){ col += texture2D(u_image, v_texCoord + offset[j]).rgb * weight[j]; } col += texture2D(u_image, v_texCoord).rgb; gl_FragColor = vec4(col, 1.0); } </script> </head> <body> <canvas id="canvas" width="128" height="128"></canvas> </body> </html>