对于WebGL中渲染到浮点纹理的支持级别,存在一些混淆e.g.。根据{{3}},OES_texture_float扩展似乎并不强制要求它,但看起来有些供应商继续实施它。因此,我的基本理解是渲染到浮点纹理实际上可以在非ES桌面环境中工作。我无法直接从浮点渲染目标中读取。
我的问题是,是否有办法使用WebGLContext :: readPixels()调用和Float32Array目标读取浮点纹理?提前谢谢。
附件是一个成功读取字节纹理的脚本,但是浮动纹理失败:
<html>
<head>
<script>
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());
}
}
function main() {
run_test(false);
console.log('Test passed using GL_UNSIGNED_BYTE');
run_test(true);
console.log('Test passed using GL_FLOAT');
}
</script>
</head>
<body onload='main()'>
</body>
</html>
答案 0 :(得分:11)
不幸的是,将RGBA组件作为字节读出似乎仍然是WebGL的唯一方法。如果需要将浮点数编码为像素值,可以使用以下命令:
在你的分形着色器(GLSL / HLSL)中:
float shift_right (float v, float amt) {
v = floor(v) + 0.5;
return floor(v / exp2(amt));
}
float shift_left (float v, float amt) {
return floor(v * exp2(amt) + 0.5);
}
float mask_last (float v, float bits) {
return mod(v, shift_left(1.0, bits));
}
float extract_bits (float num, float from, float to) {
from = floor(from + 0.5); to = floor(to + 0.5);
return mask_last(shift_right(num, from), to - from);
}
vec4 encode_float (float val) {
if (val == 0.0) return vec4(0, 0, 0, 0);
float sign = val > 0.0 ? 0.0 : 1.0;
val = abs(val);
float exponent = floor(log2(val));
float biased_exponent = exponent + 127.0;
float fraction = ((val / exp2(exponent)) - 1.0) * 8388608.0;
float t = biased_exponent / 2.0;
float last_bit_of_biased_exponent = fract(t) * 2.0;
float remaining_bits_of_biased_exponent = floor(t);
float byte4 = extract_bits(fraction, 0.0, 8.0) / 255.0;
float byte3 = extract_bits(fraction, 8.0, 16.0) / 255.0;
float byte2 = (last_bit_of_biased_exponent * 128.0 + extract_bits(fraction, 16.0, 23.0)) / 255.0;
float byte1 = (sign * 128.0 + remaining_bits_of_biased_exponent) / 255.0;
return vec4(byte4, byte3, byte2, byte1);
}
// (the following inside main(){}) return your float as the fragment color
float myFloat = 420.420;
gl_FragColor = encode_float(myFloat);
然后回到JavaScript端,在进行绘制调用之后,您可以使用以下内容提取每个像素的编码浮点值:
var pixels = new Uint8Array(CANVAS.width * CANVAS.height * 4);
gl.readPixels(0, 0, CANVAS.width, CANVAS.height, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
pixels = new Float32Array(pixels.buffer);
// pixels now contains an array of floats, 1 float for each pixel
答案 1 :(得分:7)
我正在添加我最近的发现:Chrome会让您阅读花车,作为实施定义格式(search for "readPixels" in the spec)的一部分,Firefox会实现WEBGL_color_buffer_float扩展,因此您只需加载扩展程序并阅读你的花车,我无法用Safari阅读花车。
答案 2 :(得分:6)
readPixels仅限于RGBA格式和UNSIGNED_BYTE类型(WebGL specification)。然而,有一些方法可以将浮动“打包”到RGBA / UNSIGNED_BYTE这里描述:
http://concord-consortium.github.io/lab/experiments/webgl-gpgpu/webgl.html
答案 3 :(得分:0)
自从 WebGL 发布以来,情况发生了变化。基本上,WebGL 要求您可以使用 format = RGBA 和 type = UNSIGNED_BYTE 调用 readPixels。否则,允许实现为每个帧缓冲区附件类型定义一个其他实现定义的格式/类型组合。
你可以查询那个格式/类型组合是这样的
gl.bindFramebuffer(gl.FRAMEBUFFER, someFramebuffer);
const format = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_FORMAT);
const type = gl.getParameter(gl.IMPLEMENTATION_COLOR_READ_TYPE);
不幸的是,它是实现定义的。例如,检查我的个人设备中的至少一个,我的 Nvidia Macbook Pro,在 Chrome 中报告 RGBA/UNSIGNED_BYTE。其他浏览器/设备报告 RGBA/FLOAT
WebGL2 要求能够读取浮点纹理的 RGBA/FLOAT,如果启用了 EXT_color_buffer_float
扩展。
WebGL1 中的解决方法可能包括将 RGBA/UNSIGNED_BYTE 写入为 FLOAT。见this。您可以更改着色器。或者您可以添加另一个通道来读取您的浮点结果纹理并写入 RGBA/UNSIGNED_BYTE 纹理,可能是 4 倍大以获得所有 RGBA 值。