Framebuffer 和 Renderbuffer 的 Webgl 绑定

Posted

技术标签:

【中文标题】Framebuffer 和 Renderbuffer 的 Webgl 绑定【英文标题】:Webgl binding of a Framebuffer and Renderbuffer 【发布时间】:2015-04-11 13:42:20 【问题描述】:

我想从帧缓冲区中获取像素颜色。 我尝试绑定帧缓冲区,但收到消息“此附件组合不起作用”。

RenderingEngine.prototype.getPixel = function(x, y, drawObject)
var framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
framebuffer.width = this.canvas.width;
framebuffer.height = this.canvas.height;

var depthBuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);

// allocate renderbuffer
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, this.canvas.width, this.canvas.height);  

// attach renderebuffer
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);

if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) 
   alert("this combination of attachments does not work");

gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);

    drawObject.draw();

var pixel = new Uint8Array(4);
gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
console.log(pixel);
return pixel;


更新 #1

我像这样更改了我的代码。但我总是得到黑色([0, 0, 0, 0])。你能说现在是什么问题吗?

RenderingEngine.prototype.getPixel = function(x, y, drawObject)
var framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
framebuffer.width = this.canvas.width;
framebuffer.height = this.canvas.height;

var depthBuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);


// allocate renderbuffer
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, framebuffer.width, framebuffer.height);  

// attach renderebuffer
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);

var colorBuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
// allocate colorBuffer
gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, framebuffer.width, framebuffer.height);  

// attach colorbuffer
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);

if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) 
   alert("this combination of attachments does not work");


renderingEngine.draw(drawObject);

var pixel = new Uint8Array(4);
gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
console.log(pixel);
return pixel;


更新 #2

我的错误是绘画。此代码有效。但是有一些奇怪的东西。渲染的场景被水平镜像。你知道为什么吗?

RenderingEngine.prototype.getPixel = function(x, y, drawObject)
var framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
framebuffer.width = this.canvas.width;
framebuffer.height = this.canvas.height;

var depthBuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);


// allocate renderbuffer
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, framebuffer.width, framebuffer.height);  

// attach renderebuffer
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);

var colorBuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
// allocate colorBuffer
gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, framebuffer.width, framebuffer.height);  

// attach colorbuffer
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);

if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) 
   alert("this combination of attachments does not work");


renderingEngine.draw(drawObject);

var pixel = new Uint8Array(4);
gl.readPixels(x, y, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
console.log(pixel);
return pixel;

【问题讨论】:

您只附加了一个深度渲染缓冲区。您还需要附加颜色渲染缓冲区或颜色纹理。我认为您不能只渲染到深度渲染缓冲区。 我这样修改了我的代码: 我将您的更新复制到您上面的问题。您能否删除下面的2个答案?将您的问题的更新发布为 SO 的答案并不合适。否则,至于为什么翻转,我假设您的意思是垂直而不是水平?请记住,WebGL 中的 0,0 是左下角。 【参考方案1】:

这对我有用

function log(msg) 
  var pre = document.createElement("pre");
  pre.appendChild(document.createTextNode(msg));
  document.body.appendChild(pre);


var gl = document.getElementById("c").getContext("webgl");

var framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);

var depthBuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, depthBuffer);

// allocate renderbuffer
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH_COMPONENT16, gl.canvas.width, gl.canvas.height);  

// attach renderebuffer
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.DEPTH_ATTACHMENT, gl.RENDERBUFFER, depthBuffer);

var colorBuffer = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
// allocate colorBuffer
gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA4, gl.canvas.width, gl.canvas.height);  

// attach colorbuffer
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, colorBuffer);

if (gl.checkFramebufferStatus(gl.FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE) 
   alert("this combination of attachments does not work");


gl.clearColor(0.5, 0.25, 1, 1);
gl.clear(gl.COLOR_BUFFER_BIT);
             
var pixel = new Uint8Array(4);
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
log(pixel[0] + "," + pixel[1] + "," + pixel[2] + "," + pixel[3]);
canvas  border: 1px solid black; 
<body>
  <canvas id="c"></canvas>  
</body>

虽然如果是我,我会为颜色附件附加纹理而不是渲染缓冲区。

【讨论】:

为什么是 136 ?第一种颜色是 0.5,或者 255 * 0.5 不是 136 ahh ok RGBA 是 4 位浮点数(整数中的 4 位 = 0..15)。 136 = (8/15) * 255 ; 68 = (4/15) * 255 !【参考方案2】:

引自WebGLFundamentals: 重要的是要注意 WebGL 只承诺 3 种附件组合有效。根据the spec,唯一保证的附件组合是:

COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture
COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_ATTACHMENT = DEPTH_COMPONENT16 renderbuffer
COLOR_ATTACHMENT0 = RGBA/UNSIGNED_BYTE texture + DEPTH_STENCIL_ATTACHMENT = DEPTH_STENCIL renderbuffer

【讨论】:

以上是关于Framebuffer 和 Renderbuffer 的 Webgl 绑定的主要内容,如果未能解决你的问题,请参考以下文章

OpenGL中Framebuffer和Renderbuffer的概念和区别是啥?

如何在Android上实现FrameBuffer和Overlay的blend

GL_DRAW/READ_FRAMEBUFFER 与 GL_FRAMEBUFFER?

我的 FrameBuffer 上只渲染了一个纹理

5.7.1.framebuffer介绍

Framebuffer 和 Renderbuffer 的 Webgl 绑定