本文继续上一节的内容
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) )这四个纹素值的加权平均值。权系数通过与目标点的距离远近反映,距离越近,权系数越大,即对最终的纹素值影响越大。
区别如下图: 4.5 纹理环境(纹理模式)
看一下设置代码:
glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, mode );
4.6 加载纹理
如下设置并加载纹理:
4.7 使用纹理
首先调用glEnable( GL_TEXTURE_2D ),来启用2D纹理,然后绘制图形,并且为每个顶点指定ST坐标。最后调用glDisable( GL_TEXTURE_2D ).
这是个最简单的例子,图形使用OpenGL绘制的。
4.8 纹理对象及绑定
OpenGL中glTexImage2D这个函数每次调用就会涉及到从CPU传递纹素数组给GPU,效率会非常低下。如果你只有一处使用单张纹理,那是没问题的,如果你有多处并且使用多张纹理,可想而知,卡不死你。这个时候你需要绑定纹理对象(Texture Objects)。纹理对象是将你的纹理留存在显卡中,并且反复利用,这比反复加载快多了。
创建一个纹理对象,首先先要生成纹理名称,然后再将纹理对象绑定到纹理数据上。生成纹理名称我们用glGenTextures( 1, &tex0 ),将纹理对象绑定到纹理数据上,我们用glBindTexture( ) 。每次执行glBindTexture时,你就创建了一个纹理对象。
下面例子是多张纹理时如何处理的代码:
第一次先创建两个纹理名称:tex0,tex1.并且将tex0的纹理作为当前纹理进行绑定到纹理对象,然后设置一系列参数。
然后进行tex1的纹理对象创建并绑定,并且设置参数。 之后在使用时,也就是示例代码的Display()函数中这样调用: 最后也可以调用glDeleteTextures()进行释放资源,毕竟纹理资源是有限的。
以上就是纹理对象创建并绑定,到使用的过程。使用纹理对象通常是支持纹理的最快的方式,会出现高性能的结果,这是因为它绑定(重新使用)一个现有纹理对象的速度,总是比使用函数glTexImage2D()来重新加载一个纹理的速度更快。
记得之前画太阳系的project时,有朋友问现在正在克莱姆森读博士的Doc. Lee, 说为啥他的太阳系卡成狗,李博士立马知道问题出在每次重新加载纹理上。请记得,实际工程中,多纹理时千万不要每次重新加载,否则不熟悉图形学的人很难找出卡顿,闪屏等原因,别坑队友啊。
下面我们具体解释下纹理绑定的原理吧。感兴趣的看下。熟悉OpenGL的人一般听过渲染上下文这个概念,也就是Context。渲染上下文包含了即将被送去显示的所有纹理,颜色,光照,或者点的移动等特征信息。OpenGL的绑定其实可以理解成“附上(attach)”或者“Docking”,将OpenGL对象绑定到上下文中去。然后你可以将其指派到上下文的一些特征信息中去。上下文这一块内容,还是比较有研究价值的,比如以后要用到OpenGL ES,多线程渲染,就需要进行共享上下文等等。我之前的项目,因为使用Unity进行渲染,之后要和iOS源生进行交互,但是一个在主线程,一个不在,这个时候不在一个线程是不能够进行上下文统一,进行共享纹理等操作的,这个坑我踩了很久,最后是U3D中华区技术总监在UUG大会上这样和我说的,我只能选择放弃~
如图所示: 另外如何在Shader中使用纹理,我们到着色器时再说。
这一讲先写这么多,上次有粉丝私信说第一讲内容太多,又没源码。这次就讲纹理,并附上github,里面有示例代码和太阳系源码给大家参考。下一讲我们将OpenGL光照。