1-6纹理

84 阅读3分钟

纹理是一个2D贴图

假如说想将纹理贴到三角形上,首先需要设定三角形三个顶点分别对应哪个部位,然后再纹理中进行采样,在图形的其他部分进行片段插值。这里需要注意左下角是(0,0)点

float texCoords[] = 
{ 
0.0f, 0.0f, // 左下角
1.0f, 0.0f, // 右下角 
0.5f, 1.0f // 上中 
};//纹理坐标

如果在纹理坐标范围外,我们应设置纹理环绕方式

GL_REPEAT对纹理的默认行为。重复纹理图像。
GL_MIRRORED_REPEATGL_REPEAT一样,但每次重复图片是镜像放置的。
GL_CLAMP_TO_EDGE纹理坐标会被约束在0到1之间,超出的部分会重复纹理坐标的边缘,产生一种边缘被拉伸的效果。
GL_CLAMP_TO_BORDER超出的坐标为用户指定的边缘颜色。

这些选项可以使用glTexParameter函数对坐标轴(s,t,r)设置环绕模式

例如

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT);

如果选择GL_CLAMP_TO_BORDER,同时还需设置指定边缘颜色

float borderColor[] = { 1.0f, 1.0f, 0.0f, 1.0f }; 
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);

现在我们讨论纹理过滤,主要的过滤方式有两种,GL_NEARESTGL_LINEAR

GL_NEAREST也叫做邻近过滤,是OpenGL的默认过滤方式,选择中心点最接近纹理坐标的像素来选择为样本颜色

GL_LINEAR也叫做线性过滤,给予纹理坐标附近的纹理像素计算差值来计算颜色

纹理被缩小时使用邻近过滤,放大时使用线性过滤

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); 
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

多级渐远纹理是为了解决从高分辨率纹理中获取正确颜色值的方法

GL_NEAREST_MIPMAP_NEAREST使用最邻近的多级渐远纹理来匹配像素大小,并使用邻近插值进行纹理采样
GL_LINEAR_MIPMAP_NEAREST使用最邻近的多级渐远纹理级别,并使用线性插值进行采样
GL_NEAREST_MIPMAP_LINEAR在两个最匹配像素大小的多级渐远纹理之间进行线性插值,使用邻近插值进行采样
GL_LINEAR_MIPMAP_LINEAR在两个邻近的多级渐远纹理之间使用线性插值,并使用线性插值进行采样

使用glTexParameteri设置过滤方式(放大过滤选项不能设置多级渐远纹理)

glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

使用stb_image.h来加载图片

#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
int width, height, nrChannels; 
unsigned char *data = stbi_load("container.jpg", &width, &height, &nrChannels, 0);

stbi_load函数参数为图像文件的位置,宽度,高度,颜色通道个数

生成纹理时同样用ID引用

unsigned int texture;
glGenTextures(1, &texture);

然后绑定这个纹理

glBindTexture(GL_TEXTURE_2D, texture);

再用之前的图片来生成纹理

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data); 
glGenerateMipmap(GL_TEXTURE_2D);

其中glTexImage2D函数的参数为纹理目标,纹理指定多级渐远纹理的级别,把纹理储存为何种模式,宽度高度,0,原图的格式,数据类型

最后释放内存

stbi_image_free(data);

我们在顶点数据内更新,加入颜色,同时告诉OpenGL新的顶点格式

float 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))); 
glEnableVertexAttribArray(2);

最后将属性传入着色器内

对于多个纹理,我们可以给纹理采样器分配一个位置值,叫做纹理单元

glActiveTexture(GL_TEXTURE0); // 在绑定纹理之前先激活纹理单元 
glBindTexture(GL_TEXTURE_2D, texture);

在加载图像前加入

stbi_set_flip_vertically_on_load(true);

可以翻转y轴(OpenGL和图片的(0,0)坐标y轴相反)