关于纹理
在先前的章节我们已经学会了如何给绘制的物体添加一些想要的颜色,但是对于更进一步的细节,就不得不谈到纹理(Texture),纹理通常是艺术家和程序员给物体添加细节的一个图像,我们可以通过纹理给物体增添更多的细节而不需要加入更多的顶点信息。
我们需要确定我们的物体的顶点对应纹理的哪个部分,以方便将纹理映射到物体表面,因此每个物体的顶点都会对应有一个纹理坐标告诉该顶点需要从纹理的哪部分进行采样。让后在这些顶点片段之间进行分段插值。OpenGL的纹理采样就是片段通过对应纹理坐标从纹理中分段插值获取对应位置颜色的过程。纹理坐标的范围限制在0到1范围内。
对于我们的正三角形,我们对应获取其中的三个纹理坐标顶点。(0,0)(0.5,1)(1,0),
float texCoords[] = {
0.0f, 0.0f, // lower-left corner
1.0f, 0.0f, // lower-right corner
0.5f, 1.0f // top-center corner
};
纹理采样的实现有多种方式,我们需要指定纹理采样的方式
纹理采样方式
纹理坐标的范围是0到1,但是实际上我们可以指定范围之外的纹理坐标,比如1.5,对于默认的情况,我们不做任何采样方式的规定,默认会为我们重复这个纹理,也就是说在x和y方向上1--2发放范围内会有一个和0--1范围内完全重合纹理图像给我们采样。在这里先简要介绍四种采样方式,但是事实上还有更多:
- GL_REPEAT: 默认的采样方式,简单的重复图像
- GL_MIRRORED_REPEAT: 每次重复时,在重复的基础上,进行一次镜面对称变化
- GL_CLAMP_TO_EDGE:超出规定范围的顶点都在图像的最边缘取色,这给我们一种边缘被一直拉长的视觉效果。
- GL_CLAMP_TO_BORDER: 超出范围的点被给定一种颜色,就好像有个边框
下面展示一下这四种采样的效果
每一个轴都可以单独的设置为上述提及的选项
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_MIRRORED_REPEAT);
在这里str相当于传统意义上的xyz。第一个说明了我们的纹理目标,我们现在处理的时2d纹理,第二个则指明我们要设置的是纹理s轴,设置为GL_MIRRORED_REPEAT,下一行将t轴也设置成这样。
需要注意的是,如果设置为GL_CLAMP_TO_BORDER,那么应该将整体设置为这个,并给予具体的一个颜色
float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f };
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
纹理过滤
纹理坐标并不依赖于分辨率,事实上它可以是任意的浮点数。因此OpenGL需要知道将哪个纹理坐标映射到对应的纹理像素点,他确定了对应的点如何在纹理对应的像素点上取色。接下来主要介绍两种过滤方法。
GL_LINEAR:邻近点过滤(nearest neighbor or point filtering),他会取物体点映射在纹理上对应点距离最近的点作为对应物体点的像素颜色。
GL_LINEAR:双线性过滤( (bi)linear filtering),他会在物体点对应在纹理上的点所在位置周围的像素颜色进行分段插值
由于该点距离右上最近,所以最终表现的颜色当中右上角颜色做出的贡献最大。
对于这两种颜色的视觉效果可以参考下边的图
纹理过滤可以设置成放大或缩小时的操作,当纹理被放大或缩小时进行·指定的过滤方法。
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
多级渐远纹理(Mipmaps)
想象我们的屏幕现在有一个很大的物体,他的表面仿佛该有一个丰富的纹理,当我们逐渐远离他时,它会在我们的视野中变得越来越小,细节也会越来越模糊,对应的纹理也会变得越来越小。这时从一个小片段中向一个高分辨率的纹理选取对应颜色对于OpenGL来说是存在困难的,因为可能很小的一个片段在这个纹理当中就包含了想当大的一片像素点。
OpenGL通过多级渐远纹理来解决这个问题,多级渐远纹理是一些列的纹理图像,其中每个图像的大小都是他先前一个的二分之一大小。所以当我们逐渐远离这个物体时,OpenGL会选择使用更小的多级渐远纹理来处理,当我们远离时,我们并不会注意到图形的分辨率缩小,于是OpenGL就可以用这个多级渐远纹理在远处也能采集到对应正确的像素点。
多级渐远纹理看起来就像这样。
OpenGL为我们提供了专门的创造多级渐远纹理的函数共我们调用glGenerateMipmap
但是由于多级渐远纹理之间是二分之一大小的关系,当一个像素处于两个大小的纹理之间时,比如说有两个纹理的大小是1和0.5,我现在有一个纹理0.77大小,具体应该如何处理呢?
OpenGL提供了邻近点过滤和线性过滤两种方法方法,和之前纹理放大缩小的纹理过滤排列组合,一共有四种组合,这里我们设置纹理缩放的过滤为线性,采用的多级渐远纹理也是线性。
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
注意放大的时候并不需要使用多级渐远纹理。