读取像素 Reading Pixels
从帧缓冲区读取像素并将其放入像素包缓冲区或客户端内存的方法如下所示。 我们按照像素读取过程发生的顺序描述各个阶段。
- RGBA pixel data in
- Convert to float
- Clamp to [0, 1]
- Pack
- byte, short, int, float, or packed pixel component data stream
ReadPixels 的操作。
- 并非对所有数据格式都执行 2、3 操作。 未显示深度和模板像素路径。
选择读取缓冲区 Selecting Buffers for Reading
在OpenGL中,读取像素时使用读取缓冲区来控制从帧缓冲对象的颜色缓冲区中读取像素的行为。读取缓冲区可以通过以下命令进行控制:
void glReadBuffer(enum src);
void glNamedFramebufferReadBuffer(uint framebuffer, enum src);
如果操作的是默认帧缓冲区,即绑定到 READ_FRAMEBUFFER
的帧缓冲区,则可以使用 glReadBuffer
命令。对于命名的帧缓冲区对象,可以使用 glNamedFramebufferReadBuffer
命令。
读取缓冲区的选择取决于参数 src
的值。对于默认帧缓冲区,src
必须是预定义的枚举值之一,如 FRONT_AND_BACK
、FRONT
、LEFT
、BACK
、RIGHT
或 NONE
。对于帧缓冲区对象,src
可以是 COLOR_ATTACHMENTi
的形式,其中 i
是附加点的索引。
通过调用 GetIntegerv
并将 pname
设置为 READ_BUFFER
,可以查询当前绑定的读取帧缓冲区的读取缓冲区。
读取像素 ReadPixels
初始化时,PIXEL_PACK_BUFFER绑定为0,这意味着像ReadPixels这样的图像读取和查询命令会将像素结果返回到客户端内存指针参数中。然而,如果一个非零的缓冲对象被绑定为当前的像素打包缓冲(Pixel Pack Buffer),那么该指针参数被视为该指定缓冲对象内的偏移量。
使用以下命令来读取像素:
void glReadPixels( int x, int y, sizei width, sizei height, enum format, enum type, void *data );
void glReadnPixels( int x, int y, sizei width, sizei height, enum format, enum type, sizei bufSize, void *data );
其中,x
和 y
参数定义了读取区域的左下角坐标,width
和 height
指定了要读取的像素区域大小;format
和 type
参数则指定了输出像素数据的颜色格式和数据类型;对于ReadnPixels,额外的bufSize
参数限制了读取的最大字节数。而提供的data
指针指向接收像素数据的目标内存位置。
格式和类型的首选值可以通过分别使用 pname
IMPLMENTATION_COLOR_READ_FORMAT
和 IMPLMENTATION_COLOR_READ_TYPE
调用 GetIntegerv
来确定。 优选的格式可以根据当前绑定的读取帧缓冲器的所选读取缓冲器的格式而变化。
从帧缓冲区获取像素 Obtaining Pixels from the Framebuffer
glReadPixels
函数在不同缓冲格式下读取像素数据的规则:
-
当format为DEPTH_COMPONENT时,像素值从深度缓冲区获取。如果有多重采样缓冲(SAMPLE_BUFFERS值为1),则从该缓冲区中的深度样本获取值。推荐使用最中心的样本的深度值,但实现可以选择任何对每个像素深度样本值的函数。
-
如果format为DEPTH_STENCIL,则同时从深度缓冲区和模板缓冲区获取值。type必须是UNSIGNED_INT_24_8或FLOAT_32_UNSIGNED_INT_24_8_REV。若有多重采样缓冲,同样按照上述方式从深度和模板样本中获取值。
-
若format为STENCIL_INDEX,则从模板缓冲区获取值。存在多重采样缓冲时,从其中的模板样本获取值,推荐使用最中心样本的模板值,但实现可以自行选择处理方法。
-
对于其他所有格式,像素值将从由读取缓冲区所选择的颜色缓冲区获取。
-
glReadPixels
会根据指定的(x, y)坐标以及宽度、高度参数,从选中的缓冲区逐个获取像素值。若这些像素点位于当前GL上下文分配窗口之外,或者位于当前绑定读取帧缓冲对象所附加图像之外,那么这些像素点的值是未定义的。 -
当READ_FRAMEBUFFER_BINDING不为零时,无论这些值是如何放置到缓冲区中的,都会从选定的缓冲区获取值。如果format是RED、GREEN、BLUE、RG、RGB、RGBA、BGR或BGRA之一,红、绿、蓝、alpha通道值将从每个像素位置处的选定缓冲区获取。
-
如果format为整数格式,而颜色缓冲区不是整数格式,或者颜色缓冲区是整数格式而format不是整数格式,会生成INVALID_OPERATION错误。
-
当READ_FRAMEBUFFER_BINDING非零时,红、绿、蓝、alpha通道值首先从对应逻辑缓冲区所附加图像内部组件值获取。然后根据缓冲区的基础内部格式(如表8.11所示)将内部组件转换为RGBA颜色。如果G、B、A组件在内部格式中不存在,则分别默认为0、0和1。
RGBA值的转换 Conversion of RGBA values
仅当格式不是 STENCIL_INDEX
、DEPTH_COMPONENT
或 DEPTH_STENCIL
时才适用此步骤。
R、G、B 和 A 值形成一组元素。 对于有符号或无符号标准化定点颜色缓冲区,分别使用公式 2.2 或 2.1 将每个元素转换为浮点。 对于整数或浮点颜色缓冲区,元素未修改。
深度值的转换 Conversion of Depth values
仅当格式为 DEPTH_COMPONENT
或 DEPTH_STENCIL
并且深度缓冲区使用定点表示时,此步骤才适用。
元素被视为 [0, 1] 中具有 m 位的定点值,其中 m 是深度缓冲区中的位数(参见第 13.8.1 节)。 如果深度缓冲区使用浮点表示,则无需转换。
最终转换 Final Conversion
控制读取颜色的钳制
-
void ClampColor( enum target, enum clamp );
target
:CLAMP_READ_COLOR。clamp
可以是:TRUE
:启用读取颜色钳制。FALSE
:禁用读取颜色钳制。FIXED_ONLY
:仅当所选读取颜色缓冲区具有定点分量时,启用读取颜色钳制。
对于整数RGBA颜色,每个分量都会被钳制到相应类型的可表示范围内。
对于浮点RGBA颜色,若类型为FLOAT或HALF_FLOAT且启用了读取颜色钳位,那么每个分量会被钳制到[0, 1]区间内。随后,根据表18.2中的适当转换公式应用于该分量。
如果类型是UNSIGNED_INT_10F_11F_11F_REV且格式为RGB,当启用读取颜色钳位时,每个分量将被钳制到[0, 1]之间。然后返回的数据被打包成一系列uint值。红色、绿色和蓝色分量按照第2.3.4.3节和2.3.4.4节中描述的方式转化为无符号11位浮点、无符号11位浮点和无符号10位浮点。最终,得到的红11位、绿11位和蓝10位按照表8.8所示的方式打包成UNSIGNED_INT_10F_11F_11F_REV格式的首、次、第三个分量。
如果类型是UNSIGNED_INT_5_9_9_9_REV且格式为RGB,在启用读取颜色钳位的情况下,每个分量也会被钳制到[0, 1]之间。然后返回的数据同样被打包成一系列uint值。红色、绿色和蓝色分量按内部格式为RGB9_E5时第8.5.2节所述方式转化为红色、绿色、蓝色和指数整数。这些值再按照表8.8所示的方式打包为UNSIGNED_INT_5_9_9_9_REV格式的首至第四个分量。
对于其他类型,以及对于浮点或无符号归一化固定点颜色缓冲区,无论是否启用读取颜色钳位,每个分量都将被钳制到[0, 1]区间内。而对于有符号归一化固定点颜色缓冲区,若启用了读取颜色钳位,或者类型代表无符号整数分量,则每个分量钳制到[0, 1]区间;否则,类型代表有符号整数分量,每个分量钳制到[-1, 1]区间。钳位后,应用表18.2中适当的转换公式于该分量。
对于索引值,如果类型不是FLOAT或HALF_FLOAT,则最终转换包括使用表18.3中给出的值对索引进行掩码操作。如果类型是FLOAT或HALF_FLOAT,则整数索引将被转换为GL float或half数据值。
放置在像素打包缓冲区或客户端内存中 Placement in Pixel Pack Buffer or Client Memory
像素打包缓冲(Pixel Pack Buffer)在OpenGL中的作用是作为图形数据从GPU传输到客户端内存或另一个缓冲区的中间暂存区域。当一个非零像素打包缓冲被绑定时:
- 数据写入操作将基于该缓冲区内的偏移量进行。
- 如果试图访问的数据范围超出了像素打包缓冲的大小,则会生成INVALID_OPERATION错误。
- 若data参数所指数据长度不能被相应GL数据类型的存储单位整除,也会触发INVALID_OPERATION错误。
像素数据按照与从内存向OpenGL复制像素矩形相同的规则填充到打包缓冲或客户端内存中,遵循相应的PACK_前缀参数设定的格式和布局。
根据指定的格式(如RED、GREEN、BLUE、RG、RGB、BGR等),可能只会写入对应数量的分量元素,而非所有组内元素。如果格式包含全部颜色分量,则所有元素都将被写入目标内存区域。