1.从TGA⽂文件中读取像素图
GLbyte *gltReadTGABits(const char *szFileName, GLint *iWidth, GLint *iHeight, GLint *iComponents, GLenum *eFormat);
参数1: 纹理文件名称
参数2: ⽂件宽度地址
参数3:⽂件高度地址
参数4:文件组件地址
参数5:⽂件格式地址-Open GL中颜色存储格式
返回值:pBits,指向图像数据的指针
2.纹理载入函数 1D 2D 3D纹理载入 常用2D纹理载入
void glTexImage1D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, void *data);
void glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width,GLsizei height,GLint border,GLenum format,GLenum type,void * data);
void glTexImage3D(GLenum target,GLint level,GLint internalformat,GLSizei width,GLsizei height,GLsizei depth,GLint border,GLenum format,GLenum type,void *data);
- target:
GL_TEXTURE_1D
、GL_TEXTURE_2D
、GL_TEXTURE_3D
。 - Level:指定所加载的mip贴图层次。一般我们都把这个参数设置为0。
- internalformat:每个纹理单元中存储多少颜色成分。
- width、height、depth参数:指加载纹理的宽度、⾼度、深度。==注意!==这些值必须是 2的整数次⽅方。(这是因为OpenGL 旧版本上的遗留留下的⼀一个要求。当然现在已经可以⽀支持不不是 2的整数次⽅方。但是开发者们还是习惯使⽤用以2的整数次⽅方去设置这些参数。)
- border参数:允许为纹理贴图指定⼀个边界宽度。
- format 参数:Open GL中颜色存储格式
*type 参数:使用什么数据类型存储颜色分量
*data参数: 返回的图像数据的指针
3. 更新纹理
void glTexSubImage1D(GLenum target,GLint level,GLint xOffset,GLsizei width,GLenum
format,GLenum type,const GLvoid *data);
void glTexSubImage2D(GLenum target,GLint level,GLint xOffset,GLint yOffset,GLsizei
width,GLsizei height,GLenum format,GLenum type,const GLvoid *data);
void glTexSubImage3D(GLenum target,GLint level,GLint xOffset,GLint yOffset,GLint
zOffset,GLsizei width,GLsizei height,GLsizei depth,Glenum type,const GLvoid * data);
参数含义同2,用得不多
4.插入替换纹理
void glCopyTexSubImage1D(GLenum target,GLint level,GLint xoffset,GLint x,GLint y,GLsizei
width);
void glCopyTexSubImage2D(GLenum target,GLint level,GLint xoffset,GLint yOffset,GLint x,GLi
y,GLsizei width,GLsizei height);
void glCopyTexSubImage3D(GLenum target,GLint level,GLint xoffset,GLint yOffset,GLint
zOffset,GLint x,GLint y,GLsizei width,GLsizei height);
参数含义同2,用得不多
5.使用颜⾊缓存区加载数据,形成新的纹理使⽤
void glCopyTexImage1D(GLenum target,GLint level,GLenum
internalformt,GLint x,GLint y,GLsizei width,GLint border);
void glCopyTexImage2D(GLenum target,GLint level,GLenum
internalformt,GLint x,GLint y,GLsizei width,GLsizei
height,GLint border);
x,y 在颜⾊缓存区中指定了开始读取纹理数据的位置; 缓存区⾥的数据,是源缓存区通过glReadBuffer设置的。
注意:不存在glCopyTextImage3D ,因为我们⽆法从2D 颜色缓存区中获取体积 数据。
6.纹理对象
//使⽤函数分配纹理对象
//指定纹理对象的数量 和 指针(指针指向⼀个无符号整形数组,由纹理对象标识符填充)。
void glGenTextures(GLsizei n,GLuint * textTures);
//绑定纹理理状态
//参数target:GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
//参数texture:需要绑定的纹理对象
void glBindTexture(GLenum target,GLunit texture);
//删除绑定纹理理对象
//纹理对象 以及 纹理对象指针(指针指向⼀个无符号整形数组,由纹理对象标识符填充)。
void glDeleteTextures(GLsizei n,GLuint *textures);
//测试纹理理对象是否有效
//如果texture是⼀个已经分配空间的纹理对象,那么这个函数会返回GL_TRUE,否则会返回GL_FALSE。
GLboolean glIsTexture(GLuint texture);
7.设置纹理参数-过滤方式
glTexParameterf(GLenum target,GLenum pname,GLFloat param);
glTexParameteri(GLenum target,GLenum pname,GLint param);
glTexParameterfv(GLenum target,GLenum pname,GLFloat *param);
glTexParameteriv(GLenum target,GLenum pname,GLint *param);
参数1:target,指定这些参数将要应用在那个纹理模式上,比如GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D。
参数2:pname,指定需要设置那个纹理理参数
参数3:param,设定特定的纹理理参数的值
邻近过滤(GL_NEAREST) 线性过滤(GL_LINEAR)
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST) 纹理理缩⼩小时,使⽤用邻近过滤
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR) 纹理理放⼤大时,使⽤用线性过滤
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
参数1:GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
参数2:GL_TEXTURE_WRAP_S、GL_TEXTURE_T、GL_TEXTURE_R,针对s,t,r坐标
s, t, r, q <-> x, y, z, w
参数3:GL_REPEAT、GL_CLAMP、GL_CLAMP_TO_EDGE、GL_CLAMP_TO_BORDER
GL_REPEAT:OpenGL 在纹理坐标超过1.0的⽅向上对纹理进⾏重复;
GL_CLAMP:所需的纹理单元取自纹理边界或TEXTURE_BORDER_COLOR. GL_CLAMP_TO_EDGE:环绕模式强制对范围之外的纹理坐标沿着合法的纹理单元的最后⼀⾏或者最后⼀列来进⾏采样。
GL_CLAMP_TO_BORDER:在纹理理坐标在0.0到1.0范围之外的只使用边界纹理单元。边界纹理理单元是作为围绕基本图像的额外的⾏和列列,并与基本纹理图像⼀一起加载的。 glTextParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAR_S,GL_CLAMP_TO_EDGE);
glTextParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAR_T,GL_CLAMP_TO_EDGE);
8.纹理坐标
纹理坐标和顶点坐标的对应方式是,上下左右4个面都可以朝上
9. Mip贴图(多级渐远纹理)
什么是Mip贴图
Mip贴图是一种功能强大的纹理技巧。它可以提高渲染性能同时可以改善场景的显示质量。
想象一下,假设我们有一个包含上千物体的大房间,每个物体上都有相同的纹理,有些物体会很远,但其纹理会拥有与近处物体同样高的分辨率。由于远处的物体可能只产生很少的片段,OpenGL从高分辨率纹理中为这些片段获取正确的颜色值就很困难,因为它需要对一个跨过纹理很大部分的片段只拾取一个纹理颜色。在小物体上这会产生不真实的感觉,更不用说对它们使用高分辨率纹理浪费内存的问题了。
OpenGL使用一种叫做多级渐远纹理(Mipmap)的概念来解决这个问题,它简单来说就算一些列的纹理图像,后一个纹理图像是前一个的二分之一。多级渐远纹理背后的理念很简单:距离观察者超过一定的阈值,OpenGL会使用不同的多级渐远纹理,即最合适物体的距离的那个。由于距离远,解析度不高也不会被用户注意到,同时,多级渐远纹理另一加分之处是它的性能非常好。
手工为每个纹理图像创建一系列多级渐远纹理很麻烦,幸好OpenGL有一个glGenerateMipmaps函数,在创建完一个纹理后调用它,就会承担接下来的所有工作了。
*什么时候生成Mip贴图?
只有minFilter等于以下四种模式,才可以生成Mip贴图
- GL_NEAREST_MIPMAP_NEAREST 具有非常好的性能,并且闪烁现象非常弱
- GL_NEAREST_MIPMAP_LINEAR 过滤器在Mip层之间执行了一些额外的插值,以消除他们之间的过滤痕迹。
- GL_LINEAR_MIPMAP_NEAREST 常常用于对游戏进行加上,它使用了高质量的线性过滤器
- GL_LINEAR_MIPMAP_LINEAR 三线性Mip贴图,纹理过滤的黄金准则,具有最高的精度
Mip贴图可以解决的常见问题
1.闪烁问题,当屏幕上被渲染物体的表面与它所应用的纹理图像相比显得非常小时,就会出现闪烁效果。
2.性能问题,加载更大的纹理内存并对它们进行过滤处理,但屏幕上实际只是显示的很少的一部分片段,纹理越大,性能影响越明显。
这2种问题,最简单的解决犯法就是使用更小的纹理图像,根本解决方案就是使用Mip贴图。
10. 纹理渲染流程
//分配纹理对象
参数1:纹理对象个数,
参数2:纹理对象指针
glGenTextures(1, &textureID);
//绑定纹理状态
参数1:纹理状态2D
参数2:纹理对象
glBindTexture(GL_TEXTURE_2D, textureID);
GLbyte *pBits;
int nWidth, nHeight, nComponents;
GLenum eFormat;
//1、读纹理位,读取像素
//参数1:纹理文件名称
//参数2:文件宽度地址
//参数3:文件高度地址
//参数4:文件组件地址
//参数5:文件格式地址
//返回值:pBits,指向图像数据的指针
pBits = gltReadTGABits(szFileName, &nWidth, &nHeight, &nComponents, &eFormat);
if(pBits == NULL)
return false;
//2、设置纹理参数
//参数1:纹理维度
//参数2:为S/T坐标设置模式
//参数3:wrapMode,环绕模式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrapMode);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrapMode);
//参数1:纹理维度
//参数2:线性过滤
//参数3:wrapMode,环绕模式
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, magFilter);
//设置各向异性过滤
GLfloat fLargest;
//获取各向异性过滤的最大数量
glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &fLargest);
//设置纹理参数(各向异性采样)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, fLargest);
//设置各向同性过滤,数量为1.0表示(各向同性采样)
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 1.0f);
//3.载入纹理
//参数1:纹理维度
//参数2:mip贴图层次
//参数3:纹理单元存储的颜色成分(从读取像素图是获得)
//参数4:加载纹理宽
//参数5:加载纹理高
//参数6:加载纹理的深度
//参数7:像素数据的数据类型(GL_UNSIGNED_BYTE,每个颜色分量都是一个8位无符号整数)
//参数8:指向纹理图像数据的指针
glTexImage2D(GL_TEXTURE_2D, 0, nComponents, nWidth, nHeight, 0,
eFormat, GL_UNSIGNED_BYTE, pBits);
//使用完毕释放pBits
free(pBits);
//只有minFilter 等于以下四种模式,才可以生成Mip贴图
//GL_NEAREST_MIPMAP_NEAREST具有非常好的性能,并且闪烁现象非常弱
//GL_LINEAR_MIPMAP_NEAREST常常用于对游戏进行加速,它使用了高质量的线性过滤器
//GL_LINEAR_MIPMAP_LINEAR 和GL_NEAREST_MIPMAP_LINEAR 过滤器在Mip层之间执行了一些额外的插值,以消除他们之间的过滤痕迹。
//GL_LINEAR_MIPMAP_LINEAR 三线性Mip贴图。纹理过滤的黄金准则,具有最高的精度。
if(minFilter == GL_LINEAR_MIPMAP_LINEAR ||
minFilter == GL_LINEAR_MIPMAP_NEAREST ||
minFilter == GL_NEAREST_MIPMAP_LINEAR ||
minFilter == GL_NEAREST_MIPMAP_NEAREST)
//4.纹理生成所有的Mip层
//参数:GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
glGenerateMipmap(GL_TEXTURE_2D);