博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CSharpGL(47)你好,Framebuffer!
阅读量:5955 次
发布时间:2019-06-19

本文共 10216 字,大约阅读时间需要 34 分钟。

CSharpGL(47)你好,Framebuffer!

Framebuffer对象(FBO)是一种复杂的OpenGL对象。使用自定义的framebuffer,可以实现离屏渲染,进而实现很多高级功能,例如阴影。

 

下载

CSharpGL已在GitHub开源,欢迎对OpenGL有兴趣的同学加入()

FBO基本结构

【注:本节(FBO基本结构)是翻译的(),略有修改。】

类似其它的OpenGL对象,FBO也有一套glGen, glDelete, glBind的API。

FBO这套API里的target可接受3种值:GL_FRAMEBUFFER, GL_READ_FRAMEBUFFER或GL_DRAW_FRAMEBUFFER。后两种允许你可以让读操作(等)和写操作(所有的渲染命令)发生到不同的FBO上。GL_FRAMEBUFFER 则将读写发生到同一个FBO。

名词术语

为了叙述方便,首先定义一些术语。

Image

像素的二维数组(Pixel[ , ]),有特定的格式。

Layered Image

相同大小和格式的一组Image。

包含若干Image的OpenGL对象。这些Image的格式相同,但大小未必相同(例如不同mipmap level的Image大小是不同的)。Texture可以以多种方法被shader读取。

包含1个Image的OpenGL对象。不能被shader读取。只能被创建,然后放到FBO里。

Attach

把一个对象关联(附着)到另一个对象上。附着attach不同于绑定binding。对象被绑定到上下文context,对象被附着到另一个对象。

Attachment point

Framebuffer对象里可以让Image或Layered Image附着的位置。只有符合规定的图像格式才能被附着。

Framebuffer-attachable image

格式符合规定,可以被附着到framebuffer对象的Image。

Framebuffer-attachable layered image

格式符合规定,可以被附着到framebuffer对象的Layered Image。

附着点Attachment Point

FBO有若干Image的附着点(位置):

GL_COLOR_ATTACHMENTi

这些附着点的数量依不同的实现而不同。你可以用GL_MAX_COLOR_ATTACHMENTS 查询一个OpenGL实现支持的颜色附着点的数量。最少有8个,所以你最少可以放心使用附着点0-7。这些附着点只能让可渲染色彩的Image来附着。所有compressed image formats都不是可渲染色彩的,所以都不能附着到FBO。

GL_DEPTH_ATTACHMENT

这个附着点只能让depth格式的Image附着。附着的Image就成了此FBO的depth buffer。**注意**,即使你不打算从深度附着点上读取什么东西,也应该给深度附着点设定一个Image。

GL_STENCIL_ATTACHMENT

这个附着点只能让stencil格式的Image附着。附着的Image就成了此FBO的stencil buffer。

GL_DEPTH_STENCIL_ATTACHMENT

这是“depth+stencil”的简写。附着的Image既是depth buffer又是stencil buffer。注意:如果你使用GL_DEPTH_STENCIL_ATTACHMENT,你应当使用一个以packed depth-stencil为内部格式的Texture或Renderbuffer。

Attaching Images

现在我们已经知道了Image可以附着到FBO的哪些位置上,我们可以开始谈谈如何将Image附着到FBO上。首先,我们必须用把FBO绑定到context。

Attaching Texture

首先来了解一下各种类型的Texture:

图中列出了8种类型的Texture。上方分别是1D Texture、2D Texture、3D Texture和2D Array Texture,下方分别是1D Array、Cubemap Texture、Rectangle Texture和Buffer Texture。大多数Texture都支持mipmap(上图中每个Texture从上到下分别为mipmap level0,1,2,3…)。

你可以将基本上任何类型的Texture里的Image附着到FBO。不过,FBO是被设计来做2D渲染的。所以有必要考虑一下不同类型的Texture是如何映射到FBO里的Image的。记住,Texture就是一组Image,Texture可能包含多个mipmap level,每个mipmap level都可能包含1到多个Image。

然后,对照上图,不同类型的Texture映射到FBO里的Image的方式如下:

1D Texture里的Image被视作高度为1的2D Image。1个Image可以被mipmap level标识。

2D Texture里的Image就照常使用了。1个Image可以被mipmap level标识。

3D Texture的1个mipmap level被视作2D Image的集合,此集合的元素数量即为此mipmap level的Z坐标。Z坐标的每个整数值都是一个单独的2D层(layer)。所以3D Texture里的的一个Image由layer和mipmap level共同标识。记得3D Texture的不同mipmap level的Z坐标数量是不同的。

只有1个2D Image,因此直接用mipmap level 0标识。

里每个mipmap都包含6个2D Image。因此,1个Image可以被面target和mipmap level标识。然而有些API函数里,1个mipmap level里的各个face是用layer索引标识的。

1D或2D 的每个mipmap level都包含多个Image,其数量等于数组元素的数量。因此,每个Image可以被layer(数组索引)和mipmap level标识。1D Array Texture里,每个Image都是高度为1。与3D Texture不同的是,layer不随mipmap层的递进而改变。(即各个mipap level的layer数量都相同)

类似2D Array Texture,只是Image数量乘以6。因此一个2D Image由layer(具体的说是layer-face)和mipmap level标识。(这个太难画我就不画了)

不能被附着到FBO。

上面带下划线的字很重要,因为他们对应了下面的API函数(用于附着Texture)的参数:

1 void(GLenum target​, GLenum attachment​, GLenum textarget​, GLuint texture​, GLint level​);2 void(GLenum target​, GLenum attachment​, GLenum textarget​, GLuint texture​, GLint level​);3 void (GLenum target​, GLenum attachment​, GLuint texture​, GLint level​, GLint layer​);

参数target与glBind用的相同。但是这里GL_FRAMEBUFFER的意思不是“既可读又可写”(那没有意义),他是和GL_DRAW_FRAMEBUFFER相同的意思。参数attachment是上面介绍的附着点。

参数texture是你想要附着到FBO的的Texture的名字。如果你传入“0”,就会清除指定的attachment位置上的附着物(不管附着物是什么)。

因为Texture可能包含多个Image,你必须详细说明要将哪个Image附着到附着点。除textarget之外,参数都符合上文的定义。

当附着一个非cubemap的Texture时,textarget应当是合适的类型:GL_TEXTURE_1D, GL_TEXTURE_2D_MULTISAMPLE等。当附着一个非数组的cubemap时,你必须使用函数,且textarget必须是的6个target之一。当附着一个cubemap array时,你必须使用TextureLayer,用layer标识layer-face。

注意:如果OpenGL4.5或ARB_direct_state_access可用,那么可以接受非数组cubemap类型的Texture。他会被视作只有1个layer(即6个layer-face)的数组cubemap类型的Texture。这意味着你永远不需要使用或者。

又注意:有一个函数glFramebufferTexture3D,专用于3D Texture。但是你不应该使用他,因为TextureLayer函数能够完成他所有的功能。

Attaching Renderbuffer

也可以被附着到FBO。实际上,这也是除了创建他们之外唯一的使用方法。

1 void (GLenum target​, GLenum attachment​, GLenum renderbuffertarget​, GLuint renderbuffer​);

参数与附着Texture的类似。参数renderbuffertarget必须是GL_RENDERBUFFER,参数renderbuffer是renderbuffer的名字。

Layered Images

Layered Image,如前所述,是一组有序的大小相同的Image。多种Texture都可以被认为是layered。

1D或2D 的1个mipmap level就是一个Layered Image,数组的元素数就是层数。3D Texture的1个mipmap level同样也是一个Layered Image,层数就是此mipmap level的depth。Cubemap Texture的1个mipmap level也是一个Layered Image,他有且只有6个layer,每个face是一个,且face的顺序与下面的枚举值相同:

Layer number

Cubemap face

0

GL_TEXTURE_CUBE_MAP_POSITIVE_X

1

GL_TEXTURE_CUBE_MAP_NEGATIVE_X

2

GL_TEXTURE_CUBE_MAP_POSITIVE_Y

3

GL_TEXTURE_CUBE_MAP_NEGATIVE_Y

4

GL_TEXTURE_CUBE_MAP_POSITIVE_Z

5

GL_TEXTURE_CUBE_MAP_NEGATIVE_Z

对于,Layer 代表的是layer-face的索引。他是带layer的face,按上表排列。所以如果你想渲染到第三个layer的+z face,你就要设置gl_Layer 为(2 * 6) + 4或者16。

每个Texture,被用作Layered Image的时候,都有特定数量的layer。对于Array Texture或3D Texture,layer数就是Texture 的depth。对于cubemap,总是有且只有6个layer:每个face即为1个layer。Cubmap Array 有6*layer(layer-face数)。

使用下述指令可以将Texture的一个mipmap level附着为一个Layered Image:

1 void (GLenum target​, GLenum attachment​, GLuint texture​, GLint level​);

参数含义与上文的相同。实际上,如果你不要求附着Array Texture, Cubemap或3D Texture的单独一个Image,那么这个函数可以代替很多glFramebufferTexture1D,2D或Layer。但如果texture是这种情况,那么给定的整个mipmap level将作为一个Layered Image整体被附着,即此Layered Image里所有的layer都会被附着。(译者注:有什么用呢?下面立即分解)

Layered Image用于,即向FBO的不同Layer发送不同的图元(在同一次渲染中形成不同的图像)。

Empty framebuffers

有时候会需要向一个没有附着对象的FBO渲染。显然fragment shader的输出不会写入到任何地方,但是渲染过程还是可以正常进行的。这对于shader的是有用的。

但是,图元的渲染总是基于FBO的性质(大小,sample数量等)进行的,这些性质通常由被附着的Image定义。如果没有附着Image,这些性质就必须用其它的方式定义。

没有附着Image的FBO的性质可以用下述函数设置:

1 void (GLenum target​, GLenum pname​, GLint param​);

target是FBO绑定的位置。如果要设置width,就设pname为GL_FRAMEBUFFER_DEFAULT_WIDTH;,如果要设置height,就设pname为GL_FRAMEBUFFER_DEFAULT_HEIGHT。

Layered FBO可以通过设置GL_FRAMEBUFFER_DEFAULT_LAYERS 为大于0的值来模仿。Multisample FBO可以通过设置GL_FRAMEBUFFER_DEFAULT_SAMPLES 为大于0的值来模仿。Fixed multisample位置可以通过设置GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 为非零值来模仿。

注意,仅在FBO没有附着对象的时候,这些参数才会起作用。如果附着了Image,那么这些参数会被无视。你应该仅在你想要使用无Image的FBO时才设置这些值。

Framebuffer Completeness

FBO里每个附着点都对能附着的Image的格式有要求。但是,如果附着了不符合要求的Image,不会立即产生。在使用不合适的设置的FBO时才会引发错误。为了安全地使用FBO,必须检测各种可能出现的问题(例如Image的大小等)。

一个可以正常使用的FBO被称作是“完整的FBO”。想要测试FBO的完整性,请调用这个函数:

1 GLenum (GLenum target​);

你不是非得调用这个函数不可。但是,使用不完整的FBO是错误的,所以检测一下总是好的。

如果FBO能用,会返回GL_FRAMEBUFFER_COMPLETE 。否则就是有问题。

FBO in C#

FBO最复杂的操作就是Attach不同类型的Texture。根据上文,可以总结出来,只需要glFramebufferTexture和glFramebufferTextureLayer两个函数就可以实现对所有类型Texture的Attach的支持。Wiki说OpenGL3.2开始才支持glFramebufferTexture,这我就不管了。

1         ///  2         /// Attach a level of the 
as a logical buffer to the currently bound framebuffer object. 3 /// If there are multiple images in one mipmap level of the
, then we will start 'layered rendering'. 4 ///
Bind() this framebuffer before invoking this method.
5 ///
6 /// GL_FRAMEBUFFER is equivalent to GL_DRAW_FRAMEBUFFER 7 /// Specifies the texture object to attach to the framebuffer attachment point named by
. 8 /// Specifies the attachment point of the framebuffer. 9 /// Specifies the mipmap level of
to attach.10 public void Attach(FramebufferTarget target, Texture texture, AttachmentLocation location, int mipmapLevel = 0)11 {12 if (texture == null) { throw new ArgumentNullException("texture"); }13 14 if (location == AttachmentLocation.Color)15 {16 if (this.nextColorAttachmentIndex >= Framebuffer.maxColorAttachmentCount)17 { throw new IndexOutOfRangeException("Not enough color attach points!"); }18 19 glFramebufferTexture((uint)target, GL.GL_COLOR_ATTACHMENT0 + this.nextColorAttachmentIndex, texture != null ? texture.Id : 0, mipmapLevel);20 this.nextColorAttachmentIndex++;21 }22 else23 {24 glFramebufferTexture((uint)target, (uint)location, texture != null ? texture.Id : 0, mipmapLevel);25 }26 }27 28 /// 29 /// Attach a single layer of a
to the currently bound framebuffer object.30 ///
Bind() this framebuffer before invoking this method.
31 ///
32 /// GL_FRAMEBUFFER is equivalent to GL_DRAW_FRAMEBUFFER33 /// texture must either be null or an existing cube map array texture.34 /// attachment point.35 /// Specifies the layer of
to attach.36 /// Specifies the face of
to attach.37 /// Specifies the mipmap level of
to attach.38 public void Attach(FramebufferTarget target, Texture cubemapArrayTexture, AttachmentLocation location, int layer, CubemapFace face, int mipmapLevel = 0)39 {40 this.Attach(target, cubemapArrayTexture, location, (layer * 6 + (int)((uint)face - GL.GL_TEXTURE_CUBE_MAP_POSITIVE_X)), mipmapLevel);41 }42 43 /// 44 /// Attach a single layer of a
to the currently bound framebuffer object.45 ///
Bind() this framebuffer before invoking this method.
46 ///
47 /// GL_FRAMEBUFFER is equivalent to GL_DRAW_FRAMEBUFFER48 /// texture must either be null or an existing three-dimensional texture, one- or two-dimensional array texture, cube map array texture, or multisample array texture.49 /// attachment point.50 /// Specifies the layer of
to attach.51 /// Specifies the mipmap level of
to attach.52 public void Attach(FramebufferTarget target, Texture texture, AttachmentLocation location, int layer, int mipmapLevel = 0)53 {54 if (location == AttachmentLocation.Color)55 {56 if (this.nextColorAttachmentIndex >= Framebuffer.maxColorAttachmentCount)57 { throw new IndexOutOfRangeException("Not enough color attach points!"); }58 59 glFramebufferTextureLayer((uint)target, GL.GL_COLOR_ATTACHMENT0 + this.nextColorAttachmentIndex, texture != null ? texture.Id : 0, mipmapLevel, layer);60 this.nextColorAttachmentIndex++;61 }62 else63 {64 glFramebufferTextureLayer((uint)target, (uint)location, texture != null ? texture.Id : 0, mipmapLevel, layer);65 }66 }
Attach Texture

总结

 

转载地址:http://ptexx.baihongyu.com/

你可能感兴趣的文章
2013 Linux领域年终盘点
查看>>
linux学习之查看程序端口占用情况
查看>>
相逢在栀枝花开的季节
查看>>
linux下git自动补全命令
查看>>
Ubuntu14.04LTS更新源
查看>>
Linux报“Unknown HZ value! (288) Assume 100”错误
查看>>
mysql多实例实例化数据库
查看>>
我的友情链接
查看>>
golang xml和json的解析与生成
查看>>
javascript 操作DOM元素样式
查看>>
Android 内存管理 &Memory Leak & OOM 分析
查看>>
【查找算法】基于存储的查找算法(哈希查找)
查看>>
JavaWeb网上图书商城完整项目--day02-10.提交注册表单功能之页面实现
查看>>
记录一下这次web实训的两个网站
查看>>
POJ-1830 开关问题 高斯消元
查看>>
做程序开发的你如果经常用Redis,这些问题肯定会遇到
查看>>
CAS-认证流程
查看>>
006android初级篇之jni数据类型映射
查看>>
Java 集合框架查阅技巧
查看>>
apache配置虚拟主机
查看>>