WebGL从浮点渲染目标读取像素

WebGL从浮点渲染目标读取像素,webgl,Webgl,在WebGL中渲染为浮点纹理的支持级别方面存在一些混乱。OES_texture_float扩展似乎并不强制要求它本身,但看起来有些供应商已经开始实施了。因此,我的基本理解是,渲染浮点纹理实际上在非ES桌面环境中工作。但我无法直接读取浮点渲染目标 我的问题是,是否有一种方法可以使用WebGLContext::readPixels()调用和Float32Array目标从浮点纹理读取?提前谢谢 附加的脚本成功读取字节纹理,但浮点纹理失败: <html> <head> <s

在WebGL中渲染为浮点纹理的支持级别方面存在一些混乱。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>

功能运行测试(使用浮动){
//创建画布和上下文
var canvas=document.createElement('canvas');
document.body.appendChild(画布);
var gl=canvas.getContext(“实验性webgl”);
//决定要用户使用的纹理类型
var texType,bufferFmt;
如果(使用浮点数){
texType=gl.FLOAT;
bufferFmt=Float32Array;
}否则{
texType=gl.UNSIGNED_字节;
bufferFmt=Uint8Array;
}
//查询扩展
var OES_texture_float=gl.getExtension('OES_texture_float');
如果(!OES\u纹理\u浮动){
抛出新错误(“不支持OES_纹理_浮动”);
}
//清楚的
总图视口(0,0,canvas.width,canvas.height);
gl.clearColor(1.0,0.0,0.0,1.0);
总账清除(总账颜色缓冲位);
//创建纹理
var texture=gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D,纹理);
gl.texParameteri(gl.TEXTURE\u 2D,gl.TEXTURE\u MIN\u过滤器,gl.NEAREST);
gl.texParameteri(gl.TEXTURE\u 2D,gl.TEXTURE\u MAG\u过滤器,gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D、gl.TEXTURE_WRAP_S、gl.CLAMP_TO_EDGE);
gl.texParameteri(gl.TEXTURE\u 2D、gl.TEXTURE\u WRAP\u T、gl.CLAMP\u至边缘);
gl.texImage2D(gl.TEXTURE_2D,0,gl.RGBA,512,0,gl.RGBA,texType,null);
//创建并附加帧缓冲区
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,空);
如果(总账checkFramebufferStatus(总账FRAMEBUFFER)!=总账FRAMEBUFFER\u COMPLETE){
抛出新错误(“gl.checkFramebufferStatus(gl.FRAMEBUFFER)!=gl.FRAMEBUFFER\u COMPLETE”);
}
//清楚的
总图视口(0、0、512、512);
总账清除(总账颜色缓冲位);
var像素=新的缓冲区fmt(4*512*512);
gl.readPixels(0,0,512,512,gl.RGBA,texType,pixels);
如果(像素[0]!==(使用浮点数?1.0:255)){
抛出新错误(“像素[0]==”+像素[0].toString());
}
}
函数main(){
运行测试(错误);
log('testpassed using GL_UNSIGNED_BYTE');
运行测试(真);
log('testpassed using GL_FLOAT');
}

readPixels仅限于RGBA格式和无符号字节类型()。但是,这里介绍了一些将浮点“打包”到RGBA/无符号_字节的方法:


不幸的是,读取RGBA组件作为字节似乎仍然是WebGL的唯一方法。如果需要将浮点编码为像素值,可以使用以下方法:

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
在分形着色器(GLSL/HLSL)中:

然后回到JavaScript端,在进行draw调用后,可以使用以下命令提取每个像素的编码浮点值:

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

我正在添加我最近的发现:Chrome将允许您读取浮动,作为实现定义格式()的一部分,Firefox实现了扩展,因此您可以加载扩展并读取浮动,我无法使用Safari读取浮动。

自从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/无符号字节。其他浏览器/设备报告RGBA/FLOAT

如果启用了扩展名
EXT\u color\u buffer\u FLOAT,WebGL2需要能够读取浮点纹理的RGBA/FLOAT


WebGL1中的一个解决方法可能包括将RGBA/无符号_字节作为浮点写入。看见您可以更改着色器。或者您可以添加另一个过程,读取浮点结果纹理并写入RGBA/无符号字节纹理,可能是获得所有RGBA值的4倍。

谢谢Adrian。我可以验证这是否有效。我在这部作品中使用了你的解决方案:没问题,斯蒂芬,顺便说一句,这部作品很棒;如果您还有任何问题,请随时直接联系我们:adrian[at]gatosomina[dot]com非常感谢,它的工作非常有魅力,给了我模拟所需的精度+我不知道Float32Array(ArrayBuffer)会将整数转换为浮点,这非常方便:)谢谢!您知道这是否意味着webgl 2中需要此功能?是的,我想是的。非常感谢你的评论。我看到在chrome中我可以调用
gl.getContext(“实验性webgl”)
,然后调用
gl.readPixels(0,0,宽度,高度,gl.RGB,gl.FLOAT,buf)
,而我有一个浮点FBO绑定,其中
buf
Float32Array
。但是我如何在firefox中使用这个扩展呢?我可以调用
gl.getExtension(“WEBGL\u color\u buffer\u float”)
,它返回一个
WEBGL\u color\u buffer\u float{}
,但是我该怎么处理它呢?回答我自己的问题——在firefox中似乎只有
gl.RGBA
支持
gl.float
,但一旦调用
gl.getExtension(“WEBGL\u color\u buffer\u float”)
这似乎确实有效。FWIW,th