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