纹理是一个2D贴图
假如说想将纹理贴到三角形上,首先需要设定三角形三个顶点分别对应哪个部位,然后再纹理中进行采样,在图形的其他部分进行片段插值。这里需要注意左下角是(0,0)点
float texCoords[] =
{
0.0f, 0.0f, // 左下角
1.0f, 0.0f, // 右下角
0.5f, 1.0f // 上中
};//纹理坐标
如果在纹理坐标范围外,我们应设置纹理环绕方式
GL_REPEAT | 对纹理的默认行为。重复纹理图像。 |
|---|---|
GL_MIRRORED_REPEAT | 和GL_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_NEAREST和GL_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轴相反)