本文继续上一节的内容

4.4 Filter参数

当使用纹理坐标映射到纹素数组时,正好得到对应纹素的中心位置的情况,很少出现。例如上面的(0.5,1.0)对应纹素(128,256)的情况是比较少的。如果纹理坐标映射到纹素位置(127.34,255.14)该怎么办呢 ?

这是就要用到另一个参数叫filter参数。同样先看下设置这个参数的代码:

glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter );

glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter );

其中filter分为以下两种:

GL_NEAREST:使用最佳逼近点来获取纹素,也就是最近邻滤波( nearest neighbor filtering)。这种方式容易导致走样误差,明显有像素块的感觉。

GL_LINEAR:使用线性滤波方法(linear filtering),它使用纹素位置(127.34,255.14)附近的一组纹素的加权平均值来确定最终的纹素值。例如使用 ( (127,255), (128,255), (127,254) 和 (128,254) )这四个纹素值的加权平均值。权系数通过与目标点的距离远近反映,距离越近,权系数越大,即对最终的纹素值影响越大。

区别如下图:
拓幻图形学工程师教学手册(第五讲)|一字一字敲出OpenGL学习教程
4.5 纹理环境(纹理模式)

看一下设置代码:

glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode );

4.6 加载纹理

如下设置并加载纹理:

拓幻图形学工程师教学手册(第五讲)|一字一字敲出OpenGL学习教程
4.7 使用纹理

首先调用glEnable( GL_TEXTURE_2D ),来启用2D纹理,然后绘制图形,并且为每个顶点指定ST坐标。最后调用glDisable( GL_TEXTURE_2D ).

这是个最简单的例子,图形使用OpenGL绘制的。

拓幻图形学工程师教学手册(第五讲)|一字一字敲出OpenGL学习教程
4.8 纹理对象及绑定

OpenGL中glTexImage2D这个函数每次调用就会涉及到从CPU传递纹素数组给GPU,效率会非常低下。如果你只有一处使用单张纹理,那是没问题的,如果你有多处并且使用多张纹理,可想而知,卡不死你。这个时候你需要绑定纹理对象(Texture Objects)。纹理对象是将你的纹理留存在显卡中,并且反复利用,这比反复加载快多了。

创建一个纹理对象,首先先要生成纹理名称,然后再将纹理对象绑定到纹理数据上。生成纹理名称我们用glGenTextures( 1, &tex0 ),将纹理对象绑定到纹理数据上,我们用glBindTexture( ) 。每次执行glBindTexture时,你就创建了一个纹理对象。

下面例子是多张纹理时如何处理的代码:

第一次先创建两个纹理名称:tex0,tex1.并且将tex0的纹理作为当前纹理进行绑定到纹理对象,然后设置一系列参数。

拓幻图形学工程师教学手册(第五讲)|一字一字敲出OpenGL学习教程
然后进行tex1的纹理对象创建并绑定,并且设置参数。
拓幻图形学工程师教学手册(第五讲)|一字一字敲出OpenGL学习教程
之后在使用时,也就是示例代码的Display()函数中这样调用:
拓幻图形学工程师教学手册(第五讲)|一字一字敲出OpenGL学习教程
最后也可以调用glDeleteTextures()进行释放资源,毕竟纹理资源是有限的。

以上就是纹理对象创建并绑定,到使用的过程。使用纹理对象通常是支持纹理的最快的方式,会出现高性能的结果,这是因为它绑定(重新使用)一个现有纹理对象的速度,总是比使用函数glTexImage2D()来重新加载一个纹理的速度更快。

记得之前画太阳系的project时,有朋友问现在正在克莱姆森读博士的Doc. Lee, 说为啥他的太阳系卡成狗,李博士立马知道问题出在每次重新加载纹理上。请记得,实际工程中,多纹理时千万不要每次重新加载,否则不熟悉图形学的人很难找出卡顿,闪屏等原因,别坑队友啊。

下面我们具体解释下纹理绑定的原理吧。感兴趣的看下。熟悉OpenGL的人一般听过渲染上下文这个概念,也就是Context。渲染上下文包含了即将被送去显示的所有纹理,颜色,光照,或者点的移动等特征信息。OpenGL的绑定其实可以理解成“附上(attach)”或者“Docking”,将OpenGL对象绑定到上下文中去。然后你可以将其指派到上下文的一些特征信息中去。上下文这一块内容,还是比较有研究价值的,比如以后要用到OpenGL ES,多线程渲染,就需要进行共享上下文等等。我之前的项目,因为使用Unity进行渲染,之后要和iOS源生进行交互,但是一个在主线程,一个不在,这个时候不在一个线程是不能够进行上下文统一,进行共享纹理等操作的,这个坑我踩了很久,最后是U3D中华区技术总监在UUG大会上这样和我说的,我只能选择放弃~

如图所示:
拓幻图形学工程师教学手册(第五讲)|一字一字敲出OpenGL学习教程
另外如何在Shader中使用纹理,我们到着色器时再说。

这一讲先写这么多,上次有粉丝私信说第一讲内容太多,又没源码。这次就讲纹理,并附上github,里面有示例代码和太阳系源码给大家参考。下一讲我们将OpenGL光照。