[SOLVED] Extract pixels data from DataTexture

In my scene, I have a div element to delimit a zone that I would like to transform as a texture.
By using copyFramebufferToTexture(startPosition, myDataTexture), I can extract a subpart of my scene.
Then I would like to use this texture as image in canvas in order to export it later.

webglRenderer.render(scene.ThreeScene, camera);
var dpr = window.devicePixelRatio;
var textureWidth = targetElement.clientWidth * dpr;
var textureHeight = targetElement.clientHeight * dpr;
var data = new Uint8Array(textureWidth * textureHeight * 3);
var texture = new THREE.DataTexture(data, textureWidth, textureHeight, THREE.RGBFormat);
texture.minFilter = THREE.NearestFilter;
texture.magFilter = THREE.NearestFilter;
texture.needsUpdate = true;
var startPosition = new THREE.Vector2();
startPosition.x = targetElement.offsetLeft;
startPosition.y = webglRenderer.getSize().height - targetElement.offsetTop - textureHeight;
webglRenderer.copyFramebufferToTexture(startPosition, texture);

From the code above, I can have my DataTexture and can give it to a mesh as a texture.
But I want to use it directly and when I check texture.image.data, my array contain only 0 value.

So can’t I use directly pixels value from my DataTexture?

Unfortunately, you can’t access the pixel data in this way. It’s important to understand that the actual data are stored on the GPU. texture.image.data represents CPU memory. The data are not automatically transferred from the GPU to the CPU.

You can try to render your data texture as a full screen quad and then copy the current data of your canvas (renderer.domElement) to a different canvas. This approach is demonstrated in the following example:

https://threejs.org/examples/webgl_multiple_canvases_grid.html

The interesting part is the beneath code section where context represent the 2D drawing context of the other canvas element.

context.drawImage( renderer.domElement, 0, 0 );
3 Likes

I use another solution (may be I did not well express my issue).
Instead of copy texture from framebuffer, I read directly pixels by using gl.readPixels and extract my targeted zone. This avoids me to create a DataTexture.
This is my solution:

    var gl = webglRenderer.context;
    var pixels = new Uint8Array(textureWidth * textureHeight * 4);
    gl.readPixels(startPosition.x, startPosition.y, textureWidth, textureHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
    console.log(pixels); // Uint8Array
    toImageData(pixels, textureWidth, textureHeight).then(function(bitmap) {
        //draw image to canvas
        var canvas = document.createElement('canvas');
        canvas.width = bitmap.width;
        canvas.height = bitmap.height;
        var context = canvas.getContext('2d');
        context.drawImage(bitmap, 0, 0);
        //extract image from canvas
        var img = new Image();
        img.src = canvas.toDataURL();;
        document.body.appendChild(img);
    });
    function toImageData(pixels, w, h) {
    var image = new ImageData(w, h);
    //copy texture data to Image data where format is RGBA
    var size = w * h * 4;
    for (var i = 0; i < size; i++) {
        image.data[i] = pixels[i];
    }
    return createImageBitmap(image);
}