Webgl / improve reading of render targets data

Now two methods are available: `readAll` and `readPixel`,
and the data from the render target is not re-read every time unless
`clearCachedData` is called.
This commit is contained in:
Olivier Guyot
2019-06-06 10:21:00 +02:00
parent 917950a32b
commit e852294938
2 changed files with 107 additions and 20 deletions

View File

@@ -4,6 +4,8 @@
*/
import {equals} from '../array.js';
// for pixel color reading
const tmpArray4 = new Uint8Array(4);
/**
* @classdesc
@@ -47,7 +49,13 @@ class WebGLRenderTarget {
* @type {Uint8Array}
* @private
*/
this.data_ = new Uint8Array(1);
this.data_ = new Uint8Array(0);
/**
* @type {boolean}
* @private
*/
this.dataCacheDirty_ = true;
this.updateSize_();
}
@@ -77,19 +85,50 @@ class WebGLRenderTarget {
}
/**
* Returns the content of the render target texture as raw data (series of r,g,b,a values)
* This will cause following calls to `#readAll` or `#readPixel` to download the content of the
* render target into memory, which is an expensive operation.
* This content will be kept in cache but should be cleared after each new render.
* @api
*/
clearCachedData() {
this.dataCacheDirty_ = true;
}
/**
* Returns the full content of the frame buffer as a series of r, g, b, a components
* in the 0-255 range (unsigned byte).
* @return {Uint8Array} Integer array of color values
* @api
*/
read() {
const size = this.size_;
const gl = this.helper_.getGL();
readAll() {
if (this.dataCacheDirty_) {
const size = this.size_;
const gl = this.helper_.getGL();
gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer_);
gl.readPixels(0, 0, size[0], size[1], gl.RGBA, gl.UNSIGNED_BYTE, this.data_);
gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer_);
gl.readPixels(0, 0, size[0], size[1], gl.RGBA, gl.UNSIGNED_BYTE, this.data_);
this.dataCacheDirty_ = false;
}
return this.data_;
}
/**
* Reads one pixel of the frame buffer as an array of r, g, b, a components
* in the 0-255 range (unsigned byte).
* @param {number} x Pixel coordinate
* @param {number} y Pixel coordinate
* @returns {Uint8Array} Integer array with one color value (4 components)
*/
readPixel(x, y) {
this.readAll();
const index = Math.floor(x) + (this.size_[1] - Math.floor(y) - 1) * this.size_[0];
tmpArray4[0] = this.data_[index * 4];
tmpArray4[1] = this.data_[index * 4 + 1];
tmpArray4[2] = this.data_[index * 4 + 2];
tmpArray4[3] = this.data_[index * 4 + 3];
return tmpArray4;
}
/**
* @return {WebGLTexture} Texture to render to
*/