create WebGL texture out of RGBA values - javascript

I tried to do this based off of this answer. This is my code:
<canvas id='canvas' width='500' height='500' style='border: solid 1px black'></canvas>
<script>
var canvas = document.getElementById("canvas");
var gl = canvas.getContext("webgl");
var texture = gl.createTexture();
var data = new Uint8Array([128, 128, 0, 1]);
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.bindTexture(gl.TEXTURE_2D, texture);
</script>
But all I can see is a white box with a black outline.
What am I doing wrong?
Thank you!

The code you have there just creates a texture and loads it into GPU memory. So you're not actually drawing anything to the canvas.
To get that texture on screen you'll need quite a few more things. Here is your code with the rest added:
// helper function for loading shader sources
function loadShaderSource(gl, id) {
var script = document.getElementById(id);
var source = "";
var child = script.firstChild;
while (child) {
if (child.nodeType == child.TEXT_NODE) {
source += child.textContent;
}
child = child.nextSibling;
}
return source;
}
// setup an OpenGL context
var canvas = document.getElementById("canvas");
var gl = canvas.getContext("webgl");
// build the vertex shader
var vertexShaderSource = loadShaderSource(gl, "shader-vertex");
var vertexShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertexShader, vertexShaderSource);
gl.compileShader(vertexShader);
// build the fragment shader
var fragmentShaderSource = loadShaderSource(gl, "shader-fragment");
var fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragmentShader, fragmentShaderSource);
gl.compileShader(fragmentShader);
// build a shader program from the vertex and fragment shader
var shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertexShader);
gl.attachShader(shaderProgram, fragmentShader);
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
// define vertex positions
var vertexPositions = new Float32Array([
1.0, 1.0, 0, // a
-1.0, 1.0, 0, // b b----a
1.0, -1.0, 0, // c | |
-1.0, 1.0, 0, // b | |
-1.0, -1.0, 0, // d d----c
1.0, -1.0, 0 // c
]);
// send the vertex positions to the GPU
var vertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertexPositions, gl.STATIC_DRAW);
// define vertex texcoords
var vertexTexcoords = new Float32Array([
1.0, 0.0, // a
0.0, 0.0, // b
1.0, 1.0, // c
0.0, 0.0, // b
0.0, 1.0, // d
1.0, 1.0 // c
]);
// send the vertex texcoords to the GPU
var texcoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
gl.bufferData(gl.ARRAY_BUFFER, vertexTexcoords, gl.STATIC_DRAW);
// wire up the shader program to the vertex position data
var positionAttribute = gl.getAttribLocation(shaderProgram, "position");
gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer);
gl.enableVertexAttribArray(positionAttribute);
gl.vertexAttribPointer(positionAttribute, 3, gl.FLOAT, false, 0, 0);
// wire up the shader program to the vertex texcoord data
var texcoordAttribute = gl.getAttribLocation(shaderProgram, "texcoord");
gl.bindBuffer(gl.ARRAY_BUFFER, texcoordBuffer);
gl.enableVertexAttribArray(texcoordAttribute);
gl.vertexAttribPointer(texcoordAttribute, 2, gl.FLOAT, false, 0, 0);
// generate and send texture data to the GPU
var textureData = new Uint8Array([128, 128, 0, 255]);
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, textureData);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
// wire up the shader program to the texture data
var imageUniform = gl.getUniformLocation(shaderProgram, "image")
gl.uniform1i(imageUniform, 0);
// tell the GPU to draw
gl.drawArrays(gl.TRIANGLES, 0, 6);
<canvas id='canvas' width='300' height='200' style='border: solid 1px black'></canvas>
<script id="shader-vertex" type="x-shader/x-vertex">
attribute vec3 position;
attribute vec2 texcoord;
varying highp vec2 uv;
void main() {
gl_Position = vec4(position, 1);
uv = texcoord;
}
</script>
<script id="shader-fragment" type="x-shader/x-fragment">
varying highp vec2 uv;
uniform sampler2D image;
void main() {
gl_FragColor = texture2D(image, uv);
}
</script>
I realize that is a TON of info to grok so I recommend reading through some guides. A good place to start might be MDN: Getting started with WebGL.

Related

Black screen when rendering to a texture

I'm trying to do the following:
Draw the scene in a first pass to a framebuffer I've created.
Take the texture that was attached to the created framebuffer and draw that onto a plane so that it can be displayed on screen.
Do some post-processing.
Just using the default framebuffer the scene looks like this:
Currently I'm unable to get parts 1 & 2 working. All I get is a black screen. However, the plane is placed in the scene correctly (confirmed by looking at a wireframe using gl.LINE_STRIP). I'm unsure if this is due to a mistake I've made with the code, or a lack of understanding of how framebuffers work (webgl is new to me).
Here's the relevant code excerpts:
// ======== FRAMEBUFFER PHASE ======== //
const framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(
gl.TEXTURE_2D,
0,
gl.RGB,
canvas.clientWidth,
canvas.clientHeight,
0,
gl.RGB,
gl.UNSIGNED_BYTE,
null // don't fill it with pixel data just yet
);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.framebufferTexture2D(
gl.FRAMEBUFFER,
gl.COLOR_ATTACHMENT0,
gl.TEXTURE_2D,
texture,
0
);
// ======== END FRAMEBUFFER PHASE ======== //
// =========== RENDERBUFFER PHASE ============== //
const renderBuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, renderBuffer);
gl.renderbufferStorage(
gl.RENDERBUFFER,
gl.DEPTH_STENCIL,
canvas.clientWidth,
canvas.clientHeight
);
gl.framebufferRenderbuffer(
gl.FRAMEBUFFER,
gl.DEPTH_STENCIL_ATTACHMENT,
gl.RENDERBUFFER,
renderBuffer
);
// =========== END RENDERBUFFER PHASE ============== //
// =========== CHECK FRAMEBUFFER STATUS ============== //
const framebufferState = gl.checkFramebufferStatus(gl.FRAMEBUFFER);
if (framebufferState !== gl.FRAMEBUFFER_COMPLETE) {
throw new Error(
`Framebuffer status is not complete: ${framebufferState}`
);
}
// =========== END CHECK FRAMEBUFFER STATUS ============== //
// =========== FIRST PASS RENDERING ============ //
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.clearColor(0.1, 0.1, 0.1, 1.0);
gl.clear(gl.DEPTH_BUFFER_BIT | gl.COLOR_BUFFER_BIT);
gl.enable(gl.DEPTH_TEST);
// this sets up the green quad and draws it to the screen
const objectModel = setupObjectModel({
position: [100.0, -10.0, 0.0],
colour: [0.734345265462, 0.89624528765, 0.9868589658, 1.0],
gl,
canvas,
});
objectModel.draw({
shaderProgram: mainShaderProgram,
camera: updatedCamera,
currentTime,
deltaTime,
});
// =========== END FIRST PASS RENDERING ============ //
// =========== SECOND PASS RENDERING ============ //
// back to rendering with the default framebuffer
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.disable(gl.DEPTH_TEST);
gl.useProgram(frameBufferShaderProgram);
// prettier-ignore
const verts = [
// positions // texCoords
-1.0, 1.0, 0.0, 1.0,
-1.0, -1.0, 0.0, 0.0,
1.0, -1.0, 1.0, 0.0,
-1.0, 1.0, 0.0, 1.0,
1.0, -1.0, 1.0, 0.0,
1.0, 1.0, 1.0, 1.0
];
// prettier-ignore-end
const screenQuad = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, screenQuad);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(verts), gl.STATIC_DRAW);
const aPosAttributeLocation = gl.getAttribLocation(
frameBufferShaderProgram,
"aPos"
);
gl.enableVertexAttribArray(aPosAttributeLocation);
gl.vertexAttribPointer(
aPosAttributeLocation,
2,
gl.FLOAT,
false,
Float32Array.BYTES_PER_ELEMENT * 4,
0
);
const aTexCoordsAttributeLocation = gl.getAttribLocation(
frameBufferShaderProgram,
"aTexCoords"
);
gl.enableVertexAttribArray(aTexCoordsAttributeLocation);
gl.vertexAttribPointer(
aTexCoordsAttributeLocation,
2,
gl.FLOAT,
false,
Float32Array.BYTES_PER_ELEMENT * 4,
Float32Array.BYTES_PER_ELEMENT * 2
);
const screenTexture = gl.getUniformLocation(
frameBufferShaderProgram,
"screenTexture"
);
gl.uniform1i(screenTexture, 0);
gl.drawArrays(gl.TRIANGLES, 0, 6);
And here is the framebuffer shader program:
// vertex shader
precision mediump float;
attribute vec2 aPos;
attribute vec2 aTexCoords;
varying vec2 TexCoords;
void main() {
gl_Position = vec4(aPos.x, aPos.y, 0.0, 1.0);
TexCoords = aTexCoords;
}
// fragment shader
precision mediump float;
uniform sampler2D screenTexture;
varying vec2 TexCoords;
void main() {
// the texture coordinates are fine here, it's the screen texture that's the issue
gl_FragColor = texture2D(screenTexture, TexCoords.xy);
}
This is a common mistake. WebGL 1.0 is base on OpenGL ES 2.0. The same rules apply to texture framebuffer attachments as to mipmaps. The size of a framebuffer texture must be a power of 2. See Texture Completeness and Non-Power-Of-Two Textures.
Create a framebuffer with a size equal to a power of 2 (e.g. 1024x1024):
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
// [...]
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1024, 1024, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
// [...]
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_STENCIL, 1024, 1024);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_STENCIL_ATTACHMENT, gl.RENDERBUFFER, renderBuffer);
// [...]
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.viewport(0, 0, 1024, 1024);
// [...]
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.viewport(0, 0, canvas.clientWidth, canvas.clientHeight,);
// [...]

WebGL: Rendering two objects with separate textures

I am currently working on a simple project in WebGL that requires rendering multiple 2D objects with a simple image textured on. The actual project generates a random number of objects, usually between 5 and 9, sets vertex data for them around the canvas to separate them, and is supposed to render, however it will only render one at a time (usually the last but I can change around gl.activeTexture to show other objects in the array). I tried to use a question on here about texture arrays in the shader, but to no avail, so I ended up creating a very simple test program that just tries to load two objects and textures, one on the left of the canvas and the other on the right.
From here I tried to do everything completely separate, even giving each object their own shaders, programs, buffers and everything, and subsequently binding everything in the draw call for each before calling gl.drawElements for each. This still doesn't show me the correct result, only the second texture appears, however it did lead me to discover what I believe to be happening. By commenting out the bindings and draw call for the second one, the first texture shows up, however it appears at the location of the second texture, not where it's vertices should be placing it. So, I assume what is happening in this program (and my project code) is that it is in fact drawing both, but for some reason applying the vertices of the last drawn one to all of them, thus stacking them and only showing the top (or last drawn one).
I have also tried a mishmash of tweaks to the below code, using only one program, using the same indices, texture coordinates, there are some commented out lines from trying to make calls in different orders as well. Anything commented out doesn't mean I necessarily think it is wrong or right, just from various things I've aimlessly tried at this point.
I have worked with OpenGL a little and had little to no trouble drawing multiple objects with their own textures, and I know that WebGL works differently than OpenGL in some ways including textures, but I do not see where I am creating the issue. I'm sure it is something very simple, and any guidance would be greatly appreciated.
I apologize for the long block of code, it's pretty much just straight typing everything out that I believe to be needed without trying to take any shortcuts. The initShaders call is from the WebGL js files I'm using from my textbook and isn't something I've written, and the loadImage call just simply loads an <img> from the html code. There are no issues with the images being loaded correctly as far as I can tell. I only included the first vertex and fragment shader because the other two are the same save for the id.
<script id="vertex-shader1" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec2 vTexCoord;
varying vec2 fTexCoord;
void main() {
fTexCoord = vTexCoord;
gl_Position = vPosition;
}
</script>
<script id="fragment-shader1" type="x-shader/x-fragment">
precision mediump float;
varying vec2 fTexCoord;
uniform sampler2D texture;
void main() {
gl_FragColor = texture2D(texture, fTexCoord);
}
</script>
"use-strict"
var gl;
var images = [];
var program1;
var program2;
var texture1;
var texture2;
var vBuff1;
var vBuff2;
var iBuff1;
var iBuff2;
var tBuff1;
var tBuff2;
var vPos1;
var vPos2;
var fTexCoord1;
var fTexCoord2;
var sampler1;
var sampler2;
var vertices1 = [
vec4(-0.8, 0.1, 0.0, 1.0),
vec4(-0.8, 0.3, 0.0, 1.0),
vec4(-0.6, 0.3, 0.0, 1.0),
vec4(-0.6, 0.1, 0.0, 1.0)
];
var vertices2 = [
vec4(0.1, 0.1, 0.0, 1.0),
vec4(0.1, 0.3, 0.0, 1.0),
vec4(0.3, 0.3, 0.0, 1.0),
vec4(0.3, 0.1, 0.0, 1.0)
];
var indices1 = [
0, 1, 2,
0, 2, 3
];
var indices2 = [
0, 1, 2,
0, 2, 3
];
var tcs1 = [
vec2(0, 0),
vec2(0, 1),
vec2(1, 1),
vec2(1, 0)
];
var tcs2 = [
vec2(0, 0),
vec2(0, 1),
vec2(1, 1),
vec2(1, 0)
];
window.onload = function init() {
var canvas = document.getElementById("gl-canvas");
gl = WebGLUtils.setupWebGL(canvas);
if (!gl) { alert("WebGL isn't available"); }
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
loadImages();
program1 = initShaders(gl, "vertex-shader1", "fragment-shader1");
gl.useProgram(program1);
vBuff1 = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vBuff1);
gl.bufferData(gl.ARRAY_BUFFER, flatten(vertices1), gl.STATIC_DRAW);
vPos1 = gl.getAttribLocation(program1, "vPosition");
gl.vertexAttribPointer(vPos1, 4, gl.FLOAT, false, 0, 0);
//gl.enableVertexAttribArray(vPos1);
iBuff1 = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, iBuff1);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(indices1), gl.STATIC_DRAW);
tBuff1 = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, tBuff1);
gl.bufferData(gl.ARRAY_BUFFER, flatten(tcs1), gl.STATIC_DRAW);
fTexCoord1 = gl.getAttribLocation(program1, "vTexCoord");
gl.vertexAttribPointer(fTexCoord1, 2, gl.FLOAT, false, 0, 0);
//gl.enableVertexAttribArray(fTexCoord1);
sampler1 = gl.getUniformLocation(program1, "texture");
texture1 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture1);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, images[0]);
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.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.bindTexture(gl.TEXTURE_2D, null);
///////////////////////////////////////////////////////////////////////////////////////
/*
program2 = initShaders(gl, "vertex-shader2", "fragment-shader2");
gl.useProgram(program2);
*/
vBuff2 = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vBuff2);
gl.bufferData(gl.ARRAY_BUFFER, flatten(vertices2), gl.STATIC_DRAW);
vPos2 = gl.getAttribLocation(program1, "vPosition");
gl.vertexAttribPointer(vPos2, 4, gl.FLOAT, false, 0, 0);
//gl.enableVertexAttribArray(vPos2);
iBuff2 = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, iBuff2);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(indices2), gl.STATIC_DRAW);
tBuff2 = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, tBuff2);
gl.bufferData(gl.ARRAY_BUFFER, flatten(tcs2), gl.STATIC_DRAW);
fTexCoord2 = gl.getAttribLocation(program1, "vTexCoord");
gl.vertexAttribPointer(fTexCoord2, 2, gl.FLOAT, false, 0, 0);
//gl.enableVertexAttribArray(fTexCoord2);
sampler2 = gl.getUniformLocation(program1, "texture");
texture2 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture2);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, images[1]);
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.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.bindTexture(gl.TEXTURE_2D, null);
render();
};
function render() {
gl.clear(gl.COLOR_BUFFER_BIT);
gl.useProgram(program1);
gl.bindBuffer(gl.ARRAY_BUFFER, vBuff1);
gl.enableVertexAttribArray(vPos1);
gl.enableVertexAttribArray(fTexCoord1);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture1);
gl.uniform1i(sampler1, 0);
// gl.bindBuffer(gl.ARRAY_BUFFER, vBuff1);
// gl.enableVertexAttribArray(vPos1);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, iBuff1);
gl.drawElements(gl.TRIANGLES, indices1.length, gl.UNSIGNED_BYTE, 0);
//gl.bindTexture(gl.TEXTURE_2D, null);
// gl.useProgram(program2);
gl.bindBuffer(gl.ARRAY_BUFFER,vBuff2);
gl.enableVertexAttribArray(vPos2);
gl.enableVertexAttribArray(fTexCoord2);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture2);
gl.uniform1i(sampler2, 0);
// gl.bindBuffer(gl.ARRAY_BUFFER, vBuff2);
// gl.enableVertexAttribArray(vPos2);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, iBuff2);
gl.drawElements(gl.TRIANGLES, indices2.length, gl.UNSIGNED_BYTE, 0);
requestAnimFrame(render);
}
First off AFAIK your code can't work. It calls a function loadImages and then immediately uses the images. Images load asychronously in the browser so you need to either have a callback for when the images load or else use async functions
Here is your code working. First I made a loadImage that returns a Promise. Then I made a async function called loadImages that uses that to load all the images and wait for them to load. Then I made another async function called main what first waits for loadImages and then calls init
The second issue was that in WebGL1 attributes are global state. That means you need to set them at render time not init time so the calls go gl.enableVertexAttribArray and gl.vertexAttribPointer need to happen at render time with the appropriate values for rendering the particular thing you are rendering. gl.vertexAttribPointer copies the current ARRAY_BUFFER binding to that attribute.
you might find these tutorials helpful and in particular this one about attributes and this state diagram that might help you visualize what is happening inside WebGL
"use-strict";
const vec2 = (...args) => [...args];
const vec4 = (...args) => [...args];
const flatten = a => new Float32Array(a.flat());
const WebGLUtils = {
setupWebGL: (canvas) => { return canvas.getContext('webgl'); },
};
const initShaders = (gl, vs, fs) => twgl.createProgram(gl, [vs, fs]);
const requestAnimFrame = requestAnimationFrame;
var gl;
var images = [];
var program1;
var program2;
var texture1;
var texture2;
var vBuff1;
var vBuff2;
var iBuff1;
var iBuff2;
var tBuff1;
var tBuff2;
var vPos1;
var vPos2;
var fTexCoord1;
var fTexCoord2;
var sampler1;
var sampler2;
var vertices1 = [
vec4(-0.8, 0.1, 0.0, 1.0),
vec4(-0.8, 0.3, 0.0, 1.0),
vec4(-0.6, 0.3, 0.0, 1.0),
vec4(-0.6, 0.1, 0.0, 1.0)
];
var vertices2 = [
vec4(0.1, 0.1, 0.0, 1.0),
vec4(0.1, 0.3, 0.0, 1.0),
vec4(0.3, 0.3, 0.0, 1.0),
vec4(0.3, 0.1, 0.0, 1.0)
];
var indices1 = [
0, 1, 2,
0, 2, 3
];
var indices2 = [
0, 1, 2,
0, 2, 3
];
var tcs1 = [
vec2(0, 0),
vec2(0, 1),
vec2(1, 1),
vec2(1, 0)
];
var tcs2 = [
vec2(0, 0),
vec2(0, 1),
vec2(1, 1),
vec2(1, 0)
];
function init() {
var canvas = document.getElementById("gl-canvas");
gl = WebGLUtils.setupWebGL(canvas);
if (!gl) { alert("WebGL isn't available"); }
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(0.0, 0.0, 0.0, 1.0);
program1 = initShaders(gl, "vertex-shader1", "fragment-shader1");
gl.useProgram(program1);
vBuff1 = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vBuff1);
gl.bufferData(gl.ARRAY_BUFFER, flatten(vertices1), gl.STATIC_DRAW);
vPos1 = gl.getAttribLocation(program1, "vPosition");
iBuff1 = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, iBuff1);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(indices1), gl.STATIC_DRAW);
tBuff1 = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, tBuff1);
gl.bufferData(gl.ARRAY_BUFFER, flatten(tcs1), gl.STATIC_DRAW);
fTexCoord1 = gl.getAttribLocation(program1, "vTexCoord");
sampler1 = gl.getUniformLocation(program1, "texture");
texture1 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture1);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, images[0]);
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.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.bindTexture(gl.TEXTURE_2D, null);
///////////////////////////////////////////////////////////////////////////////////////
/*
program2 = initShaders(gl, "vertex-shader2", "fragment-shader2");
gl.useProgram(program2);
*/
vBuff2 = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vBuff2);
gl.bufferData(gl.ARRAY_BUFFER, flatten(vertices2), gl.STATIC_DRAW);
vPos2 = gl.getAttribLocation(program1, "vPosition");
iBuff2 = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, iBuff2);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint8Array(indices2), gl.STATIC_DRAW);
tBuff2 = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, tBuff2);
gl.bufferData(gl.ARRAY_BUFFER, flatten(tcs2), gl.STATIC_DRAW);
fTexCoord2 = gl.getAttribLocation(program1, "vTexCoord");
gl.vertexAttribPointer(fTexCoord2, 2, gl.FLOAT, false, 0, 0);
//gl.enableVertexAttribArray(fTexCoord2);
sampler2 = gl.getUniformLocation(program1, "texture");
texture2 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture2);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, images[1]);
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.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.bindTexture(gl.TEXTURE_2D, null);
render();
};
function render() {
gl.clear(gl.COLOR_BUFFER_BIT);
gl.useProgram(program1);
gl.bindBuffer(gl.ARRAY_BUFFER, vBuff1);
gl.enableVertexAttribArray(vPos1);
gl.vertexAttribPointer(vPos1, 4, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, tBuff1);
gl.enableVertexAttribArray(fTexCoord1);
gl.vertexAttribPointer(fTexCoord1, 2, gl.FLOAT, false, 0, 0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture1);
gl.uniform1i(sampler1, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, iBuff1);
gl.drawElements(gl.TRIANGLES, indices1.length, gl.UNSIGNED_BYTE, 0);
gl.bindBuffer(gl.ARRAY_BUFFER,vBuff2);
gl.enableVertexAttribArray(vPos2);
gl.vertexAttribPointer(vPos2, 4, gl.FLOAT, false, 0, 0);
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, texture2);
gl.uniform1i(sampler2, 0);
gl.bindBuffer(gl.ARRAY_BUFFER,tBuff2);
gl.enableVertexAttribArray(fTexCoord2);
gl.vertexAttribPointer(fTexCoord2, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, iBuff2);
gl.drawElements(gl.TRIANGLES, indices2.length, gl.UNSIGNED_BYTE, 0);
requestAnimFrame(render);
}
function loadImage(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.onload = () => resolve(img);
img.onerror = reject;
img.crossOrigin = 'anonymous';
img.src = url;
});
}
async function loadImages(imgs) {
images = await Promise.all(imgs.map(loadImage));
}
async function main() {
await loadImages([
'https://webglfundamentals.org/webgl/resources/f-texture.png',
'https://webglfundamentals.org/webgl/lessons/resources/noodles-01.jpg',
]);
init();
}
main();
<script id="vertex-shader1" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec2 vTexCoord;
varying vec2 fTexCoord;
void main() {
fTexCoord = vTexCoord;
gl_Position = vPosition;
}
</script>
<script id="fragment-shader1" type="x-shader/x-fragment">
precision mediump float;
varying vec2 fTexCoord;
uniform sampler2D texture;
void main() {
gl_FragColor = texture2D(texture, fTexCoord);
}
</script>
<canvas id="gl-canvas"></canvas>
<script src="https://twgljs.org/dist/4.x/twgl.min.js"></script>

Webgl / Javascript : canvas texture content copy to another context texture object

I'm trying to copy the content (display of an image) of my first webgl context to a texture from another webgl context.
I'm using texImage2D function with a canvas element as a source, getting no errors, but it renders nothing but black.
I don't know what I'm missing, so any kind of help is greatly appreciated.
I'm looking at a webgl1 solution, and using Chrome.
var canvas1;
var texture1;
var image;
var shaderProgram;
var vertex_buffer;
var texture_buffer;
var aVertLocation;
var aTexLocation;
var vertices = [];
var texCoords = [];
var gl;
var gl2;
var canvas2;
var texture2;
var shaderProgram2;
var vertex_buffer2;
var texture_buffer2;
var index_Buffer2;
var aVertLocation2;
var aTexLocation2;
var vertices2 = [];
var texCoords2 = [];
indices = [0, 1, 2, 0, 2, 3];
vertices = [-1, -1, 1, -1, 1, 1, -1, 1];
texCoords = [0, 0, 1, 0, 1, 1, 0, 1];
function initApp()
{
initWebGL();
image = new Image();
image.onload = function(){
render();
render2();
}
image.crossOrigin = '';
image.src = 'https://i.imgur.com/ZKMnXce.png';
}
function initWebGL()
{
canvas1 = document.getElementById('glCanvas1');
gl = canvas1.getContext('webgl');
/*====================== Shaders =======================*/
// Vertex shader source code
var vertCode =
'attribute vec2 coordinates;' +
'attribute vec2 aTexCoord;' +
'varying highp vec2 vTexCoord;' +
'void main(void) {' +
'gl_Position = vec4(coordinates,1.0,1.0);' +
'vTexCoord = aTexCoord;' +
'}';
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
//fragment shader source code
var fragCode =
'uniform sampler2D texture;' +
'varying highp vec2 vTexCoord;' +
'void main(void) {' +
' gl_FragColor = texture2D(texture, vTexCoord);' +
'}';
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.deleteShader( vertShader );
gl.deleteShader( fragShader );
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
aVertLocation = gl.getAttribLocation(shaderProgram, "coordinates");
aTexLocation = gl.getAttribLocation(shaderProgram, "aTexCoord");
vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.enableVertexAttribArray(aVertLocation);
gl.vertexAttribPointer(aVertLocation, 2, gl.FLOAT, false, 0, 0);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
texture_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texture_buffer);
gl.enableVertexAttribArray(aTexLocation);
gl.vertexAttribPointer(aTexLocation, 2, gl.FLOAT, false, 0, 0);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texCoords), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
index_buffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
texture1 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture1);
gl.uniform1i( gl.getUniformLocation( shaderProgram, 'texture' ), 0 );
gl.bindTexture(gl.TEXTURE_2D, null);
//==========================================================//
canvas2 = document.getElementById('glCanvas2');
gl2 = canvas2.getContext('webgl');
var vertShader2 = gl2.createShader(gl2.VERTEX_SHADER);
var fragShader2 = gl2.createShader(gl2.FRAGMENT_SHADER);
gl2.shaderSource(vertShader2, vertCode);
gl2.shaderSource(fragShader2, fragCode);
gl2.compileShader(vertShader2);
gl2.compileShader(fragShader2);
shaderProgram2 = gl2.createProgram();
gl2.attachShader(shaderProgram2, vertShader2);
gl2.attachShader(shaderProgram2, fragShader2);
gl2.deleteShader( vertShader2 );
gl2.deleteShader( fragShader2 );
gl2.linkProgram(shaderProgram2);
gl2.useProgram(shaderProgram2);
aVertLocation2 = gl2.getAttribLocation(shaderProgram2, "coordinates");
aTexLocation2 = gl2.getAttribLocation(shaderProgram2, "aTexCoord");
vertex_buffer2 = gl2.createBuffer();
gl2.bindBuffer(gl2.ARRAY_BUFFER, vertex_buffer2);
gl2.enableVertexAttribArray(aVertLocation2);
gl2.vertexAttribPointer(aVertLocation2, 2, gl2.BYTE, false, 0, 0);
gl2.bufferData(gl2.ARRAY_BUFFER, new Float32Array(vertices), gl2.STATIC_DRAW);
gl2.bindBuffer(gl2.ARRAY_BUFFER, null);
texture_buffer2 = gl2.createBuffer();
gl2.bindBuffer(gl2.ARRAY_BUFFER, texture_buffer2);
gl2.enableVertexAttribArray(aTexLocation2);
gl2.vertexAttribPointer(aTexLocation, 2, gl2.BYTE, false, 0, 0);
gl2.bufferData(gl2.ARRAY_BUFFER, new Float32Array(texCoords), gl2.STATIC_DRAW);
gl2.bindBuffer(gl2.ARRAY_BUFFER, null);
index_buffer2 = gl2.createBuffer();
gl2.bindBuffer(gl2.ELEMENT_ARRAY_BUFFER, index_buffer2);
gl2.bufferData(gl2.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl2.STATIC_DRAW);
gl2.bindBuffer(gl2.ELEMENT_ARRAY_BUFFER, null);
texture2 = gl2.createTexture();
gl2.bindTexture(gl2.TEXTURE_2D, texture2);
gl2.uniform1i( gl2.getUniformLocation( shaderProgram2, 'texture' ), 0 );
gl2.bindTexture(gl2.TEXTURE_2D, null);
}
function updateTexture()
{
gl.bindTexture(gl.TEXTURE_2D, texture1);
gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
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.generateMipmap(gl.TEXTURE_2D);
gl.bindTexture(gl.TEXTURE_2D, null);
}
function render()
{
if ( !shaderProgram ) return;
updateTexture();
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
gl.bindTexture(gl.TEXTURE_2D, texture1);
gl.enableVertexAttribArray(aVertLocation);
gl.enableVertexAttribArray(aTexLocation);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer)
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
gl.disableVertexAttribArray(aVertLocation);
gl.disableVertexAttribArray(aTexLocation);
}
function updateTexture2()
{
gl2.bindTexture(gl2.TEXTURE_2D, texture2);
gl2.texImage2D(gl2.TEXTURE_2D, 0, gl2.RGBA, gl2.RGBA, gl2.UNSIGNED_BYTE, canvas1);
gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MAG_FILTER, gl2.LINEAR);
gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MIN_FILTER, gl2.LINEAR);
gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_WRAP_S, gl2.CLAMP_TO_EDGE);
gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_WRAP_T, gl2.CLAMP_TO_EDGE);
gl2.generateMipmap(gl2.TEXTURE_2D);
gl2.bindTexture(gl2.TEXTURE_2D, null);
}
function render2()
{
if ( !shaderProgram2 ) return;
updateTexture2();
gl2.clearColor(0.0, 0.0, 0.0, 1.0);
gl2.clear( gl2.COLOR_BUFFER_BIT | gl2.DEPTH_BUFFER_BIT );
gl2.bindTexture(gl2.TEXTURE_2D, texture2);
gl2.enableVertexAttribArray(aVertLocation2);
gl2.enableVertexAttribArray(aTexLocation2);
gl2.bindBuffer(gl2.ELEMENT_ARRAY_BUFFER, index_buffer2);
gl2.drawElements(gl2.TRIANGLES, 6, gl2.UNSIGNED_SHORT,0);
gl2.disableVertexAttribArray(aVertLocation2);
gl2.disableVertexAttribArray(aTexLocation2);
}
document.addEventListener('DOMContentLoaded', initApp);
<canvas id="glCanvas1" width="128" height="128" ></canvas>
<canvas id="glCanvas2" width="128" height="128" ></canvas>
Thanks in advance :)
The copy is working just fine. What's not working is your code 😜
Here's what I did to find the bug
First moved the code to snippet so I could actually run it. Please use snippets in the future.
Next I used an image from imgur. Because that image is on another domain I needed to set crossOrigin. Fortunately imgur supports CORS allowing WebGL to use the image. If it was me I wouldn't have used an image because that part is not important. A single colored pixel would show the issue just as well and remove the need for a image
Now that the code is running and the bug shown the first thing to do was to change this line in updateTexture2
gl2.texImage2D(gl2.TEXTURE_2D, 0, gl2.RGBA, gl2.RGBA, gl2.UNSIGNED_BYTE, canvas1);
to just use the same image
gl2.texImage2D(gl2.TEXTURE_2D, 0, gl2.RGBA, gl2.RGBA, gl2.UNSIGNED_BYTE, image);
The second canvas was still black showing the issue had nothing to with copying a canvas.
So, next I edited the fragment shader to this
gl_FragColor = vec4(1,0,0,1);
the second canvas was still black. This showed the issue had nothing to do with textures at all. The code was not drawing anything visible the second canvas.
So, looking at stuff related to the vertex shader the bug was these 2 lines
gl2.vertexAttribPointer(aVertLocation2, 2, gl2.BYTE, false, 0, 0);
...
gl2.vertexAttribPointer(aTexLocation, 2, gl2.BYTE, false, 0, 0);
needed to be gl.FLOAT not gl.BYTE
Some other random comments.
I used multi line template literals for the shaders
There's no reason to call gl.generateMips if your filtering is set not to use mips
This code has no meaning
gl.bindTexture(gl.TEXTURE_2D, texture1);
gl.uniform1i( gl.getUniformLocation( shaderProgram, 'texture' ), 0 );
gl.bindTexture(gl.TEXTURE_2D, null);
There's no reason to bind the texture here. gl.uniform1i just sets an integer value to the uniform shaderProgram. It does not record anything about the texture itself so just
gl.uniform1i( gl.getUniformLocation( shaderProgram, 'texture' ), 0 );
Without the the bindTexture calls would be fine. On top of that uniforms default to 0 so you don't really need the gl.uniform1i call. On the other hand maybe you had that their to set it to something other than 0 later.
Finally because WebGL can not share resources across canvases (at least as of July 2017), then, depending on what you're making you might want to consider using a single canvas. See the last solution in this answer
var canvas1;
var texture1;
var image;
var shaderProgram;
var vertex_buffer;
var texture_buffer;
var aVertLocation;
var aTexLocation;
var vertices = [];
var texCoords = [];
var gl;
var gl2;
var canvas2;
var texture2;
var shaderProgram2;
var vertex_buffer2;
var texture_buffer2;
var index_Buffer2;
var aVertLocation2;
var aTexLocation2;
var vertices2 = [];
var texCoords2 = [];
indices = [0, 1, 2, 0, 2, 3];
vertices = [-1, -1, 1, -1, 1, 1, -1, 1];
texCoords = [0, 0, 1, 0, 1, 1, 0, 1];
function initApp()
{
initWebGL();
image = new Image();
image.onload = function(){
render();
render2();
}
image.crossOrigin = '';
image.src = 'https://i.imgur.com/ZKMnXce.png';
}
function initWebGL()
{
canvas1 = document.getElementById('glCanvas1');
gl = canvas1.getContext('webgl');
/*====================== Shaders =======================*/
// Vertex shader source code
var vertCode = `
attribute vec2 coordinates;
attribute vec2 aTexCoord;
varying highp vec2 vTexCoord;
void main(void) {
gl_Position = vec4(coordinates,1.0,1.0);
vTexCoord = aTexCoord;
}
`;
var vertShader = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vertShader, vertCode);
gl.compileShader(vertShader);
//fragment shader source code
var fragCode = `
precision mediump float;
uniform sampler2D texture;
varying highp vec2 vTexCoord;
void main(void) {
gl_FragColor = texture2D(texture, vTexCoord);
}
`;
var fragShader = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fragShader, fragCode);
gl.compileShader(fragShader);
shaderProgram = gl.createProgram();
gl.attachShader(shaderProgram, vertShader);
gl.attachShader(shaderProgram, fragShader);
gl.deleteShader( vertShader );
gl.deleteShader( fragShader );
gl.linkProgram(shaderProgram);
gl.useProgram(shaderProgram);
aVertLocation = gl.getAttribLocation(shaderProgram, "coordinates");
aTexLocation = gl.getAttribLocation(shaderProgram, "aTexCoord");
vertex_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertex_buffer);
gl.enableVertexAttribArray(aVertLocation);
gl.vertexAttribPointer(aVertLocation, 2, gl.FLOAT, false, 0, 0);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(vertices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
texture_buffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, texture_buffer);
gl.enableVertexAttribArray(aTexLocation);
gl.vertexAttribPointer(aTexLocation, 2, gl.FLOAT, false, 0, 0);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array(texCoords), gl.STATIC_DRAW);
gl.bindBuffer(gl.ARRAY_BUFFER, null);
index_buffer = gl.createBuffer();
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer);
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
texture1 = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture1);
gl.uniform1i( gl.getUniformLocation( shaderProgram, 'texture' ), 0 );
gl.bindTexture(gl.TEXTURE_2D, null);
//==========================================================//
canvas2 = document.getElementById('glCanvas2');
gl2 = canvas2.getContext('webgl');
var vertShader2 = gl2.createShader(gl2.VERTEX_SHADER);
var fragShader2 = gl2.createShader(gl2.FRAGMENT_SHADER);
gl2.shaderSource(vertShader2, vertCode);
gl2.shaderSource(fragShader2, fragCode);
gl2.compileShader(vertShader2);
gl2.compileShader(fragShader2);
shaderProgram2 = gl2.createProgram();
gl2.attachShader(shaderProgram2, vertShader2);
gl2.attachShader(shaderProgram2, fragShader2);
gl2.deleteShader( vertShader2 );
gl2.deleteShader( fragShader2 );
gl2.linkProgram(shaderProgram2);
gl2.useProgram(shaderProgram2);
aVertLocation2 = gl2.getAttribLocation(shaderProgram2, "coordinates");
aTexLocation2 = gl2.getAttribLocation(shaderProgram2, "aTexCoord");
vertex_buffer2 = gl2.createBuffer();
gl2.bindBuffer(gl2.ARRAY_BUFFER, vertex_buffer2);
gl2.enableVertexAttribArray(aVertLocation2);
gl2.vertexAttribPointer(aVertLocation2, 2, gl2.FLOAT, false, 0, 0);
gl2.bufferData(gl2.ARRAY_BUFFER, new Float32Array(vertices), gl2.STATIC_DRAW);
gl2.bindBuffer(gl2.ARRAY_BUFFER, null);
texture_buffer2 = gl2.createBuffer();
gl2.bindBuffer(gl2.ARRAY_BUFFER, texture_buffer2);
gl2.enableVertexAttribArray(aTexLocation2);
gl2.vertexAttribPointer(aTexLocation, 2, gl2.FLOAT, false, 0, 0);
gl2.bufferData(gl2.ARRAY_BUFFER, new Float32Array(texCoords), gl2.STATIC_DRAW);
gl2.bindBuffer(gl2.ARRAY_BUFFER, null);
index_buffer2 = gl2.createBuffer();
gl2.bindBuffer(gl2.ELEMENT_ARRAY_BUFFER, index_buffer2);
gl2.bufferData(gl2.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl2.STATIC_DRAW);
gl2.bindBuffer(gl2.ELEMENT_ARRAY_BUFFER, null);
texture2 = gl2.createTexture();
gl2.bindTexture(gl2.TEXTURE_2D, texture2);
gl2.uniform1i( gl2.getUniformLocation( shaderProgram2, 'texture' ), 0 );
gl2.bindTexture(gl2.TEXTURE_2D, null);
}
function updateTexture()
{
gl.bindTexture(gl.TEXTURE_2D, texture1);
gl.pixelStorei(gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, gl.NONE);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, true);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGB, gl.RGB, gl.UNSIGNED_BYTE, image);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
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.generateMipmap(gl.TEXTURE_2D);
gl.bindTexture(gl.TEXTURE_2D, null);
}
function render()
{
if ( !shaderProgram ) return;
updateTexture();
gl.clearColor(0.0, 0.0, 0.0, 1.0);
gl.clear( gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT );
gl.bindTexture(gl.TEXTURE_2D, texture1);
gl.enableVertexAttribArray(aVertLocation);
gl.enableVertexAttribArray(aTexLocation);
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, index_buffer)
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
gl.disableVertexAttribArray(aVertLocation);
gl.disableVertexAttribArray(aTexLocation);
}
function updateTexture2()
{
gl2.bindTexture(gl2.TEXTURE_2D, texture2);
gl2.texImage2D(gl2.TEXTURE_2D, 0, gl2.RGBA, gl2.RGBA, gl2.UNSIGNED_BYTE, canvas1);
gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MAG_FILTER, gl2.LINEAR);
gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_MIN_FILTER, gl2.LINEAR);
gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_WRAP_S, gl2.CLAMP_TO_EDGE);
gl2.texParameteri(gl2.TEXTURE_2D, gl2.TEXTURE_WRAP_T, gl2.CLAMP_TO_EDGE);
gl2.generateMipmap(gl2.TEXTURE_2D);
gl2.bindTexture(gl2.TEXTURE_2D, null);
}
function render2()
{
if ( !shaderProgram2 ) return;
updateTexture2();
gl2.clearColor(0.0, 0.0, 0.0, 1.0);
gl2.clear( gl2.COLOR_BUFFER_BIT | gl2.DEPTH_BUFFER_BIT );
gl2.bindTexture(gl2.TEXTURE_2D, texture2);
gl2.enableVertexAttribArray(aVertLocation2);
gl2.enableVertexAttribArray(aTexLocation2);
gl2.bindBuffer(gl2.ELEMENT_ARRAY_BUFFER, index_buffer2);
gl2.drawElements(gl2.TRIANGLES, 6, gl2.UNSIGNED_SHORT,0);
gl2.disableVertexAttribArray(aVertLocation2);
gl2.disableVertexAttribArray(aTexLocation2);
}
document.addEventListener('DOMContentLoaded', initApp);
<canvas id="glCanvas1" width="128" height="128" ></canvas>
<canvas id="glCanvas2" width="128" height="128" ></canvas>

Why does the order of binding buffers seem to matter in a simple WebGL program?

Sorry if this is really dumb. I'm having the weirdest WebGL issue. I've written a really basic WebGL program to render a sprite.
<!DOCTYPE html>
<html lang="en">
<head><title></title>
<style>
html, body { height: 100%; margin: 0; padding: 0; overflow: hidden; }
canvas { position: absolute; top:0;left:0; cursor: none; }
</style></head><body>
<canvas id="webgltestingthing"></canvas>
<script>
var scene,gl,cursor,sh={};
var vertexShader="\
precision mediump float;\
attribute vec2 a_position;\
attribute vec2 a_texCoord;\
uniform vec2 u_resolution;\
varying vec2 v_texCoord;\
void main() {\
gl_Position = vec4(a_position/u_resolution*2.0-1.0, 0, 1);\
v_texCoord = a_texCoord;\
}";
var fragShader="\
precision mediump float;\
uniform sampler2D u_image;\
varying vec2 v_texCoord;\
void main() {\
gl_FragColor = texture2D(u_image, v_texCoord);\
}";
function resizeScene() {
document.getElementById("webgltestingthing").width = document.body.clientWidth;
document.getElementById("webgltestingthing").height = document.body.clientHeight;
if(gl) gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight); }
mouseX=-1000; mouseY=-1000;
function trackMouse(e) { e = e || window.event; mouseX=event.pageX; mouseY=event.pageY; }
function trackMouseOut() { mouseX=-1000; mouseY=-1000; }
function createShader(gl, type, source) {
var shader = gl.createShader(type);
gl.shaderSource(shader, source);
gl.compileShader(shader);
var success = gl.getShaderParameter(shader, gl.COMPILE_STATUS);
if (success) { return shader; }
console.log(gl.getShaderInfoLog(shader)); gl.deleteShader(shader); }
function createProgram(gl, vertexShader, fragmentShader) {
var program = gl.createProgram();
gl.attachShader(program, vertexShader);
gl.attachShader(program, fragmentShader);
gl.linkProgram(program);
var success = gl.getProgramParameter(program, gl.LINK_STATUS);
if (success) { return {p: program, a: {}, u: {}}; }
console.log(gl.getProgramInfoLog(program)); gl.deleteProgram(program); }
function createTexture(url,onload) {
this.img=new Image(); this.onload=onload; this.loaded=false;
this.img.src=url;
this.w=0; this.h=0; this.texture=gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, this.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);
postload=function() {
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, this.img);
this.loaded=true; this.onload(); }
this.img.addEventListener("load",postload.bind(this));
return this; }
function renderSprite(t,x,y) {
if(!t.loaded) return;
var x1=x,y1=scene.clientHeight-y,x2=x+t.img.width,y2=y1-t.img.height;
gl.activeTexture(gl.TEXTURE0);
gl.bindTexture(gl.TEXTURE_2D, t.texture);
gl.useProgram(sh.sprite.p);
gl.bindBuffer(gl.ARRAY_BUFFER, sh.sprite.a.texCoordBuffer);
gl.enableVertexAttribArray(sh.sprite.a.texCoord);
gl.vertexAttribPointer(sh.sprite.a.texCoord, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, sh.sprite.a.positionBuffer);
gl.enableVertexAttribArray(sh.sprite.a.position);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([x1, y1, x2, y1, x1, y2, x1, y2, x2, y1, x2, y2]), gl.STATIC_DRAW);
gl.vertexAttribPointer(sh.sprite.a.position, 2, gl.FLOAT, false, 0, 0);
gl.uniform2fv(sh.sprite.u.res, [scene.clientWidth, scene.clientHeight]);
gl.uniform1i(sh.sprite.u.img, 0);
gl.drawArrays(gl.TRIANGLES, 0, 6);
}
function renderStuff() {
gl.clearColor(0, 0, 0, 0);
gl.clear(gl.COLOR_BUFFER_BIT);
if(mouseX>0) renderSprite(cursor,mouseX,mouseY);
requestAnimationFrame(renderStuff);
}
(function() {
scene=document.getElementById("webgltestingthing"); resizeScene();
window.addEventListener('resize', resizeScene, true);
window.addEventListener('mousemove', trackMouse, true);
scene.addEventListener('mouseout', trackMouseOut, true);
gl=scene.getContext("experimental-webgl");
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
sh.f_sprite = createShader(gl, gl.FRAGMENT_SHADER, fragShader);
sh.v_bypixels = createShader(gl, gl.VERTEX_SHADER, vertexShader);
sh.sprite = createProgram(gl, sh.v_bypixels, sh.f_sprite);
sh.sprite.u.res = gl.getUniformLocation(sh.sprite.p, "u_resolution");
sh.sprite.u.img = gl.getUniformLocation(sh.sprite.p, 'u_image');
sh.sprite.a.position = gl.getUniformLocation(sh.sprite.p, "a_position");
sh.sprite.a.positionBuffer = gl.createBuffer();
sh.sprite.a.texCoord = gl.getUniformLocation(sh.sprite.p, "a_texCoord");
sh.sprite.a.texCoordBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, sh.sprite.a.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);
cursor=createTexture("graphics/cursor.png",function() { renderStuff(); });
})();
</script>
</body>
</html>
This displays a blank white screen. I'd hoped it would display the texture at the mouse position. There's no errors in the console or anything. Then I did some playing around and noticed something odd that I couldn't explain. I added this to my fragment shader:
if(v_texCoord==vec2(0.0,0.0)) gl_FragColor = vec4(1.0,0.0,0.0,1.0);
And indeed, it turns out the texture coordinate everywhere on the image is apparently 0.0/0.0! WebGL now correctly renders a red box in the position where the sprite is supposed to be, at the exact size of the sprite. So then my attention turned to the part where I set the buffer up to pass in the texture co-ordinate and something even weirder happened: if you swap around the code so that I set the position buffer first, like this (in the rendersprite function):
gl.bindBuffer(gl.ARRAY_BUFFER, sh.sprite.a.positionBuffer);
gl.enableVertexAttribArray(sh.sprite.a.position);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([x1, y1, x2, y1, x1, y2, x1, y2, x2, y1, x2, y2]), gl.STATIC_DRAW);
gl.vertexAttribPointer(sh.sprite.a.position, 2, gl.FLOAT, false, 0, 0);
gl.bindBuffer(gl.ARRAY_BUFFER, sh.sprite.a.texCoordBuffer);
gl.enableVertexAttribArray(sh.sprite.a.texCoord);
gl.vertexAttribPointer(sh.sprite.a.texCoord, 2, gl.FLOAT, false, 0, 0);
Now my red box isn't even there anymore! So that indicates to me that for some reason, whatever buffer I'm setting first on this simple shader is not working, but I can't see any reason why. I've tried all sorts of different ways and tried shuffling things around and such, no luck so far. I'm also confused about why the order matters at all.
Anyone have any idea?
In your setup function you're using getUniformLocation to query the attribute locations, attributes however are not uniforms and their locations need to be queried using getAttribLocation instead.
Calling getUniformLocation on the attributes returns null which is then casted to 0 in your enableVertexAttribArray and vertexAttribPointer calls, hence you're binding the vertex attributes to the same location.
sh.sprite.a.position = gl.getAttribLocation(sh.sprite.p, "a_position");
sh.sprite.a.positionBuffer = gl.createBuffer();
sh.sprite.a.texCoord = gl.getAttribLocation(sh.sprite.p, "a_texCoord");
sh.sprite.a.texCoordBuffer = gl.createBuffer();

webgl readpixels textures shader issue

I've been trying to learn some webgl, and basically have two programs where the rendered pixels get stored in a texture and then used in the other program's shader.
webgl.modTexture(gl, webgl.texture[1], webgl.frameBuffer[0]);
This will call and attempt to readpixels of a screen and put the modified data back into the texture to be used in the next program render routine.
All I get is a black screen becoming more transparent gradually, but there should be the u_image being seen also (since this is being rendered in the first program where the pixels are read with readpixels).
If I comment out the second program's rendering:
gl.useProgram(webgl.program);
gl.clearColor(0, 0.5, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 6);
Then it will just render u_image without any fading.
So I'm not sure what is the problem. Seems like maybe it isn't reading the pixels correctly? But then, why would the fading be working if that's the case? Is there something wrong with trying to use the two textures?
Hopefully someone can look at the code and see what might be the issue.
//webgl stuff
var webgl = new webglData();
function webglData(){
this.then = 0; //used for deltatime in rendering
this.request; //requestanimationframe, used when stopping/starting
this.canvas;
this.context;
this.div;
this.program;
this.cellProgram;
this.texture = [];
this.frameBuffer = [];
this.cellVShader = `
attribute vec2 aVertexPosition;
attribute vec2 a_position;
attribute vec2 a_texCoord;
uniform vec2 u_resolution;
varying vec2 v_texCoord;
varying vec2 v_NW;
varying vec2 v_N;
varying vec2 v_NE;
varying vec2 v_W;
varying vec2 v_E;
varying vec2 v_SW;
varying vec2 v_S;
varying vec2 v_SE;
vec2 getOffset( int x, int y){
vec2 v = floor(a_texCoord * u_resolution);
v.x += float(x), v.y += float(y);
v /= u_resolution;
return v;
}
void main() {
//v_texCoord = a_texCoord;
//gl_Position = vec4(aVertexPosition, 0.0, 1.0);
// convert the rectangle from pixels to 0.0 to 1.0
vec2 zeroToOne = a_position / u_resolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
// pass the texCoord to the fragment shader
// The GPU will interpolate this value between points.
v_texCoord = a_texCoord;
v_NW = getOffset( -1, 1);
v_N = getOffset( 0, 1);
v_NE = getOffset( 1, 1);
v_W = getOffset( -1, 0);
v_E = getOffset( 1, 0);
v_SW = getOffset( -1, -1);
v_S = getOffset( 0, -1);
v_SE = getOffset( 1, -1);
}
`;
this.cellFShader = `
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D u_canvas1;
uniform vec4 uColor;
// our texture
uniform sampler2D u_before;
uniform sampler2D u_after;
uniform sampler2D u_image;
// the texCoords passed in from the vertex shader.
varying vec2 v_texCoord;
varying vec2 v_NW;
varying vec2 v_N;
varying vec2 v_NE;
varying vec2 v_W;
varying vec2 v_E;
varying vec2 v_SW;
varying vec2 v_S;
varying vec2 v_SE;
void main() {
// Look up a color from the texture.
gl_FragColor = texture2D(u_image, v_W);
//gl_FragColor = uColor;
}
`;
this.vertexShader = `
attribute vec2 aVertexPosition;
attribute vec2 a_position;
attribute vec2 a_texCoord;
uniform vec2 u_resolution;
varying vec2 v_texCoord;
void main() {
//v_texCoord = a_texCoord;
//gl_Position = vec4(aVertexPosition, 0.0, 1.0);
// convert the rectangle from pixels to 0.0 to 1.0
vec2 zeroToOne = a_position / u_resolution;
// convert from 0->1 to 0->2
vec2 zeroToTwo = zeroToOne * 2.0;
// convert from 0->2 to -1->+1 (clipspace)
vec2 clipSpace = zeroToTwo - 1.0;
gl_Position = vec4(clipSpace * vec2(1, -1), 0, 1);
// pass the texCoord to the fragment shader
// The GPU will interpolate this value between points.
v_texCoord = a_texCoord;
}
`;
this.fragmentShader = `
#ifdef GL_ES
precision highp float;
#endif
uniform sampler2D u_canvas1;
uniform vec4 uColor;
// our texture
uniform sampler2D u_before;
uniform sampler2D u_after;
uniform sampler2D u_image;
// the texCoords passed in from the vertex shader.
varying vec2 v_texCoord;
void main() {
// Look up a color from the texture.
gl_FragColor = texture2D(u_before, v_texCoord);
//gl_FragColor = uColor;
}
`;
this.init = function(){
this.div = innerDoc.getElementById('webglDiv');
gui.Window.get().showDevTools();
this.canvas = document.createElement('canvas');
this.context = this.canvas.getContext("experimental-webgl");
this.canvas.width = 512;
this.canvas.height = 512;
this.canvas.style.position = 'absolute';
this.canvas.style.zIndex = -1;
this.canvas.style.pointerEvents = 'none';
this.div.appendChild(this.canvas);
if(!this.context)return;
var gl = this.context;
gl.viewport(0, 0, this.canvas.width, this.canvas.height);
gl.clearColor(0, 0.5, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
//compile the shaders and create the program for webgl
var vs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(vs, this.vertexShader);
gl.compileShader(vs);
var fs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(fs, this.fragmentShader);
gl.compileShader(fs);
var cvs = gl.createShader(gl.VERTEX_SHADER);
gl.shaderSource(cvs, this.cellVShader);
gl.compileShader(cvs);
var cfs = gl.createShader(gl.FRAGMENT_SHADER);
gl.shaderSource(cfs, this.cellFShader);
gl.compileShader(cfs);
this.program = gl.createProgram();
gl.attachShader(this.program, vs);
gl.attachShader(this.program, fs);
gl.linkProgram(this.program);
//gl.useProgram(this.program);
this.cellProgram = gl.createProgram();
gl.attachShader(this.cellProgram, cvs);
gl.attachShader(this.cellProgram, cfs);
gl.linkProgram(this.cellProgram);
//gl.useProgram(this.cellProgram);
//output any errors
if (!gl.getShaderParameter(vs, gl.COMPILE_STATUS))console.log(gl.getShaderInfoLog(vs));
if (!gl.getShaderParameter(fs, gl.COMPILE_STATUS))console.log(gl.getShaderInfoLog(fs));
if (!gl.getProgramParameter(this.program, gl.LINK_STATUS))console.log(gl.getProgramInfoLog(this.program));
if (!gl.getShaderParameter(cvs, gl.COMPILE_STATUS))console.log(gl.getShaderInfoLog(cvs));
if (!gl.getShaderParameter(cfs, gl.COMPILE_STATUS))console.log(gl.getShaderInfoLog(cfs));
if (!gl.getProgramParameter(this.cellProgram, gl.LINK_STATUS))console.log(gl.getProgramInfoLog(this.cellProgram));
this.setupStuff(gl, this.program);
this.setupStuff(gl, this.cellProgram);
this.texture.push( this.setupTexture(tool.canvas, 0, "u_image") );
this.texture.push( this.createBlankTexture(gl, tool.canvas.width*tool.canvas.height*4, gl.RGBA, tool.canvas.width, tool.canvas.height, "u_before") );
this.texture.push( this.createBlankTexture(gl, tool.canvas.width*tool.canvas.height*4, gl.RGBA, tool.canvas.width, tool.canvas.height, "u_after") );
this.frameBuffer.push( gl.createFramebuffer() );
this.request = requestAnimationFrame(this.render);
}
this.render = function(now){
if(!webgl.context || config.tab!='scene'){cancelAnimationFrame(webgl.request); return;}
var gl = webgl.context;
// Convert the time to seconds
now *= 0.001;
// Subtract the previous time from the current time
var deltaTime = now - webgl.then;
// Remember the current time for the next frame.
webgl.then = now;
gl.useProgram(webgl.cellProgram);
gl.drawArrays(gl.TRIANGLES, 0, 6);
webgl.modTexture(gl, webgl.texture[1], webgl.frameBuffer[0]);
gl.useProgram(webgl.program);
gl.clearColor(0, 0.5, 0, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 6);
this.request = requestAnimationFrame(webgl.render);
}
this.setupStuff = function(gl, program){
gl.useProgram(program);
// look up where the vertex data needs to go.
var positionLocation = gl.getAttribLocation(program, "a_position");
var texCoordLocation = gl.getAttribLocation(program, "a_texCoord");
// provide texture coordinates for the rectangle.
//this will be what the texture gets displayed on?
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);
// lookup uniforms
var resolutionLocation = gl.getUniformLocation(program, "u_resolution");
// set the resolution
gl.uniform2f(resolutionLocation, this.canvas.width, this.canvas.height);
// Create a buffer for the position of the rectangle corners.
// store the data for the texture coordinates that were defined above, into the a_position?
var buffer = gl.createBuffer();
//this.frameBuffer.push(buffer);
gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
gl.enableVertexAttribArray(positionLocation);
gl.vertexAttribPointer(positionLocation, 2, gl.FLOAT, false, 0, 0);
// Set a rectangle the same size as the image.
//I guess this adjusts the buffer data that was just created?
this.setRectangle(gl, 0, 0, this.canvas.width, this.canvas.height);
//var tex2 = setupTexture(canvas2, 1, program, "u_canvas2");
// Draw the rectangle.
//gl.drawArrays(gl.TRIANGLES, 0, 6);
//gl.drawArrays(gl.TRIANGLES, 0, numItems);
}
this.refreshTexture = function(){
if(!this.context)return;
var gl = this.context;
gl.activeTexture(gl.TEXTURE0 + 0);
gl.bindTexture(gl.TEXTURE_2D, this.texture[0]);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, tool.canvas);
//gl.drawArrays(gl.TRIANGLES, 0, 6);
}
this.modTexture = function(gl, sTexture, framebuffer){
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, sTexture, 0);
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE)
{
var sTextureSize = sTexture.width * sTexture.height * 4; // r, g, b, a
var pixels = new Uint8Array( sTextureSize );
gl.readPixels( 0, 0, sTexture.width, sTexture.height, gl.RGBA, gl.UNSIGNED_BYTE, pixels );
for( var i=0 ; i<sTextureSize ; i+=4 )
{
if( pixels[i+3] > 0 )
{
pixels[i+3] = Math.min( 255, pixels[i+3]*0.995 ); // set half alpha
}
}
// upload changes
gl.activeTexture(gl.TEXTURE0 + 1);
gl.bindTexture(gl.TEXTURE_2D, sTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,
sTexture.width, sTexture.height, 0,
gl.RGBA, gl.UNSIGNED_BYTE, pixels);
}
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
}
this.setupFrameBuffer = function(canvas, textureUnit, program, uniformName) {
if(!this.context)return;
var gl = this.context;
var rttFramebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, rttFramebuffer);
rttFramebuffer.width = this.canvas.width;
rttFramebuffer.height = this.canvas.height;
var rttTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, rttTexture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_NEAREST);
gl.generateMipmap(gl.TEXTURE_2D);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, rttFramebuffer.width, rttFramebuffer.height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, rttTexture, 0);
gl.bindTexture(gl.TEXTURE_2D, null);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
return rttFrameBuffer;
}
this.setupTexture = function(canvas, textureUnit, uniformName) {
var gl = this.context;
var tex = gl.createTexture();
this.updateTextureFromCanvas(tex, canvas, textureUnit);
tex.width = canvas.width;
tex.height= canvas.height;
// Set the parameters so we can render any size image.
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.useProgram(this.program);
var location = gl.getUniformLocation(this.program, uniformName);
gl.uniform1i(location, textureUnit);
gl.useProgram(this.cellProgram);
location = gl.getUniformLocation(this.cellProgram, uniformName);
gl.uniform1i(location, textureUnit);
return tex;
}
this.updateTextureFromCanvas = function(tex, canvas, textureUnit) {
if(!this.context)return;
var gl = this.context;
gl.activeTexture(gl.TEXTURE0 + textureUnit);
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas);
}
this.createBlankTexture = function(gl, dataArray, type, width, height, uniformName) {
var dataTypedArray = new Uint8Array(dataArray); // Don't need to do this if the data is already in a typed array
for( var i=0 ; i<dataArray ; i+=4 )
{
dataTypedArray[i+3] = 255;
}
var texture = gl.createTexture();
texture.width = width;
texture.height= height;
gl.activeTexture(gl.TEXTURE0 + this.texture.length);
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texImage2D(gl.TEXTURE_2D, 0, type, width, height, 0, type, gl.UNSIGNED_BYTE, dataTypedArray);
// Other texture setup here, like filter modes and mipmap generation
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.useProgram(this.program);
var location = gl.getUniformLocation(this.program, uniformName);
gl.uniform1i(location, this.texture.length);
gl.useProgram(this.cellProgram);
location = gl.getUniformLocation(this.cellProgram, uniformName);
gl.uniform1i(location, this.texture.length);
return texture;
}
this.setRectangle = function(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);
}
}
Okay I managed to get things working.
I had to learn what exactly needs to be called at different stages:
Do I have to create separate buffers per webgl program?
And I had to change the part with the framebuffer to use a different texture than the one it is putting the data into.
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, sTexture, 0);
gl.activeTexture(gl.TEXTURE0 + 1);
gl.bindTexture(gl.TEXTURE_2D, sTexture);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA,
sTexture.width, sTexture.height, 0,
gl.RGBA, gl.UNSIGNED_BYTE, pixels);
so the sTexture needs to change like so:
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, someOtherTexture, 0);

Categories