WebGL many textures

356 Views Asked by At

I am working with image processing in WebGL and have come across a problem I can't seem to solve. I haven't worked much with GL and I have a feeling I am misunderstanding something fundamental and simple.

My goal is to simulate layers. Initially I setup each layer using different contexts and then compiled each into a final rendered canvas but creating a texture from the canvas each render was slow. Next I used a Uint8Array for each layer which contains the image data and that was much faster but lead to the problem I have now.

The problem is when I add more than 8 layers. If I have 8 layers and add another the first layer seems to be emptied - the layer becomes blank. I tried changing from Uint8Array to using a texture for each layer but the problem still persists.

I can provide some code snippets if needed but there is a lot of code across multiple files and it's a bit of a mess as I've been trying to solve this. The layers are compiled using two framebuffers to draw back and forth to and a shader handles the math.

Eight layers, rendering properly: Eight Layers

Nine layers, breaks things: Nine Layers

Edit: Here is some code and I forgot to mention I am using the helper library twgl.

First I setup the layer texture:

this.renderTexture = twgl.createTexture(gl, {
    width: this.width,
    height: this.height,
    target: gl.TEXTURE_2D,
    min: gl.NEAREST,
    max: gl.NEAREST,
    wrap: gl.CLAMP_TO_EDGE
});

I draw something (like an image) to framebuffer and then update the appropriate layer's texture:

gl.readPixels(0, 0, this.width, this.height, gl.RGBA, gl.UNSIGNED_BYTE, this.buf8);

twgl.setTextureFromArray(gl, this.renderTexture, this.buf8, {
    width: this.width,
    height: this.height
});

And last I render each layer into one:

// create two buffers to ping pong
var blendedFramebufferInfo = [
    twgl.createFramebufferInfo(gl, [{
        src: $this.layers.length === 1 ? null : bottomLayer.buf8,
        width: gl.canvas.width,
        height: gl.canvas.height,
        target: gl.TEXTURE_2D,
        format: gl.RGBA,
        min: gl.NEAREST,
        max: gl.NEAREST,
        wrap: gl.CLAMP_TO_EDGE
    }], gl.canvas.width, gl.canvas.height),

    twgl.createFramebufferInfo(gl, [{
        width: gl.canvas.width,
        height: gl.canvas.height,
        target: gl.TEXTURE_2D,
        format: gl.RGBA,
        min: gl.NEAREST,
        max: gl.NEAREST,
        wrap: gl.CLAMP_TO_EDGE
    }], gl.canvas.width, gl.canvas.height)
];

var layers = [...],
    activeBuffer = 1;

while (layer = layers.shift()) {
    // bind to either buffer or canvas
    twgl.bindFramebufferInfo(gl, layers.length ? blendedFramebufferInfo[activeBuffer] : null);

    // set proper program
    var programInfo = $this.setBlendProgram(layer.blendMode());

    // set uniforms
    twgl.setUniforms(programInfo, {
        u_dst: blendedFramebufferInfo[activeBuffer ? 0 : 1].attachments[0],
        u_src: layer.renderTexture
    });
    // draw
    gl.drawArrays(gl.TRIANGLES, 0, 6);

    // draw to other texture next time around
    activeBuffer = activeBuffer ? 0 : 1;
}
0

There are 0 best solutions below