There is some confusion e.g. in terms of support levels for rendering to floating point textures in WebGL. The OES_texture_float extension does not seem to mandate it per se, as per Optional support for FLOAT textures as FBO attachments (deprecated), but it looks like some vendors went ahead and implement it. Therefore my basic understanding is that rendering to floating point textures actually works in non-ES desktop environments. I have not been able to read from the floating point render target directly though.
My question is whether there is a way to read from a floating point texture using a WebGLContext::readPixels() call and a Float32Array destination? Thanks in advance.
Attached is a script that succeeds reading from a byte texture, but fails for a float texture:
function main() {
run_test(false);
console.log('Test passed using GL_UNSIGNED_BYTE');
run_test(true);
console.log('Test passed using GL_FLOAT');
}
function run_test(use_float) {
// Create canvas and context
var canvas = document.createElement('canvas');
document.body.appendChild(canvas);
var gl = canvas.getContext("experimental-webgl");
// Decide on types to user for texture
var texType, bufferFmt;
if (use_float) {
texType = gl.FLOAT;
bufferFmt = Float32Array;
} else {
texType = gl.UNSIGNED_BYTE;
bufferFmt = Uint8Array;
}
// Query extension
var OES_texture_float = gl.getExtension('OES_texture_float');
if (!OES_texture_float) {
throw new Error("No support for OES_texture_float");
}
// Clear
gl.viewport(0, 0, canvas.width, canvas.height);
gl.clearColor(1.0, 0.0, 0.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
// Create texture
var texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
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.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 512, 512, 0, gl.RGBA, texType, null);
// Create and attach frame buffer
var fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
gl.bindTexture(gl.TEXTURE_2D, null);
if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) {
throw new Error("gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE");
}
// Clear
gl.viewport(0, 0, 512, 512);
gl.clear(gl.COLOR_BUFFER_BIT);
var pixels = new bufferFmt(4 * 512 * 512);
gl.readPixels(0, 0, 512, 512, gl.RGBA, texType, pixels);
if (pixels[0] !== (use_float ? 1.0 : 255)) {
throw new Error("pixels[0] === " + pixels[0].toString());
}
}
The readPixels is limited to the RGBA format and the UNSIGNED_BYTE type (WebGL specification). However there are some methods for "packing" floats into RGBA/UNSIGNED_BYTE described here:
http://concord-consortium.github.io/lab/experiments/webgl-gpgpu/webgl.html