• 简介

glTexImage2D在OpenGL中主要用来指定二维纹理和立方体纹理,函数原型如下(OpenGL 2.1):

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

参数:

target :指定纹理单元的类型是哪一种,必须指定为 GL_TEXTURE_2D, GL_PROXY_TEXTURE_2D, GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X, GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, or GL_PROXY_TEXTURE_CUBE_MAP中的一个。二维纹理需要指定为GL_TEXTURE_2D

level:指定纹理单元的层次,非mipmap纹理level设置为0,mipmap纹理设置为纹理的层级

internalFormat:指定OpenGL是如何管理纹理单元中数据格式的。网络上很多解释说这个参数必须和后面的format参数一样,这个说法是不正确的

width:指定纹理单元的宽度

height:指定纹理单元的高度

border:指定纹理单元的边框,如果包含边框取值为1,不包含边框取值为0

format:指定data所指向的数据的格式

type:指定data所指向的数据的类型

data:实际指向的数据是什么,这个参数有两种解释

下面对这些参数作更详细的解释,记录下来备忘。

target:由于目前只用到了二维纹理的部分,因此这个参数必须指定为GL_TEXTURE_2D

level:目前只用在非mipmap纹理方式下,因此这个参数必须设置为0

internalFormat:对于这个参数需要重点解释一下,以前的使用中一般也是参考网络上的解释将它和后面的format参数设置为一样的,但是具体是什么原因并不清楚。查阅一些资料后,对这个参数有了更好的理解。

以下是stackoverflow 中的一段解释:

The format and type parameters describe the data you are passing to OpenGL as part of a pixel transfer operation. The internalforamt describes the format of the texture. You're telling OpenGL that you're giving it takes that looks like X, and OpenGL is to store it in a texture where the data is Y. Theinternalformat is "Y".

从描述中我们知道:internalFormat用来指定OpenGL中纹理单元中的格式是什么样的,而参数中的后三个(format 、type、 data)是用来指定用来传输到OpenGL中纹理单元数据的格式是怎么样的。回忆一下我们是如何加载一张图片作为纹理的,一般过程如下:

  1. 读取一张图片到内存中的某处(假设到pBytes指向的内存中)
  2. 生成一个绑定纹理ID(假设为texID),并绑定纹理ID到一个纹理单元(glGenTexture和glBindTexture)
  3. 使用glTexImage2D将内存中的数据拷贝到OpenGL纹理单元中
  4. 设置纹理单元的过滤方式、插值方式等(一般是使用glTexParameter)
  5. 绑定纹理(texID)并使用纹理

上面的internalForamt参数指定的就是texID对应纹理单元中的数据格式(An Image Format describes the way that the images in Textures and renderbuffers store their data. They define the meaning of the image's data.),它是对OpenGL硬件驱动的一种很强的提示,告诉驱动它里面的数据是怎么组织的。

因此如果我们将internalForamt中的格式指定的和format中格式一致就可以更快地进行传输,而不需要在二者之间进行转换。

format、type、data指定的是pBytes中数据是怎么样组织的(A Pixel Transfer operation is the act of taking pixel data from an unformatted memory buffer and copying it in OpenGL-owned storag)

参数format和type指定了pBytes中的像素数据该如何解译:

其中format指定了每一个像素所包含的成分以及这些成分的顺序是怎么样的,比如:GL_RGBA指定了每个像素包含RGBA四个部分,顺序是R、G、B、A 而如果我们指定GL_BGRA则说明每个像素包含四个部分,但是顺序却不一样;

type则指定每一个成分需要几个字节来表示,比如我们指定GL_UNSIGNED_BYTE在说明每个成分需要一个unsigned byte来表示也就是一个字节,type的取值还包括:

  • GL_(UNSIGNED_)BYTE​: 1 byte
  • GL_(UNSIGNED_)SHORT​: 2 bytes
  • GL_(UNSIGNED_)INT​: 4 bytes
  • GL_HALF_FLOAT​: 2 bytes
  • GL_FLOAT​: 4 bytes

参数data在上文中说有两种解释:

1.当有缓冲区绑定到 GL_PIXEL_PACK/UNPACK_BUFFER 时,这时候使用了PBO(Pixel Buffer Object),此时的data是一个指向缓冲区对象数据的偏移量

2.当没有缓冲区绑定到GL_PIXEL_PACK/UNPACK_BUFFER 时,这是data是指向内存中的指针(上文中提到的pBytes)

这两者之间的转换过程:(将Memory中的格式转换为纹理中的格式的过程):

包括如下两个阶段:

先将Memory转换为RGBA的方式(中间过程),转换方式:

Memory                                            RGBA (中间过程)
----------------------------------------------------------------
RED                                                           R001
----------------------------------------------------------------
GREEN                                                       0G01
----------------------------------------------------------------
BLUE                                                          00B1
----------------------------------------------------------------
ALPHA                                                         000A
----------------------------------------------------------------
RGB                                                            RGB1
----------------------------------------------------------------
RGBA                                                           RGBA
----------------------------------------------------------------
LUMINANCE                                               LLL1
----------------------------------------------------------------
LUMINANCE_ALPHA                               LLLA
----------------------------------------------------------------

之后再从中间过程的RGBA转换到internalFormat指定的格式(转换的方式按下面的公式进行)

INTENSITY = R
LUMINANCE = R
R = R
G = G
B = B
A = A

举例说明:如果你指定format是GL_RGB,但是你指定internalFormat是GL_LUMINANCE ,那么转换过程是这样的

1.现将GL_RGB转为GL_RGBA其中A都是1

2.将GL_RGBA中的R成分给解释为LUMINANCE

另外一种情况,如果你将一个GL_RGB的format指定为GL_ALPHA的internalFormat,那么得到的值全都是0

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐