FrameBuffer与RenderBuffer基本认识

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FrameBuffer与RenderBuffer基本认识相关的知识,希望对你有一定的参考价值。

参考技术A FrameBuffer对象实际上不是缓冲区,而是包含一个或多个附件的聚合容器对象,而这些附件又是实际的缓冲区。可以将Framebuffer理解为C结构,其中每个成员都是指向缓冲区的指针。没有任何附件,framebuffer对象的占用空间非常小。
现在连接到framebuffer的每个缓冲区可以是RenderBuffer或texture。
Renderbuffer是实际缓冲区(字节数组,或整数或像素)。Renderbuffer以原生格式存储像素值,因此它针对屏幕外渲染进行了优化。绘制到RenderBuffer可能比绘制到纹理快得多,缺点是像素使用原生的,依赖于实现的格式,因此RenderBuffer读取比从纹理读取要困难得多。然而,一旦绘制了RenderBuffer,就可以使用像素传输操作将其内容直接赋值到屏幕,这意味着RenderBuffer可用于有效地实现您提到的双缓冲区模式。

Framebuffer 和 Renderbuffer 的 Webgl 绑定

【中文标题】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基本认识的主要内容,如果未能解决你的问题,请参考以下文章

Framebuffer 和 Renderbuffer 的 Webgl 绑定

FrameBuffer & RenderBuffer

WebGL— FrameBuffer,RenderBuffer,Texture区别

WebGL— FrameBuffer,RenderBuffer,Texture区别

OpenGL 帧缓冲绑定目标

绘制渲染缓冲区对象的内容