纹理
- 现实生活中,纹理最通常的作用是装饰我们的物体模型,它就像是贴纸一样贴在物体表面,使得物体表面拥有图案。但实际上在OpenGL中,纹理的作用不仅限于此,它可以用来存储大量的数据,一个典型的例子就是利用纹理存储地形信息。简单说,你加载的图片,来到底层都会变成纹理处理。
纹理对象
- 纹理对象允许我们一次加载一个以上纹理状态(包含纹理图像)。以及在它们之间进行快速切换。纹理状态是由当前绑定的纹理对象维护的。而纹理对象时一个无符号整数标识的。
// 纹理对象
GLuint texture;
//使用函数分配纹理对象
//指定纹理对象的数量 和 指针(指针指向一个无符号整形数组,由纹理对象标识符填充)。
void glGenTextures(GLsizei n,GLuint * textTures);
//绑定纹理状态
//参数target:GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
//参数texture:需要绑定的纹理对象
void glBindTexture(GLenum target,GLunit texture);
//删除绑定纹理对象
//参数n:指定要删除的纹理数。
//参数textures:指定要删除的纹理数组。
void glDeleteTextures(GLsizei n,GLuint *textures);
//测试纹理对象是否有效
//参数texture:如果texture是一个已经分配空间的纹理对象,那么这个函数会返回GL_TRUE,否则会返回GL_FALSE。
GLboolean glIsTexture(GLuint texture);
读取TGA纹理
- TGA文件
TGA格式是计算机上应用最广泛的图象格式。在兼顾了BMP的图象质量的同时又兼顾了JPEG的体积优势。并且还有自身的特点:通道效果、方向性。在CG领域常作为影视动画的序列输出格式,因为兼具体积小和效果清晰的特点。
- 读取TGA文件
//获取指向tag文件指针
//szFileName: 纹理文件名称
//iWidth: 文件宽度地址
//iHeight:文件高度地址
//iComponents:文件组件地址
//eFormat:文件格式地址
//return:pBits,指向图像数据的指针
GLbyte *gltReadTGABits(const char *szFileName, GLint *iWidth, GLint *iHeight, GLint *iComponents, GLenum *eFormat);
//载入纹理
//target: GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D 。
//Level : 指定所加载的mip贴图层次。一般我们都把这个参数设置为0。
//internalformat: 每个纹理单元中存储多少颜色成分。
//width、height、depth: 指加载纹理的宽度、高度、深度。
//border: 允许为纹理贴图指定一个边界宽度。
//format: gltReadTGABits函数中,通过 eFormat 参数返回图片的颜色格式
//type参数:OpenGL 数据存储方式,一般使用 GL_UNSIGNED_BYTE
//data参数:图片数据指针
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);
纹理参数设置
-
过滤方式
-
邻近过滤:选取离取色点(+号)最近的颜色,作为样本颜色.
邻近过滤 -
线性过滤:基于取色点(+号)附近的颜色,混合计算出一个新的颜色作为样本颜色.
线性过滤
-
//参数介绍
//GL_TEXTURE_2D:二维纹理
//GL_TEXTURE_MAG_FILTER:图片放大时的过滤方式
//GL_LINEAR:线性过滤
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
//参数介绍
//GL_TEXTURE_2D:二维纹理
//GL_TEXTURE_MIN_FILTER:图片缩小时的过滤方式
//GL_NEAREST:邻近过滤
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST);
- 环绕方式
参数 | 描述 |
---|---|
GL_REPEAT | 超出纹理范围的坐标整数部分被忽略,形成重复效果。 |
GL_MIRRORED_REPEAT | 超出纹理范围的坐标整数部分被忽略,但当整数部分为奇数时进行取反,形成镜像效果。 |
GL_CLAMP_TO_EDGE | 超出纹理范围的坐标被截取成0和1,形成纹理边缘延伸的效果。 |
GL_CLAMP_TO_BORDER | 超出纹理范围的部分被设置为边缘色。 |
当纹理坐标超出默认范围时,每个选项都有不同的视觉效果输出. 这四种模式所产生的纹理效果如下:
环绕方式
//参数介绍
//GL_TEXTURE_2D:二维纹理
//GL_TEXTURE_WRAR_S:对应X轴
//GL_CLAMP_TO_EDGE:环绕方式
glTextParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAR_S,GL_CLAMP_TO_EDGE);
//参数介绍
//GL_TEXTURE_2D:二维纹理
//GL_TEXTURE_WRAR_T:对应Y轴
//GL_CLAMP_TO_EDGE:环绕方式
glTextParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAR_T,GL_CLAMP_TO_EDGE);
Mipmaps
- Mipmaps 将纹理按照1/2的比例缩小并生成副本,以此类推直到纹理只有1x1大小(这里是纹理坐标,不是真实像素大小)。采样时我们根据当前缩小比率来选择合适大小的纹理,按照线性过滤或最邻近过滤来采样。比如,我们要用做贴图的纹理大小为 64x32,对它做下采样生成32x16,16x8,8x4,4x2,2x1,1x1的纹理,如果要渲染的区域大小为14x6,那么我们要么选16x8的纹理,要么选16x8与8x4的两块纹理做加权平均。
Mipmaps
- Mipmaps是一个功能强大的纹理技术,它可以提高渲染的性能以及提升场景的视觉质量。它可以用来解决使用一般的纹理贴图会出现的两个常见的问题:
闪烁,当屏幕上被渲染区域与它所应用的纹理图像相比显得非常小时,就会出现闪烁。尤其当视口和物体在移动的时候,这种负面效果更容易被看到。
性能问题。如果我们的贴纹理的区域离我们非常远,远到在屏幕中只有一个像素那么大小时,纹理的所有纹素都集中在这一像素中。这时,我们无论做邻近过滤还是做线性过滤时都不得不将纹理的所有纹素计算在内,这种计算效率将大大影响我们的采样效率,而纹理的数据量越大,对效率的影响就会更大。
- 使用Mipmaps
1.生成mipmaps
glGenerateMipmap(GL_TEXTURE_2D);
- 设置过滤方式的时候使用以下参数:
参数 | 描述 |
---|---|
GL_NEAREST_MIPMAP_NEAREST | 选择最邻近的mip层,并使用最邻近过滤。 |
GL_NEAREST_MIPMAP_LINEAR | 对两个mip层使用最邻近过滤后的采样结果进行加权平均。 |
GL_LINEAR_MIPMAP_NEAREST | 选择最邻近的mip层,使用线性插值算法进行过滤。 |
GL_LINEAR_MIPMAP_LINEAR | 对两个mip层使用线性插值过滤后的采样结果进行加权平均,又称三线性mipmap。 |