通常生活中,地砖的图文,壁纸的图文 这种比普通颜色复杂的颜色就是纹理
纹理
为了将纹理映射到三角形,我们需要告诉三角形的每个顶点对应的纹理部分。每个顶点应该有一个纹理坐标与它们相关联,指定要从哪个部分纹理图像中进行抽样。片段插值然后对其他片段进行其余的处理。
纹理坐标范围从0到1的x和y轴线(现在使用的是2D纹理图像)。调用使用纹理坐标检索纹理颜色采样。纹理坐标从(0,0)纹理图像的(1,1)左下角开始到纹理图像的右上角
为三角形指定3个纹理坐标点。我们希望三角形的左下方与纹理的左下方对应,所以我们使用(0,0)三角形左下角的纹理坐标。同样适用于具有(1,0)纹理坐标的右下侧。三角形的顶部应与纹理图像的顶部中心对应,因此我们将(0.5,1.0)其作为其纹理坐标。我们只需要将3个纹理坐标传递给顶点着色器,然后将它们传递给片段着色器,从而对每个片段的所有纹理坐标进行内插。
float texCoords[] = {
0.0f, 0.0f, // 左下角
1.0f, 0.0f, // 右下角
0.5f, 1.0f // 中间的点
};
纹理包装
OpenGL的默认行为是重复纹理图像(我们基本上忽略浮点纹理坐标的整数部分),但OpenGL提供了以下选项:
- GL_REPEAT:纹理的默认行为。重复纹理图像。
- GL_MIRRORED_REPEAT:与GL_REPEAT相同,但每次重复都会镜像图像。
- GL_CLAMP_TO_EDGE:夹住0和之间的坐标1。结果是较高的坐标被夹紧到边缘,导致拉伸的边缘图案。
- GL_CLAMP_TO_BORDER:范围外的坐标现在被赋予用户指定的边框颜色。
看一下每个选项不同的效果:
前述每个选项可以为每个坐标轴进行设置(s,t(和r如果您正在使用3D纹理),相当于x,y,z)与glTexParameter*
功能:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);
/*
*第一个参数指定纹理目标,我们正在使用2D纹理,因此纹理目标是GL_TEXTURE_2D
*第二个参数要求我们要设置什么选项,以及哪个纹理轴。我们要配置该WRAP选项S并T为轴指定它
*最后一个参数要求我们传递我们想要的纹理包装模式,在这种情况下,OpenGL将使用GL_MIRRORED_REPEAT在当前活动的纹理上设置其纹理包装选项。
*/
纹理过滤
纹理坐标不依赖于分辨率,但可以是任何浮点值,因此OpenGL必须弄清楚哪个纹理像素(也称为 纹理元素)将纹理坐标映射到。有几个选项可用,但现在我们将讨论最重要的选项:GL_NEAREST
和GL_LINEAR
。
GL_NEAREST(也称为最近邻滤波)是OpenGL的默认纹理过滤方法。当设置为GL_NEAREST时,OpenGL会选择中心最接近纹理坐标的像素。下面你可以看到4个像素,其中十字架代表确切的纹理坐标。左上纹理体的中心最靠近纹理坐标,因此被选为采样颜色:
GL_LINEAR(也称为(bi)线性滤波)从纹理坐标的相邻纹素中获取内插值,逼近纹素之间的颜色。从纹理坐标到纹素中心的距离越小,纹素的颜色越多,对采样的颜色有所贡献。下面我们可以看到返回相邻像素的混合颜色:
看一下2个选项效果
GL_NEAREST导致阻塞的模式,我们可以清楚地看到形成纹理的像素,而GL_LINEAR产生更平滑的图案,其中各个像素不太可见。GL_LINEAR产生更逼真的输出,但是我们更喜欢更多的8位外观,因此选择GL_NEAREST选项。
注意:如果使用图片当作纹理,需要图像的宽度和高度
生成纹理
- 创建一个纹理被引用的ID
int texture;
glGenTextures(1, &texture);
/*
*第一个参数:指定要生成的纹理对象的数量
*第二个参数:指定存储生成的纹理的数组
*/
2.绑定纹理
glBindTexture(GL_TEXTURE_2D, texture);
/*
*将给定的纹理对象设置为当前活动的纹理对象
*第一个参数:指定最常见的纹理绑定到的目标 GL_TEXTURE_1D GL_TEXTURE_2D GL_TEXTURE_3D
*指定要绑定的纹理
*/
3.生成纹理
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
/*
*在当前纹理单元的当前绑定纹理对象上生成纹理图像
*第一个参数指定纹理目标; 将其设置为GL_TEXTURE_2D意味着此操作将在同一目标上的当前绑定纹理对象上生成纹理(因此,绑定到目标GL_TEXTURE_1D或GL_TEXTURE_3D的任何纹理都不会受到影响)。
*第二个参数指定要为其创建纹理的mipmap级别,如果要手动设置每个mipmap级别,但我们将其保留在基本级别0。
*第三个参数告诉OpenGL我们想要存储纹理的是什么样的格式。我们的图像只有RGB值,所以我们将保存纹理与RGB值。
*第4和第5个参数设置结果纹理的宽度和高度。我们在加载图像时存储了那些,所以我们将使用相应的变量。
下一个参数应该是0(一些遗留的东西)。
*第7和第8个参数指定源图像的格式和数据类型。我们使用RGB值加载图像并将其存储为chars(字节),以便我们传递相应的值。
*最后一个参数是实际的图像数据。
*/
4.一旦 glTexImage2D被调用,当前绑定的纹理对象现在具有附加的纹理图像。然而,目前它只具有加载的纹理图像的基本级别,如果我们要使用mipmap,我们必须手动指定所有不同的图像(通过不断增加第二个参数),或者我们可以调用glGenerateMipmap生成纹理后。这将自动生成当前绑定纹理的所有必需的mipmap。
glGenerateMipmap(GL_TEXTURE_2D);
生成完以后,释放图像内存
应用纹理
首先必须使用纹理坐标更新顶点数据:
GLfloat vertices[] = {
0.5f, 0.5f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f
};
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 8 * sizeof(float), (void*)(6 * sizeof(float)));
必须调整前两个顶点属性的步幅参数8 * sizeof(float)
glEnableVertexAttribArray(2);