OpenGL ES手册翻译---4.每块碎片的操作和帧缓冲(三)

4.4 帧缓冲对象

如同第一章和第二章描述的一样,OpenGL ES渲染到帧缓冲(和从帧缓冲中读取)。OpenGL ES定义了两类帧缓冲:窗口系统提供的帧缓冲和应用创建的帧缓冲。

默认情况下,OpenGL ES使用窗口系统提供的帧缓冲。附着在帧缓冲上的图像的存储,维度,空间分配,格式都是由窗口系统全部管理的。因此,OpenGL ES不能改变窗口系统提供的帧缓冲(包括其图像)的状态,OpenGL ES也不能删除窗口系统提供的帧缓冲本身或其图像。

接下来的小节介绍的规范,可用来对应用创建的帧缓冲对象做创建,销毁,修改状态和附着点的操作。

应用创建的帧缓冲对象包含的帧缓冲的状态和纹理对象包含纹理的状态使用的是相同的方式。特别的是,帧缓冲对象包含了一些必要的状态,来描述颜色,深度,模板这些逻辑缓冲的集合。对每个逻辑缓冲来说,一个帧缓冲可以附着的图像可以被附着在帧缓冲上来为逻辑缓冲存储要被渲染的输出。帧缓冲可附着的图像的例子有纹理图像和渲染缓冲图像。

通过允许渲染缓冲图像附着在帧缓冲上,OpenGL ES提供了一套机制来支持离屏渲染。更多的是,通过允许纹理图像附着在帧缓冲上,OpenGL ES提供了一套机制来支持render to texture

4.4.1 绑定和管理帧缓对象

在第四章中介绍的操作会作用于绑定在目标靶FRAMEBUFFER上的帧缓冲对象上附着的图像。默认情况下,绑定在目标靶FRAMEBUFFER上的帧缓冲是0,并指定默认的基于实现的由窗口系统提供的帧缓冲。当绑定在目标靶FRAMEBUFFER上的帧缓冲不是0,而是应用创建的帧缓冲对象的名字,那么在第四章中介绍的操作就会对应用创建的帧缓冲对象发生作用,而不是默认的帧缓冲对象。

帧缓冲对象的命名空间是无符号整数,0被OpenGL ES保留用来指代默认的帧缓冲。一个帧缓冲对象通过给FRAMEBUFFER绑定未使用的名字来创建。绑定的有效函数为:

void BindFramebuffer(enum target, uint framebuffer);

target要设置为FRAMEBUFFERframebuffer设置为未使用的名字。帧缓冲对象的结果是一个有新状态的向量。它有一个颜色附着点,再加上一个深度和模板附着点。

函数BindFramebuffer也可以用来绑定一个已经存在的帧缓冲对象到target上。如果绑定是成功的,对于已经绑定的帧缓冲对象其状态不会发生任何改变,而之前绑定在target上的帧缓冲就被破坏了。当前在FRAMEBUFFER上绑定的帧缓冲可以通过GetIntegerv查询到(FRAMEBUFFER_BINDING)。

当帧缓冲被绑定到目标靶FRAMEBUFFER上时,OpenGL ES对帧缓冲所绑定的目标靶的操作会影响附着在帧缓冲对象上的图像,对所绑定的目标靶的查询也会返回绑定的帧缓冲对象的状态。特别的,在表6.21(实现基于像素深度)中对指定值的查询都来自于当前的绑定的帧缓冲对象。绑定在目标靶FRAMEBUFFER上的帧缓冲对象被用作是碎片操作的目的地以及像素读取比如ReadPixels的像素源。

在初始状态下,保留名字0被绑定在目标靶FRAMEBUFFER上。应用创建的帧缓冲对象不会和名字0有关系。名字0代指窗口系统提供的帧缓冲对象。但名字为0绑定在目标靶FRAMEBUFFER上时,所有对帧缓冲的查询和操作都是在默认的帧缓冲上。在一些实现中,默认窗口系统提供的帧缓冲的一些属性可以随着时间的变化而变化(举个例子,比如对窗口系统事件的响应,比如给新的窗口绘画系统附加上下文)。

应用创建的帧缓冲对象(就是那些名字不是0的)和默认窗口系统提供的帧缓冲在一些重要的地方有所不同。首先最重要的一点,不像窗口系统提供的帧缓冲,应用创建的帧缓冲在每个逻辑缓冲中都有可以被修改的附着点。帧缓冲附着的图像可以通过这些附着点附着或者分离。其次,附着在应用创建的帧缓冲的图像的大小和格式完全由OpenGL ES接口来控制,而且不会受到窗口系统事件的影响,比如像素格式选择,窗口大小调整,显示模式变化。

另外,当渲染到应用创建的帧缓冲或者从应用创建的帧缓冲中读取时,

  1. 像素归属测试总是成功的。换句话说,应用创建的帧缓冲对象拥有所有他们的像素。
  2. 没有可是的颜色缓冲位平面。这意味着没有和后,前颜色位平面相关的颜色缓冲。
  3. 仅有的颜色缓冲位平面是那些由帧缓冲定义的,附着在附着点COLOR_ATTACHMENT0上的缓冲。
  4. 仅有的深度缓冲为平面是那些由帧缓冲定义的,附着在附着点DEPTH_ATTACHMENT上的缓冲。
  5. 仅有的模板位平面是那些由帧缓冲定义的,附着在附着点STENCIL_ATTACHMENT上的缓冲。
  6. 没有多重采样缓冲,所以依赖实现的状态变量SAMPLESSAMPLE_BUFFERS都是0。

帧缓冲对象可以用下面函数删除:

void DeleteFramebuffers(sizei n, uint *framebuffers);

framebuffers包含了要被删除的n个缓冲对象的名字。在帧缓冲对象被删除后,也就没有附着点了,名字再次变成未被使用。如果当前绑定在目标靶FRAMEBUFFER上的帧缓冲被删除了,BindFramebuffer就会被按照目标靶FRAMEBUFFERframebuffer为0来执行。在framebuffers中未被使用的名字被静默忽略,正如0值一样。

函数

void GenFramebuffers(sizei n,uint *framebuffers);

返回n个之前没有用过的帧缓冲对象,新的帧缓冲对象名字储存在framebuffers中。仅仅处于GenFramebuffers的目的,这些名字会被标记为使用过,但是查询他们的状态和类型只有在第一次绑定后才可以,就像他们没有被使用过一样。

4.4.2 把图像附着在帧缓冲上

帧缓冲可附着的图像可以附着在应用创建的帧缓冲对象上或者从其分立。相反的,在窗口系统提供的帧缓冲的图像附着点,不能通过OpenGL ES改变。

一个单一的帧缓冲可附着图像可以附着在多个应用创建的帧缓冲对象上,这样很好的避免了数据的拷贝和可能增加的内存消耗。

对每个逻辑缓冲,帧缓冲对象存储了一系列的定义逻辑缓冲的附着点的状态。附着点状态包含了足够多的状态,这些状态用来标识在附着点上附着的单一图像或者没有图形附着。每个逻辑缓冲的附着点状态罗列在表6.24中。

有两种类型的帧缓冲可附着图像:渲染缓冲对象的图像和纹理对象的图像。

4.4.3 渲染缓冲对象

一个渲染缓冲是一个包含了一副壳渲染的内部格式图像的数据存储对象。OpenGL ES提供了描述底层的用来申请和删除渲染缓冲的图像的方法,以及把渲染缓冲的图象附着在帧缓冲的方法。

渲染缓冲对象的命名空间是无符号整数,0被OpenGL ES保留。一个渲染缓冲对象通过将未使用的名字绑定在RENDERBUFFER上来创建。绑定的函数是:

BindRenderbuffer(enum target, uint renderbuffer);

target设置为RENDERBUFFER,renderbuffer用来设置名字。如果renderbuffer不是0,生成的渲染缓冲对象就是一个新的状态向量,它被一个大小为0的内存缓冲初始化,组成它的状态值列在表6.23中。之前的在target上的绑定都会破裂。

函数BindRenderbuffer也可以用来绑定一个已经存在的渲染缓冲对象。如果绑定成功,新绑定的渲染缓冲对象的状态也不会发生变化,之前的绑定在target上的渲染缓冲对象就会破裂。

当渲染缓冲对象被绑定,在对绑定的目标靶的OpenGL ES操作会作用于绑定的渲染缓冲对象,对渲染缓冲对象绑定的目标靶的查询会返回绑定的渲染缓冲对象的状态。

名字0是保留的。用0不能创建一个渲染缓冲对象。如果renderbuffer是0,之前所任意的绑定在target上的渲染缓冲对象都会破裂,target的绑定也会恢复到初始化状态。

在初始化状态下,保留的名字0被绑定到RENDERBUFFER。没有渲染缓冲对象时对应于名字0的,因此,客户端试图更改或者查询在目标靶FRAMRBUFFER名字为0时的渲染缓冲状态会产生错误。

使用GetIntegerv,当前RENDERBUFFER的绑定可以通过RENDERBUFFER_BINDING来查询。

渲染缓冲对象调用下面函数来删除:

void DeleteRenderbuffers(sizei n, const uint *renderbuffers);

其中,renderbuffer包含了要被删除的n个渲染缓冲对象的名字。在渲染缓冲对象被删除后,渲染缓冲对象就没有内容了,名字也会再次回到未使用。如果当前绑定在RENDERBUFFER的一个渲染缓冲被删除了,就相当于是BindRenderbuffer函数用targetRENDERBUFFERname为0做了执行。另外,如果渲染缓冲的图像附着在一个帧缓冲对象上时,当删除渲染缓冲时需要特别的注意。在renderbuffers中没有使用的名字会被静默的忽略,就像其值为0一样。

函数

void GenRenderbuffers(sizei n, uint *renderbuffers);

renderbuffers中会返回n个之前没有使用的渲染缓冲对象的名字。这些名字仅仅对于GenRenderbuffers的目第是会被标记为已使用过,但是只有在他们被第一次绑定后才可以接受渲染缓冲的状态,否则就像是他们没有被使用一样。

函数

void RenderbufferStorage(enum target,enum internalformat, sizei width, sizei height);

建立了渲染缓冲对象的图像的数据存储,格式,以及维度。target一定是RENDERBUFFER,internalformat一定是表4.5中介绍的可渲染色彩,可渲染深度,可渲染模板格式中的一种。widthheight是在渲染缓冲中的像素的维度。如果width或者height都大于MAX_RENDERBUFFER_SIZE,将会产生INVALID_VALUE。如果OpenGL ES不能创建一个需求大小的数据存储空间,会产生OUT_OF_MEMORY错误。在调用RenderbufferStorage之后,RenderbufferStorage删除渲染缓冲上的已经存在的数据存储和数据存储的内容都是未定义的。

OpenGL ES实现会基于RenderbufferStorage的参数(除了target)来变通内部通道结构的空间申请,但是空间申请和选定的内部格式一定不是其他状态的函数,一旦建立也不能被修改。申请的图像的每个通道的比特位的实际结构可以通过GetRenderbufferParameteriv来查询。

  • 将渲染缓冲图像附着在帧缓冲上

一个渲染缓冲可以通过调用函数

void FramebufferRenderbuffer(enum target, enum attachment, enum renderbuffertarget, uint renderbuffer);

将其作为一个逻辑缓冲附着在当前绑定的帧缓冲上。target一定是FRAMEBUFFER。如果FramebufferRenderbuffer在调用时,当前的FRAMEBUFFER_BINDING的值是0,将会产生INVALID_OPERATION错误。attachment应该被设置为COLOR_ATTACHMENT0,DEPTH_ATTACHMENT,STENCIL_ATTACHMENT中的其中一个附着点。renderbuffertarget一定是RENDERBUFFERrenderbuffer应该设置要附着在帧缓冲对象上的渲染缓冲对象的名字。renderbuffer一定是0或者renderbuffertarget类型的一个已经存在的渲染缓冲对象的名字,否则,会产生INVALID_OPERATION错误。如果renderbuffer是0,renderbuffertarget的值就会被忽略。

如果renderbuffer不是0,而且如果FramebufferRenderbuffer执行成功,名字为renderbuffer的渲染缓冲将会被用作是逻辑缓冲,这个逻辑缓冲被当前绑定在target上的帧缓冲对象的attachment做了唯一的标识。对于指定附着点的FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE的值被设置为RENDERBUFFER,FRAMEBUFFER_ATTACHEMNT_OBJECT_NAME的值设置给renderbuffer。其他的由attachment指定的附着点的值的状态都被设置到如表6.24中列出的默认值。渲染缓冲对象的状态没有任何改变,任何之前的绑定在帧缓冲target的帧缓冲的attachment逻辑缓冲的附着点都会分离。另一方面,附着不成功时,渲染缓冲对象或者帧缓冲对象的也不会发生变化。

在当前被绑定到target的帧缓冲中,如果有任何被attachment标记的图像,调用FramebufferRenderbuffer,将其renderbuffer参数设置为0,将会使图像分离。在绑定到target的对象中由attachment指定的所有附着点的状态值通过设置他们的默认值,这些默认值列在表6.24中。

如果当前绑定的帧缓冲附着图像时,如果渲染缓冲对象被删除,这样就好像是FramebufferRenderbuffer被调用,并对每个在当前绑定的帧缓冲的附着咋附着点上的图像,设置renderbuffer为0。换句话说,这个渲染缓冲图像第一次从当前绑定的帧缓冲的所有附着点上分离。注意,渲染缓冲图像并没有从任何没有绑定的帧缓冲上分离。从没有绑定的帧缓冲上分离图像是应用的责任。

  • 将纹理附着在帧缓冲上

OpenGL ES支持将帧缓冲的渲染的内容拷贝到纹理对象的图像中,方式是通过使用CopyTexImage2DCopyTexSubImage2D。另外,OpenGL ES也支持直接渲染到纹理对象的图像上。

想要直接渲染到纹理图像上,纹理对象指定的图像可以当成是当前绑定的帧缓冲的一个逻辑缓冲附着,使用下面函数:

void FramebufferTexture2D(enum target, enum attachment, enum textarget, uint texture,int level);

targetFRAMEBUFFER。如果在FramebufferTexture2D调用时,FRAMEBUFFER_BINDING的值是0,将会产生INVALID_OPERATION错误。attachment是帧缓冲对象的一个附着点。

如果texture是0,textargetlevel参数就被忽略了。如果texture不是0,那么texture就一定会命名一个已经存在的纹理对象,这个纹理对象带有textarget的目标靶的,或者texture一定会命名立方体纹理,而且textarget一定是TEXTURE_CUBE_MAP_POSITIVE_X,TEXTURE_CUBE_MAP_POSITIVE_Y,TEXTURE_CUBE_MAP_POSITIVE_Z,TEXTURE_CUBE_MAP_NEGATIVE_X,TEXTURE_CUBE_MAP_NEGATIVE_Y,TEXTURE_CUBE_MAP_NEGATIVE_Z中的其中一个。否则,会产生INVALID_OPERATION错误。

level表示帧缓冲附着的纹理图像的mipmap的等级,而且一定是0。否则会出现INVALID_VALUE错误。

如果texture不是0,textarget一定是TEXTURE_2D,TEXTURE_CUBE_MAP_POSITIVE_X,TEXTURE_CUBE_MAP_POSITIVE_Y,TEXTURE_CUBE_MAP_POSITIVE_Z,TEXTURE_CUBE_MAP_NEGATIVE_X,TEXTURE_CUBE_MAP_NEGATIVE_Y,TEXTURE_CUBE_MAP_NEGATIVE_Z中的一个。

如果texture不是0,且如果FramebufferTexture2D成功了,那么指定的纹理图像将会被用作是逻辑缓冲,这个逻辑缓冲由当前绑定在target上的帧缓冲的attachment作为标识。指定的附着点的FRAMEBUFFER-ATTACHMENT-OBJECT-TYPE的值被设置到TEXTURE,FRAMEBUFFER_ATTACHMENT-OBJECT-NAME被设置到texture。另外,对有名字的附着点的FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL的值设置到level。如果texture是立方体贴图纹理,那么有名的附着点的FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE的值设置到textarget。所有的由attachement只指定的附着点的所有其他状态的值都设置为默认值,这些默认值在表6.24中列出。对于纹理对象的状态没有什么改变,绑定在目标靶target的帧缓冲对象的逻辑缓冲的在attachment的之前的所有附着点都破裂了。另一方面,如果,附着没有成功,对于纹理对象或者帧缓冲对象的状态都没有任何变化。

函数FramebufferTexture2Dtexture名字为0将会分离当前绑定在target的帧缓冲的所有attachment标识的图像。由attachment指定的附着点的所有状态值都被设置为如表6.24的默认值。

如果纹理对象在其图像附着在当前绑定的帧缓冲上是被删除,那么就好像是FramebufferTexture2D在调用时texture参数是0,作用于每个在当前绑定的帧缓冲上附着的图像的附着点一样。换句话说,在当前绑定的帧缓冲上的所有的附着点上第一次分离了纹理图形。注意,纹理图像不是从其他的帧缓冲上分离的。从其他帧缓冲对象上分离纹理图像是由应用来负责的。

4.4.4 在纹理和帧缓冲之间的反馈循环

当纹理对象可以同时用作GL操作的源和目的时,可能会存在一个反馈回路。当存在反馈回路时,会导致无定义的行为。这一节将详细介绍渲染反馈回路的小节(见3.7.7节)和纹理复制反馈回路的小节(见3.7.2节)。

  • 渲染反馈回路

将纹理附着在帧缓冲对象上的机制不会阻止在绘画的帧缓冲上附着绑定在纹理单元上的二维纹理图像。当发生这种状况时,访问图像的纹理操作将会产生未定义的结果,如同3.7.7节结尾介绍的那样。这种条件导致的未定义的表现下面会详细介绍。这样未定义的纹理操作很有可能是未定的碎片处理操作留下的最终的结果,应该是要避免的。

当纹理对象是绑定的而且是可以做纹理处理时,为了避免在当前绑定的帧缓冲上附着纹理图像,可以采用一些特殊的预防措施。OpenGL ES渲染操作写入的像素,而当这些像素在当前绑定的纹理中被用做纹素需要同时读取这些像素,这样就创建了一个渲染反馈回路。这样的场景下,帧缓冲会被认为是帧缓冲完整的,但是在这种状态下,被渲染的碎片的值是未定义的。纹理采样值也有可能是未定义的,如同3.7.7节中“渲染反馈回路”中介绍的那样。

特别的,如果下面的所有条件都成立,被渲染的碎片的值会是未定义的:

  1. 纹理对象T的图像附着在当前绑定的帧缓冲的附着点A。
  2. 纹理对象T当前绑定在纹理单元U上
  3. 当前可编程的顶点或者碎片处理状态,有可能会从绑定在纹理单元U上的纹理对象T上采样。

当下面任意一个条件具备时,被渲染的碎片的值都会是未定义的:

  1. 纹理对象T的TEXTURE_MIN_FILTER的值是NEAREST或者LINEAR,且附着点A上的FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL的值是0(纹理对象的0级图像阵列)。
  2. 纹理对象T的TEXTURE_MIN_FILTER的值是NEAREST_MIPMAP_NEAREST,NEAREST_MIPMAP_LINEAR,LINEAR_MIPMAP_NEAREST,LINEAR_MIPMAP_LINEAR中的一个,而且附着点A的FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL的值在纹理对象T指定的mipmap等级的范围之内。

在这次讨论中,如果活跃的碎片或者顶点着色器包含了一些可以对绑定在纹理单元U上的纹理对象T进行采样的规范,那么绑定在纹理单元U上的纹理对象T采样就是可能的,甚至是那些规范仅仅是在一定条件下被执行。

  • 纹理复制反馈回路

和渲染反馈回路相同,纹理图像是被附着在读入帧缓冲上的,同时又是CopyTexImage操作的目的地,如同3.7.2节中“纹理复制反馈回路”中介绍的那样,也是有可能的。当条件成立时,复制操作对纹素的写入和在可能存在的读帧缓冲中用作像素使用时,对这些纹素的读取,会形成一个纹理复制反馈回路。这种场景下,复制操作写入的纹素的值是未定义的。

具体的,如果下面的条件成立,复制的纹素的值是无定义的:

  1. 纹理对象T的图像附着在当前绑定的帧缓冲对象的附着点A。
  2. 选择的读缓冲是附着点A。
  3. T被绑定到CopyTexImage操作的纹理目标靶上。
  4. 复制操作的level参数选择了附着在A上的同一张图像。

4.4.5 帧缓冲完整性

如果帧缓冲的所有的附着图像,要求用于渲染和读取的所有的参数,都定义一致而且满足下面的要求,则这个帧缓冲对象被称为是一个完整的帧缓冲。帧缓冲完整性的规则是基于附着图像的性质,和一些依赖于实现的约束的。如果想要帧缓冲被高效的用作OpenGL ES帧缓冲的渲染操作的目的和OpenGL ES帧缓冲的读取操作源,那么帧缓冲必须是完整的。

附着图像的内部格式会影响帧缓冲的完整性,所以第一次定义图像的内部格式和可以被附着的附着点是非常有用的。图像的内部格式在表4.5中有总结。颜色可渲染的个是包括红,绿,蓝和可能的透明度通道;深度可渲染的格式包括深度通道;模板可渲染的格式包括模板通道。

image

不在表4.5中列出的格式,包括压缩的内部格式,不论他们包含了什么通道,都不是颜色,深度,模板可渲染的。

  • 帧缓冲附着完整性

如果帧缓冲的附着点attachmentFRAMEBUFFER_ATTACHMENT_OBJECT_TYPE的值不是NONE,被称为名为image的帧缓冲可附着图像附着到帧缓冲的附着点上。image通过attachment中的状态来标识,如同在4.4.2节中介绍的。

帧缓冲附着点attachmentattachmentFRAMEBUFFER_ATTACHMENT_OBJECT_TYPENONE时(比如没有附着图像),或者下面所有的条件都成立时,被认为是具备帧缓冲附着完整性:

  1. image是已经存在的对象的一部分,其中这个对象的名字由FRAMEBUFFER_ATTACHMENT_OBJECT_NAME指定,类型由FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE指定。
  2. image的宽和高一定是非零的。
  3. 如果attachmentCOLOR_ATTACHMENT0,image一定有一个颜色可渲染的内部格式。
  4. 如果attachmentDEPTH_ATTACHMENT,image一定有一个深度可渲染的内部格式。
  5. 如果attachmentSTENCEL_ATTACHMENT,image一定有一个模板可渲染的内部格式。
  • 帧缓冲完整性

在这一节,每个规则后面都有一个粗体的错误枚举。

如果是窗口系统提供的帧缓冲或者下面所有的条件成立,帧缓冲对象target被认为是帧缓冲完备的:

  1. 所有帧缓冲附着点是帧缓冲附着点完备的。FRAMEBUFFER_INCOMPLETE_ATTACHMENT
  2. 在帧缓冲上至少一副图像时附着的。FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT
  3. 所有附着的图像有相同的宽和高。FRAMEBUFFER_INCOMPLETE_DIMENSIONS
  4. 附着图像的内部格式的组合没有违反基于实现的系列约束。FRAMEBUFFER_UNSUPPORTED

在帧缓冲完备性规则的每个条件后面的粗体枚举,表示当违反该条件时,CheckFramebufferStatus函数产生的返回值。如果违反超过一个条件,确切的CheckFramebufferStatus要返回哪一条枚举,是依赖于实现的。

执行下面操作中的任何一条都有可能改变帧缓冲是否完备。

  1. BindFramebuffer绑定到不同的帧缓冲上。
  2. FramebufferTexture2DFramebufferRenderbuffer将图像附着在帧缓冲上。
  3. FramebufferTexture2DFramebufferRenderbuffer将图像从帧缓冲上分离。
  4. 调用TexImage2D,CopyTexImage2D,CompressedTexImage2D改变帧缓冲上附着的纹理图像的宽,高和内部格式。
  5. 调用RenderbufferStorage改变在帧缓冲上附着的渲染缓冲的宽,高和内部格式。
  6. 调用DeleteTextures,DeleteRenderbuffers删除在当前帧缓冲绑定的帧缓冲对象上附着的包含图像的对象。

尽管OpenGl ES为帧缓冲可附着图像定义了一系列的内部格式,比如纹理图像和的渲染缓冲图像,但是一些实现还是不能支持渲染一些特殊的内部格式组合。如果在帧缓冲对象上附着的图像的格式的组合并不被实现所支持,那么帧缓冲就是不完备的,产生条件标签FRAMEBUFFER_UNSUPPORTED下。对于不产生FRAMEBUFFER_UNSUPPORTED的帧缓冲,必然至少会有一种内部格式的组合。

由于特别的帧缓冲完备性测试的依赖于实现的条件,和因为帧缓冲完备性可以在附着的图像做修改时发生变化,尽管不是强制要求,但还是强烈建议应用要在渲染之前去检查帧缓冲是否是完备的。当前绑定在target上的帧缓冲对象的状态可以通过下面函数查询:

enum CheckFramebufferStatus(enum target);

如果target不是FRAMEBUFFER,会产生INVALID_ENUM。如果CheckFramebufferStatus产生错误,会返回0。

否则,会返回一个标识绑定在target的帧缓冲是否完备的枚举值,如果不是完备的,枚举会标识出帧缓冲完备性违反的规则。如果这缓冲是完备的,那么会返回FRAMEBUFFER_COMPLETE

  • 帧缓冲完备性对帧缓冲操作的影响

如果当前绑定的帧缓冲不是完备的,那么企图使用帧缓冲用来读写会产生错误。这意味着渲染函数例如DrawArraysDrawElements,还有帧缓冲读取函数ReadPixelsCopyTexSubImage,在帧缓冲不完整是,会产生INVALID_FRAMEBUFFER_OPERATION错误。

4.4.6 帧缓冲状态对帧缓冲相关值的影响

FRAMEBUFFER_BINDING的值发生变化,当前绑定的帧缓冲对象的状态发生变化,或者当前绑定的帧缓冲上附着的图像发生变化时,表6.21(依赖实现的像素深度)列出的状态变量的值也会发生变化。

FRAMEBUFFER_BINDING是0,在表6.21中列出的状态变量的值是由实现来定义的。

FRAMEBUFFER_BINDING是非零,如果当前绑定帧缓冲对象不是完备的帧缓冲,那么表6.21中列出的状态变量将是未定义的。

FRAMEBUFFER_BINDING是非零而且当前绑定的帧缓冲是完备的,那么在表6.21中列出的状态变量的值,将完全由由FRAMEBUFFER_BINDING,当前绑定的帧缓冲的状态,和当前帧缓冲附着的图像的状态决定。

4.4.7 附着图像中像素和元素之间的映射

FRAMEBUFFER_BINDING是非零的,写入帧缓冲的操作会改变附着在被选择的逻辑缓冲上的附着的图像,从帧缓冲中读取的操作读取在选中的逻辑缓冲上附着的图像。

如果附着的图像是一个渲染缓冲图像,那么窗口坐标(x_w,y_w)对应于在同样坐标系的渲染缓冲的图像的值。

如果附着的图像时纹理图像,那么窗口坐标(x_w,y_w)对应于纹理0级图像阵列的在相同组标下的值。

  • 转换成帧缓冲可附着图像通道

FRAMEBUFFER_BINDING是非零,颜色值可以写入到帧缓冲时,对于每个绘图缓冲,R,G,B,A值被转换成被选中的逻辑缓冲上附着的帧缓冲附着图像的内部格式对应的内部通道,得出的内部通道被下载附着在逻辑缓冲的图像上。ColorMask,DepthMask,StencilMask,StencilMaskSeparate这些蒙版操作同样有效。

4.4.8 错误

如果CheckFramebufferStatus不是FRAMEBUFFER_COMPLETE,任何企图渲染到帧缓冲或者从帧缓冲中读取的操作都会产生INVALID_FRAMEBUFFER_OPERATION错误。

FRAMEBUFFER_BINDING的值是0,GetFramebufferAttachmentParameteriv调用时,会产生INVALID_OPERATION错误。

FRAMEBUFFER_BINDING的值是0,FramebufferRenderbuffer,FramebufferTexture2D调用时,会产生INVALID_OPERATION错误。

FRAMEBUFFER_BINDING的值是0,RenderbufferStorage调用时,会产生INVALID_OPERATION错误。

如果在调用```RenderbufferStorage``时,使用的widthheight参数的值比MAX_RENDERBUFFER_SIZE大,会产生INVALID_VALUE错误。

如果在调用RenderbufferStorage时,internalformat不在支持的颜色,深度或者模板格式之中,会出现INVALID_ENUM错误。

如果在调用FramebufferRenderbuffer时,renderbuffer不是渲染缓冲对象的名字,会产生INVALID_OPERATION错误。

如果在调用FramebufferTexture2D时,texture不是纹理对象的名字,会产生INVALID_OPERATION错误。

如果在调用FramebufferTexture2D时,level比0小,会产生INVALID_VALUE错误。

如果在调用FramebufferTexture2D时,level比0大,会产生INVALID_VALUE错误。

如果在调用CheckFramebufferStatus时,target不是FRAMEBUFFER,会产生INNVALID_ENUM错误。

如果在调用RenderbufferStorage时,OpenGL ES不能创建一个要求大小的数据存储空间,会产生OUT_OF_MEMORY错误。

如果在调用GenerateMipmap时,targetTEXTURE_CUBE_MAP而且当前绑定在TEXTURE_CUBE_MAP上的纹理对象不是完备的立方体,会产生INVALID_OPEARTION错误。

推荐阅读更多精彩内容