关于OpenGL的图像数据格式

1. 引言

当我们使用OpenGL进行有关图片处理的时候,例如做纹理映射相关程序的时候,一定调用过以下这些函数:
1. glTexImage{1,2,3}D
2. glCopyTexImage{1,2,3}D
这些函数中经常会遇到一个参数 internalFormat,同时也会遇到另外两个参数 format和type 这些参数从表意上就没有width、height这样的参数那么直观。本文就是详细介绍一下参数internalFormat的方方面面,另一篇文章《OpenGL像素格式》介绍另外两个参数format和type。

2. 简介

在OpenGL中什么地方可以作为图像可以存储图像(Image)呢?首先我们想到的是:
1. 纹理对象
2. 帧缓存对象
3. 像素缓冲区对象
这三类对象是在显卡的显存中,那么还有一个地方是内存中
4. 内存中的一块区域
我们需要对这些对象进行分类,其中1和2是有特定用途的,1是作为给几何体贴图使用,2可以理解为我们在屏幕上看到的场景。3和4就没有那么特定的用处了,可以把它们理解为存储像素数据的仓库。
基于这样一种认识,那么接下来我们需要解释的是,1和2里面存储的数据是什么格式的,是RGB、RGBA还是其他方式,这就是本文讨论的主题图像格式(Image Format)[个人翻译,中文准确翻译有待考究]

3. 详细介绍

图像格式(ImageFormat)描述了图像在纹理和帧缓存中的存储方式,定义了图像数据的含义。
图像格式有三种类型:颜色、深度、深度/模板 ,所有的格式都可以被应用到纹理存储单元或者帧缓存存储单元(除非特别的说明)

3.1 颜色格式

颜色格式可以以3种方式存储,归一化的整型数(normalized integers),浮点数和整数。其中单位化的整型和浮点型在shader中会被解析为浮点数组,整型会被解析为整型数据。
归一化的整型数可以分为两类,包括有符号类型和无符号类型,有符号类型的取值范围是[-1,1],无符号类型的取值范围是[0,1]
OpenGL在定义颜色格式的时候,语法如下:

GL_[components][size][type]
  • 1

components:指的是颜色分量,OpenGL只允许图像格式使用下面的4种:"R" "RG" "RGB" "RGBA",size定义了每种分量占用的位数(bit),type定义了颜色格式使用的存储方式,可以的取值包括:

type取值参数解释
“”(空)无后缀表示使用的是无符号的的归一化整型数
“_SNORM”归一化的有符号整型
“F”浮点类型,如:GL_RGBA32F指每个分量(R\G\B\A)是32位的浮点数
“I”有符号整型,如GL_RGBA8I指每个分量都是位于[-128,127]的整型数
“UI”无符号整形数

根据上面的介绍,如果你需要一个3分量的无符号整型格式,并且每个分量占用8位(1个字节),那么使用的格式应该是:GL_RGB8UI
对于每一种类型的颜色格式,颜色的每一个分量在位数上有一个限制:

格式type每一个分量的位数
无符号归一化整型2、4、5、8、10、12、16
有符号归一化整型8、16
无符号整型8、16、32
有符号整型8、16、32
浮点数16、32

需要注意的是:

1. 对于分量位数是2位的情况,只能使用RGBA,使用其他方式都是不允许的(如你不能使用GL_RG2这种格式)
2. 对于分量位数是4,5,12的情况,只能使用RGB和RGBA,使用其他方式都是不允许的
3. 对于分量位数是10的情况,只能使用RGB,其他方式都是不允许的(例如你不能使用GL_RGBA10这种格式

在使用过程中也可以省略分量占用的位数,这种情况仅仅适用于无符号归一化的整型格式,如果省略了,那么OpenGL会帮我们选择一个位数。一般来说,最好还是指定一个位数。

3.2 特殊的颜色格式

以上所讲的是常规的颜色格式的情况,OpenGL除此之外还支持部分其他的颜色格式,列举如下:

颜色格式格式说明
GL_R3_G3_B2归一化的整型,RG分量占用3位,B分量占用2位(正好1个字节)
GL_RGB5_A1RGB分量分别占用5位,A分量占用1位,这种格式通常用于压缩格式
GL_RGB10_A2RGB分量分别占用10位,A分量占用2位(正好4个字节)
GL_RGB10_A2UI无符号整型数,RGB占用10位,A占用2位
GL_R11F_G11F_B10F浮点数类型的格式,最大程度节约存储空间
GL_RGB9_E5浮点类型的格式,它的计算方式非常复杂,一般不用于帧缓冲格式,E是科学记数法的一个标识

3.3 压缩的格式

纹理压缩是非常重要的减少内存占用的一种方式,当可以使用纹理压缩方式时,最好都能运用这一方式。在OpenGL中有两种类型的压缩格式:通用的压缩方式和特定的压缩方式。
通用的纹理压缩方式的实现依赖于OpenGL的硬件驱动,一般来说实现比较自由,最好还是尽量避免使用。
通用的纹理压缩格式使用下面的语法:

GL_COMPRESSED_components
  • 1

components可以设置为RED RG RGB RGBA SRGB SRGB_ALPHA
压缩格式并不能被设置为帧缓冲区的格式

3.4 深度格式

深度格式有两种类型,归一化整型和浮点数类型,深度图像格式提供一下几种:

GL_DEPTH_COMPONENT16
GL_DEPTH_COMPONENT24
GL_DEPTH_COMPONENT32
GL_DEPTH_COMPONENT32F

3.4 深度、模板格式

深度模板格式融合深度和纹理,可以让你设置深度缓冲区的同时设置模板缓冲区。
如果OpenGL提供了ARB_stencil_texturing扩展(OpenGL4.3)那么纹理对象可以设置一个参数来通过取样器获取模板的部分。
这种类型的图像格式只有两种:

GL_DEPTH24_STENCIL8
GL_DEPTH32F_STENCIL8
  • 1
  • 2

3.6 模板格式

模板格式用来存储一个模板值,模板值一般是无符号的整型,所有的模板格式类型使用GL_STENCIL_INDEX#的方式,包括

GL_STENCIL_INDEX1
GL_STENCIL_INDEX4
GL_STENCIL_INDEX8
GL_STENCIL_INDEX16
  • 1
  • 2
  • 3
  • 4

3.7 常用的图像格式

OpenGL规范对于图像格式的实现相对比较宽松,不过规范中也指明了某些格式必须要支持,包括以下的一些格式:

3.7.1 支持纹理和帧缓冲区

基本格式数据类型每一个分量占据的位数
RGBA,RG,RED归一化整型8,16
RGBA,RG,RED浮点型16,32
RGBA,RG,RED无符号整型8,16,32
RGBA,RG,RED有符号整型8,16,32

另外还包括

GL_RGB10_A2
GL_RGB10_A2UI
GL_R11F_G11F_B10F
GL_SRGB8_ALPHA8
GL_DEPTH_COMPONENT16
GL_DEPTH_COMPONENT24
GL_DEPTH_COMPONENT32F
GL_DEPTH24_STENCIL8
GL_DEPTH32F_STENCIL8
GL_STENCIL_INDEX8(4.3只支持帧缓冲区,4.4支持帧缓冲区和纹理)

3.7.2 只支持纹理

以下的这些格式必须支持纹理,但是能否支持帧缓冲区OpenGL规范并没有强制要求:

基本类型数据格式分量占据的位数
RGB无符号归一化整型8,16
RGBA,RGB,RG,RED有符号归一化整型8,16
RGB浮点16,32
RGB有符号整型8,16,32
RGB无符号整型8,16,32
RG,RED无符号整型Compressed with RGTC(TODO?)

此外还包括:

GL_SRGB8
GL_RGB9_E5
  • 格式查询

OpenGL的图像格式的许多属性根据OpenGL的实现不同而略有差异(这主要是OpenGL对于图像格式的要求比较宽松所致),OpenGL在4.3以及以上版本提供了一种查询图像格式的机制,可以使用下面的函数来获取图像格式:

void glGetInternalFormativ​(
GLenum target​, 
GLenum internalformat​, 
GLenum pname​, 
GLsizei bufSize​, 
GLint *params​);

void glGetInternalFormati64v​(
GLenum target​, 
GLenum internalformat​, 
GLenum pname​, 
GLsizei bufSize​, 
GLint64 *params​);

3.9 过时的图像格式

在OpenGL Legecy中有两种类型的颜色格式Luminance和intensity,它们表示一般只有两个分量的格式(有点类似于RED或者是RG),但是它们的表现和RED与RG不一样。体现着:
当GL_RED在shader中使用时, vec4是(Red,0,0,1)
GL_INTENSITY是(I,I,I,I),GL_LUMINANCE是(L,L,L,1),GL_LUMINANCE_ALPHA是(L,L,L,A)
这两种格式有8位和16位两种:

GL_INTENSITY8, 
GL_INTENSITY16,
GL_LUMINANCE8,
GL_LUMINANCE_ALPHA16

4. 其他

在设置OpenGL的InternalFormat的时候相对比较自由,但是一般来说调用需要设置internalformat的函数时,一般会有pixel format和type这两个参数与之在一起出现,例如:

void glTexImage2D(  GLenum target,
    GLint level,
    GLint internalFormat,
    GLsizei width,
    GLsizei height,
    GLint border,
    GLenum format,
    GLenum type,
    const GLvoid * data);

简单来说internalFormat定义了GPU中像素的格式和存储方式,format和type以及data这三个参数共同定义了在内存中像素的格式和存储方式,如果我们设置这两者格式差异很大,OpenGL在内部会帮助我们转换,这样往往带来性能上的损失,一般来说最好把二者设置的比较兼容,方便OpenGL做数据的传输,避免转换。

参考:
Image Format
stackoverflow关于internalformat讨论

©️2020 CSDN 皮肤主题: 撸撸猫 设计师:设计师小姐姐 返回首页