Very new to WebGL and attempting to port some 2D image processing shaders in order to get a handle on things. I initially was misled by the MDN tutorials into thinking WebGL was like OpenGL desktop, but then found these tutorials, which I found much more true to form as well as my purposes. However, I'm still having some trouble in formatting a render loop so I can pass a continually updating texture for processing. In cases where it does render, I just get a muddy mess and in cases where the vertex shader isn't a simple pass through I get nothing. I understand GLSL and the basics of how buffers work, but clearly am doing something very wrong here... Any help would be greatly appreciated. Thanks!
class GL {
constructor(canvas){
this.gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
if (!this.gl) {
alert("Unable to initialize WebGL. Your browser may not support it.");
this.gl = null;
}
//init shaders
var fragmentShader = getShader(this.gl, "fshader");
var vertexShader = getShader(this.gl, "vshader");
var shaderProgram = this.gl.createProgram();
this.gl.attachShader(shaderProgram, vertexShader);
this.gl.attachShader(shaderProgram, fragmentShader);
this.gl.linkProgram(shaderProgram);
this.gl.useProgram(shaderProgram);
this.positionLocation = this.gl.getAttribLocation(shaderProgram, "position");
this.texCoordLocation = this.gl.getAttribLocation(shaderProgram, "texcoord");
var resolutionLocation = this.gl.getUniformLocation(shaderProgram, "resolution");
this.width = this.gl.getUniformLocation(shaderProgram, "width");
//set resolution
this.gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
function getShader(gl, id) {
var shaderScript, theSource, currentChild, shader;
shaderScript = document.getElementById(id);
if (!shaderScript) {
return null;
}
theSource = "";
currentChild = shaderScript.firstChild;
while(currentChild) {
if (currentChild.nodeType == currentChild.TEXT_NODE) {
theSource += currentChild.textContent;
}
currentChild = currentChild.nextSibling;
}
if (shaderScript.type == "x-shader/x-fragment") {
shader = gl.createShader(gl.FRAGMENT_SHADER);
} else if (shaderScript.type == "x-shader/x-vertex") {
shader = gl.createShader(gl.VERTEX_SHADER);
} else {
// Unknown shader type
return null;
}
gl.shaderSource(shader, theSource);
gl.compileShader(shader);
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
alert("An error occurred compiling the shaders: " + gl.getShaderInfoLog(shader));
return null;
}
return shader;
};
};
render(bufferCanvas, x, y) {
this.gl.clear(this.gl.COLOR_BUFFER_BIT);
//texture coordinates
var texCoordBuffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, this.texCoordBuffer);
this.gl.enableVertexAttribArray(this.texCoordLocation);
this.gl.vertexAttribPointer(this.texCoordLocation, 2, this.gl.FLOAT, false, 8, 0);
this.gl.bufferData(
this.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]),
this.gl.STATIC_DRAW);
//create texture
var texture = this.gl.createTexture();
this.gl.bindTexture(this.gl.TEXTURE_2D, texture);
//normalize image to powers of two
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_S, this.gl.CLAMP_TO_EDGE);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_WRAP_T, this.gl.CLAMP_TO_EDGE);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MIN_FILTER, this.gl.NEAREST);
this.gl.texParameteri(this.gl.TEXTURE_2D, this.gl.TEXTURE_MAG_FILTER, this.gl.NEAREST);
//load texture from 2d canvas
this.gl.texImage2D(this.gl.TEXTURE_2D,
0,
this.gl.RGBA,
this.gl.RGBA,
this.gl.UNSIGNED_BYTE,
bufferCanvas);
//load buffer
var buffer = this.gl.createBuffer();
this.gl.bindBuffer(this.gl.ARRAY_BUFFER, buffer);
this.gl.enableVertexAttribArray(this.positionLocation);
this.gl.vertexAttribPointer(this.positionLocation, 2, this.gl.FLOAT, false, 12, 0);
//draw size and position
this.gl.bufferData(this.gl.ARRAY_BUFFER, new Float32Array([
x, y,
x + bufferCanvas.width, y,
x, y + bufferCanvas.height,
x, y + bufferCanvas.height,
x+ bufferCanvas.width, y,
x+ bufferCanvas.width, y + bufferCanvas.height]), this.gl.STATIC_DRAW);
//blur width
this.gl.enableVertexAttribArray(this.width);
this.gl.vertexAttribPointer(this.width, 1, this.gl.FLOAT, false, 12, 8);
//draw
this.gl.drawArrays(this.gl.TRIANGLES, 0, 6);
};
};
var canvas2d = document.getElementById('buffer-canvas');
var context2d = canvas2d.getContext("2d");
var canvasGL = new GL(document.getElementById('main-canvas'));
canvasGL.width = 5.0;
for(var i=0; i<10; i++) {
var r = Math.floor(Math.random() * 255);
var g = Math.floor(Math.random() * 255);
var b = Math.floor(Math.random() * 255);
var a = Math.floor(Math.random() * 255);
context2d.fillStyle = "rgba(" + r + "," + g + "," + b + "," + a + ")";
var x = Math.random() * canvas2d.width;
var y = Math.random() * canvas2d.height;
var width = canvas2d.width - (Math.random() * canvas2d.width);
var height = canvas2d.height - (Math.random() * canvas2d.height);
context2d.fillRect(x, y, width , height);
canvasGL.render(canvas2d, canvas2d.getBoundingClientRect("left"), canvas2d.getBoundingClientRect("top"));
}
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/sylvester/0.1.3/sylvester.min.js"></script>
<script src="https://github.com/mdn/webgl-examples/blob/gh-pages/tutorial/glUtils.js"></script>
<script id="vshader" type="x-shader/x-vertex">
precision mediump float;
attribute vec2 position;
attribute vec2 texcoord;
uniform vec2 resolution;
uniform float width;
varying vec2 texcoord11;
varying vec2 texcoord00;
varying vec2 texcoord02;
varying vec2 texcoord20;
varying vec2 texcoord22;
void main()
{
gl_Position = vec4(((position / resolution) * 2.0 - 1.0) * vec2(1, -1), 0, 1);
// get texcoords
texcoord11 = texcoord;
texcoord00 = texcoord + vec2(-width, -width);
texcoord02 = texcoord + vec2( width, -width);
texcoord20 = texcoord + vec2( width, width);
texcoord22 = texcoord + vec2(-width, width);
}
</script>
<script id="fshader" type="x-shader/x-fragment">
precision mediump float;
uniform sampler2D image;
varying vec2 texcoord11;
varying vec2 texcoord00;
varying vec2 texcoord02;
varying vec2 texcoord20;
varying vec2 texcoord22;
void main()
{
vec4 blur;
blur = texture2D(image, texcoord11);
blur += texture2D(image, texcoord00);
blur += texture2D(image, texcoord02);
blur += texture2D(image, texcoord20);
blur += texture2D(image, texcoord22);
gl_FragColor = 0.2 * blur;
}
</script>
</head>
<body>
<canvas id="main-canvas" width="400" height="300" style="border:1px solid black;"></canvas>
<canvas id="buffer-canvas" width="400" height="300" style="visibility:hidden;"></canvas>
</body>