之前我们已经通过渲染三角形,通过深度计算、颜色混合等方式,模拟出了3D效果,但是为了达到更加真实的效果,还有一种方式: 纹理贴图(texture mappint) .纹理是一种应用到场景中三角形上的 图像数据 ,通过过滤的纹理单元(相当于基于纹理的像素)填充到实心区域.

纹理贴图可以理解为,新房装修的墙纸,依据一面墙各个角的点,对应墙纸的点,然后贴上去.

1.读取像素

OpenGL一般读取的是tga文件,OpenGL ES可以直接使用png、jpg压缩格式的图片.targa图像格式(.tga)是一种方便而且容易使用的图像格式,它即支持简单颜色图像,也支持带有Alpha值的图像.

gltReadTGABits(const char *szFileName, GLint *iWidth, GLint *iHeight, GLint *iComponents, GLenum *eFormat)
1.szFileName:纹理文件名称
2.iWidth:文件宽度地址 nWidth用来接受宽度值
3.iHeight:文件高度地址
4.iComponents:文件组件地址
5.eFormat:文件格式地址
返回值pBits:指向图像数据的指针
复制代码

gltReadTGABits函数用来打开文件,然后读入文件头并进行语法分析,以确定文件的宽度、高度和数据格式等,返回的结果指向了图像数据.

2.载入纹理

在几何图形中应用纹理贴图时,第一个必要步骤就是将纹理载入内存.一旦被载入,这些纹理就会称为当前纹理状态的一部分.有3个OpenGL函数经常用来从存储器缓冲区中载入:

  • glTexImage1D
  • glTexImage2D
  • glTexImage3D
  • 它们是由glTexImage派生出来,OpenGL支持一维、二维、三维纹理贴图,使用相应的函数来载入这些纹理,并将它们设置为当前纹理.

    glTexImage2D(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels)
     1.target:纹理维度 123D
     2.level:mip贴图层次,对于非mip贴图的纹理,可以设置为0
     3.internalformat:纹理单元存储的颜色成分
     4.width:纹理宽度
     5.height:纹理高度
     6.border:加载纹理的边界宽度
     8.format:OpenGL的像素格式,一般由读取时的eFormat决定
     7.type:像素数据的数据类型,告诉OpenGL使用缓存区中的什么数据类型来存储颜色分量,像素数据的数据类型
     8.pixels:指向纹理图像数据的指针
    
  • width,height和depth参数一般都是2的整数次方,在较老的OpenGL实现中,如果使用了非2的整数次幂的值,将会导致纹理贴图被隐式的禁用.
  • border参数允许为纹理贴图指定一个边界宽度,纹理边界允许通过对边界处的纹理单元进行额外的设置,来对它的宽度、高度或深度进行扩展.
  • format:像素格式

    像素格式一般常用GL_RGBA,GL_RGB

  • 分配纹理对象
  • 在纹理之间进行切换或重新加载不同的纹理对象可能会是开销很大的操作.纹理对象允许我们一次加载一个以上的纹理状态,包括纹理图像,以及在它们之间进行快速切换.纹理状态是由当前绑定的纹理对象维护的,而纹理对象是由一个无符号整数标识的.首先是分配纹理对象

    glGenTextures(GLsizei n, GLuint *textures)
    n:纹理对象个数
    textures;纹理对象指针
    复制代码

    函数指定纹理对象的数量和一个指针,这个指针指向一个无符号整形数组(由纹理对象标识符填充).

  • 绑定纹理状态
  • glBindTexture(GLenum target, GLuint texture)
    target:纹理维度:GL_TEXTURE_1D 、2D、3D
    texture:纹理对象
    复制代码

    texture是需要绑定的特定纹理对象,此后,所有的纹理加载和纹理参数设置只影响当前绑定的纹理对象.

  • 删除纹理对象
  • void glDeleteTextures(GLsizei n, GLuint *textures)
    复制代码

    在销毁大量的纹理内存时,多次调用可能会造成延迟

    4.纹理参数

    //参数1:target,指定这些参数将要应⽤用在那个纹理理模式上,⽐比如GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D。 
    //参数2:pname,指定需要设置那个纹理理参数
    //参数3:param,设定特定的纹理理参数的值
    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);
    
  • 设置过滤方式
  • 设置放大/缩小时的过滤方式

    放大:GL_TEXTURE_MAG_FILTER
    缩小:GL_TEXTURE_MIN_FILTER
    临近过滤:GL_NEAREST
    线性过滤:GL_LINEAR
    我们可以看下面例子,在放大时的临近过滤和线性过滤的区分.

    左侧临近过滤:临近过滤最显著的特征就是,当纹理被拉伸到特别大的时候,会出现斑驳状像素.是因为不管纹理坐标位于哪个纹理单元,这个纹理单元的颜色就作为这个片段的纹理颜色.

    右侧线性过滤:线性过滤是把这个纹理坐标周围的纹理单元的加权平均值应用到这个纹理坐标上(线性插值).所以当拉伸放大时会出现“失真”的效果.线性过滤往往比临近过滤付出更多的额外开销,但是当今硬件设备,几乎可以忽略不计.

  • 设置环绕方式
  • 环绕方式指当纹理坐标超出默认范围时,边缘的显示形式.

    x轴:GL_TEXTURE_WRAP_S
    y轴:GL_TEXTURE_WRAP_T
    z轴:GL_TEXTURE_WRAP_R