相关API
glGenTexture(GLsizei n,GLuint* textures)
作用: 生成纹理对象,用来产生你要操作的纹理对象的索引,比如你告诉OpenGL,我需要5个纹理对象,它会从没有用到的整数里返回5个给你
参数:
- n 要生成的纹理对象的数量
- textures 存储生成的纹理对象索引
void glBindTexture(GLenum target,GLuint texture)
作用: 绑定纹理对象
参数:
- target 绑定纹理类型,只能取值GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D或者GL_TEXTURE_CUBE_MAP
- texture 绑定纹理对象索引
void glTexImage2D(GLenum target,GLuint level,GLenum internalFormat,GLsizei width,GLsizei height,GLuint border,GLenum format,GLenum type,const GLvoid* data)
作用: 为2D纹理指定图片数据
参数:
- 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是如何管理纹理单元中数据格式的
- width 指定纹理单元的宽度
- height 指定纹理单元的高度
- border 指定纹理单元的边框,如果包含边框取值为1,不包含边框取值为0
- format 指定data所指向的数据的格式,取值为GL_RGBA、GL_RGB之类
- type 指定data所指向的数据的类型,取值为GL_(UNSIGNED_)BYTE (1字节)、GL_(UNSIGNED_)SHORT(2字节)、GL_(UNSIGNED_)INT (4字节)、GL_HALF_FLOAT (2字节)、GL_FLOAT(4字节)之一
- data 实际指向的数据是什么,有两种解释,当有缓冲区绑定到 GL_PIXEL_PACK/UNPACK_BUFFER 时,这时候使用了PBO(Pixel Buffer Object),此时的data是一个指向缓冲区对象数据的偏移量;
当没有缓冲区绑定到GL_PIXEL_PACK/UNPACK_BUFFER 时,这是data是指向内存中的指针(上文中提到的pBytes)
将Memory中的格式转换为纹理中的格式的过程:
包括如下两个阶段:
先将Memory转换为RGBA的方式(中间过程),转换方式:
之后再从中间过程的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
OpenGL中的贴图方式(转自OpenGL基本概念入门——纹理贴图)
OpenGL为我们提供了三种纹理——GL_TEXTURE_1D、GL_TEXTURE_2D和GL_TEXTURE_3D。它们分别表示1维纹理、2维纹理和3维纹理。无论是哪一中纹理,使用方法都是相同的:即先创建一个纹理对象和一个存储纹理数据的n维数组,在调用glTexImageN
D函数来传入相应的纹理数据。除此之外,我们可以一些函数来设置纹理的其他特性。
设置贴图模式
OpenGL提供了3种不同的贴图模式:GL_MODULATE,GL_DECAL和GL_BLEND。默认情况下,贴图模式是GL_MODULATE,在这种模式下,OpenGL会根据当前的光照系统调整物体的色彩和明暗。第二种模式是GL_DECAL,
在这种模式下所有的光照效果都是无效的,OpenGL将仅依据纹理贴图来绘制物体的表面。最后是GL_BLEND,这种模式允许我们使用混合纹理。在这种
模式下,我们可以把当前纹理同一个颜色混合而得到一个新的纹理。我们可以调用glTexEnvi函数来设置当前贴图模式:
glTexEnvi(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,TextureMode);
其中TextureMode就是想要设置的纹理模式,可以为GL_MODULATE,GL_DECAL和GL_BLEND中的任何一种。
另外,对于GL_BLEND模式,我们可以调用
glTexEnvfv(GL_TEXUTRE_ENV,GL_TEXTURE_ENV_COLOR,@ColorRGBA);
其中,ColorRGBA为一个表示RGBA颜色的4维数组。
纹理滤镜
在纹理映射的过程中,如果图元的大小不等于纹理的大小,OpenGL便会对纹理进行缩放以适应图元的尺寸。我们可以通过设置纹理滤镜来决定OpenGL对某个纹理采用的放大、缩小的算法。
调用glTexParameter来设置纹理滤镜。如:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILETER, MagFilter);//设置放大滤镜
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, MinFilter); //设置缩小滤镜
上述调用中,第一个参数表明是针对何种纹理进行设置,第二个参数表示要设置放大滤镜还是缩小滤镜。第三个参数表示使用的滤镜。可以为下面的值之一:
滤镜 | 描述 |
---|---|
GL_NEAREST | 取最邻近像素 |
GL_LINEAR | 线性内部插值 |
GL_NEAREST_MIPMAP_NEAREST | 最近多贴图等级的最近像素 |
GL_NEAREST_MIPMAP_LINEAR | 在最近多贴图等级的内部线性插值 |
GL_LINEAR_MIPMAP_NEAREST | 在最近多贴图等级的外部线性插值 |
GL_LINEAR_MIPMAP_LINEAR | 在最近多贴图等级的外部和内部线性插值 |
纹理映射(转自OpenGL基本概念入门——纹理贴图)
纹理坐标
要使用当前的纹理绘制图元,我们必须在绘制每个顶点之前为该顶点指定纹理坐标。只需调用
glTexCoord2d(s;t);
函数即可。其中,s、t是对于2D纹理而言的s、t坐标。对于任何纹理,它的纹理坐标都如同下图所示的那样:
对于任何纹理,无论纹理的真正大小如何,其顶端(左上角)的纹理坐标恒为(0,0),右下角的纹理坐标恒为(1,1)。也就是说,纹理坐标应是一个介于0到1之间的一个小数。
例如,下面的代码将使用当前纹理绘制一个三角形:
glBindTexture(Tex);
glBegin(GL_TRIANGLES);
glTexCoord2d(0,0);
glVertex3f(-10,-10,0);
glTexCoord2d(0,1);
glVertex3f(-10,10,0);
glTexCoord2d(1,1);
glVertex3f(10,10,0);
glEnd();
纹理缠绕
前面提到,纹理坐标应位于0-1之间。那么当纹理坐标大于这个值会出现什么情况呢?
我们可以对OpenGL进行设置,以决定当纹理坐标不位于这一区间时应采取的操作。我们可以指定两种操作:GL_CLAMP和GL_REPEAT。对于GL_CLAMP,超出纹理坐标的区域会使用纹理图像的边界颜色来代替,如下图所示。
而GL_REPEAT方式则是对纹理坐标进行重置而得到重复的图像。观察下图,你就能很容易地发现这一点。
可以调用glTexParameter设置缠绕方式:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,WrapMode);//在s方向上的缠绕方式
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,WrapMode);//在t方向上的缠绕方式
其中,WrapMode可取GL_CLAMP或者GL_REPEAT。
多贴图纹理
多贴图纹理(Mip
Mapping)为一个纹理对象生成不同尺寸的图像。在需要时,根据绘制图形的大小来决定采用的纹理等级或者在不同的纹理等级之间进行线性内插。使用多贴
图纹理的好处在于消除纹理躁动。这种情况在所绘制的景物离观察者较远时常常发生(如图6.6-1和6.6-2)。由于多贴图纹理现在的渲染速度已经很快,
以至于和普通纹理没有什么区别,我们现在一般都使用多贴图纹理。
使用多贴图纹理并不麻烦。首先,我们需要创建不同等级(尺寸)的纹理图片。我们需要调用n次glTexImage2D函数,生成不同等级的纹理贴图。例如:
glTexImage2D(GL_TEXTURE_2D,0,3,8,8,0,GL_RGB,GL_UNSIGNED_BYTE,Pixels);
glTexImage2D(GL_TEXTURE_2D,1,3,4,4,0,GL_RGB,GL_UNSIGNED_BYTE,Pixels);
glTexImage2D(GL_TEXTURE_2D,2,3,2,2,0,GL_RGB,GL_UNSIGNED_BYTE,Pixels);
glTexImage2D(GL_TEXTURE_2D,3,3,1,1,0,GL_RGB,GL_UNSIGNED_BYTE,Pixels);
这些函数调用的第二个参数表示当前纹理的等级。0级的分辨率最大。之后,每一级的分辨率是上一级分辨率的一半。这样的函数调用应一直进行下去,直至图像的高度和宽度都为1。
但有时候,这样做总并不是很方便。我们可以借助一个glu函数帮我们自动生成这些多贴图纹理。只需要把生成纹理图像的函数调用由glTexImage2D改为gluBuild2DMipMaps即可:
gluBuild2DMipMaps(GL_TEXTURE_2D,3,Bit.Width,Bit.Height,0,GL_RGB,GL_UNSIGNED_BYTE,Pixels);
此外,还必须把纹理的滤镜改为MIP_MAP滤镜。例如:
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);