Search code examples
javascriptwebglframebufferglteximage2dwebgl2

Getting the 'red' pixel value of the texture drawn using gl.texImage2D


I am sending a Float32array to my fragment shader using texture ( the goal here is to sent a data to the shader using textures, process this data in the shader then send it back to javascript). Since my data is not actually an image, I decided to send it by 'gl.R32F', and I am trying to read this data after processing using gl.readPixels. Here is my code, as an example, without processing the data yet, firstly I am trying to find a way to send the data back to javascript;

var canvas = document.getElementById('webgl-canvas');
var bbb = 4096*4096;
var widthcanvas = Math.sqrt(bbb)
canvas.width = widthcanvas;
canvas.height = widthcanvas;
var gl = initGL(canvas);

var boxVertices = new Float32Array([
    -1.0,  1.0,  0, 0, 
    -1.0, -1.0,  0, 1,
     1.0,  1.0,  1, 0,
     1.0, -1.0,  1, 1
]);
var boxVertexBuffer = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, boxVertexBuffer);
gl.bufferData(gl.ARRAY_BUFFER, boxVertices, gl.STATIC_DRAW);
var boxTexture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, boxTexture);

gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
gl.texParameterf(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);


var data= new Float32Array(bbb);
for(var i = 0; i < bbb; i++) {
    data[i] = -i;
}

gl.texImage2D(gl.TEXTURE_2D, 0, gl.R32F, widthcanvas, widthcanvas, 0, gl.RED, gl.FLOAT, data);
gl.bindTexture(gl.TEXTURE_2D, null);

var a_position = gl.getAttribLocation(shaderProgram, 'a_position');
var a_textCoords = gl.getAttribLocation(shaderProgram, 'a_textCoords');

gl.vertexAttribPointer  (a_position, 2, gl.FLOAT, gl.FALSE, 4 * Float32Array.BYTES_PER_ELEMENT, 0);
gl.vertexAttribPointer(a_textCoords, 2, gl.FLOAT, gl.FALSE, 4 * Float32Array.BYTES_PER_ELEMENT, 2 * Float32Array.BYTES_PER_ELEMENT);



gl.enableVertexAttribArray(a_position);

gl.clearColor(0.75, 0.85, 0.8, 1.0);
gl.viewport(0, 0, gl.viewportWidth, gl.viewportHeight);
gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT);

gl.bindTexture(gl.TEXTURE_2D, boxTexture);
gl.activeTexture(gl.TEXTURE0);
gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);

var framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, boxTexture, 0);

var pixels = new Float32Array(gl.drawingBufferWidth * gl.drawingBufferHeight);
gl.readPixels(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight, gl.RED, gl.FLOAT, pixels);
console.log(pixels);
gl.deleteFramebuffer(framebuffer);

I am not getting any error when I try to write the data as texture ( Although I do not know whether or not the data was sent without any change, since, I cannot read it back ). However when I am trying to read it back using gl.readPixels, I get the following error,

ERROR :GL_INVALID_FRAMEBUFFER_OPERATION : glReadPixels: framebuffer incomplete

So, my question is this;

  1. If the way I send the data using texture is correct, and my data is not changed during this process, how can I send it back to JavaScript?
  2. If the way I send the data is wrong, how can I achieve my goal?

If you could help me with this problem, I would be grateful. Thank you.

P.s: The data won't always be a perfect square.


Solution

  • pleup was right. R32F need an extension to become color-renderable. When I added the following into my code, everything worked fine,

    var ext = gl.getExtension('EXT_color_buffer_float');
    

    Thank you again for the answer.