1.基础知识:
1.Textures(纹理)
纹理是一个2D图片(甚至也有1D和3D的纹理),它可以用来添加物体的细节。可以存储凹凸信息,不用给网格模型添加额外顶点。
2.texture coordinate(纹理坐标)
为了将纹理映射到三角形,我们需要告诉三角形的每个顶点它对应于纹理的哪个部分。 因此,每个顶点都应该有一个与之关联的纹理坐标,用于指定从纹理图像的哪个部分进行采样。 片段插值然后为其他片段做其余的工作。
纹理坐标在 x 和 y 轴上的范围从 0 到 1(请记住,我们使用的是 2D 纹理图像)。 使用纹理坐标检索纹理颜色称为采样。 纹理坐标从纹理图像左下角的 (0,0) 到纹理图像右上角的 (1,1)。
3.sampling
使用纹理坐标检索纹理颜色称为采样。
4.Texture Wrapping (纹理坐标包装)
纹理坐标通常范围从 (0,0) 到 (1,1) 但如果我们指定超出此范围的坐标会发生什么? OpenGL 的默认行为是重复纹理图像(我们基本上忽略浮点纹理坐标的整数部分),但 OpenGL 提供了更多选项:
GL_REPEAT:纹理的默认行为。 重复纹理图像。
GL_MIRRORED_REPEAT:与 GL_REPEAT 相同,但每次重复都会镜像图像。
GL_CLAMP_TO_EDGE:将坐标限制在 0 和 1 之间。结果是更高的坐标被限制到边缘,导致边缘图案被拉伸。
GL_CLAMP_TO_BORDER:范围之外的坐标现在被赋予用户指定的边框颜色。
5.Texture Filtering
纹理坐标不依赖于分辨率,而是任何浮点值,因此 OpenGL 必须确定将纹理坐标映射到哪个纹元(也称为 texel )。 如果您有一个非常大的对象和一个低分辨率的纹理,这将变得尤为重要。 OpenGL 纹理过滤的选项,最重要的选项:GL_NEAREST 和 GL_LINEAR。
6.GL_NEAREST
GL_NEAREST(也称为最近邻(nearest neighbor)或点过滤(point filtering))是 OpenGL 的默认纹理过滤方法。 当设置为 GL_NEAREST 时,OpenGL 选择中心最接近纹理坐标的纹素。 您可以在下方看到 4 个像素,其中十字代表精确的纹理坐标。 左上角纹素的中心最接近纹理坐标,因此被选为采样颜色:
7.GL_LINEAR
GL_LINEAR(也称为(双)线性过滤 (bi)linear filtering)从纹理坐标的相邻纹素中获取内插值,近似于纹素之间的颜色。 从纹理坐标到纹素中心的距离越小,纹素颜色对采样颜色的贡献就越大。 下面我们可以看到返回了相邻像素的混合颜色
8.magnifying (放大)
纹理过滤可以设置为放大和缩小操作(放大或缩小时),因此您可以例如在纹理向下缩放时使用最近邻过滤和对放大纹理进行线性过滤。 因此,我们必须通过 glTexParameter* 为这两个选项指定过滤方法。 代码应该类似于设置包装方法:
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
9.minifying (缩小)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
10.Mipmaps
假设远处的物体与靠近观察者的物体具有相同的高分辨率纹理。由于对象距离很远并且可能只产生几个片段,OpenGL 很难从高分辨率纹理中检索其片段的正确颜色值,因为它必须为跨越大部分纹理的片段选择纹理颜色.这将在小物体上产生可见的伪影,更不用说在小物体上使用高分辨率纹理会浪费内存带宽。
为了解决这个问题,OpenGL 使用了一个称为 mipmap 的概念,它基本上是一个纹理图像的集合,其中每个后续纹理与前一个纹理相比小两倍。 mipmaps 背后的想法应该很容易理解:在与观察者的特定距离阈值之后,OpenGL 将使用最适合与对象距离的不同 mipmap 纹理。由于物体距离较远,用户不会注意到较小的分辨率。然后,OpenGL 能够对正确的纹素进行采样,并且在对那部分 mipmap 进行采样时所涉及的缓存内存更少。让我们仔细看看 mipmapped 纹理是什么样子的
要指定 mipmap 级别之间的过滤方法,我们可以使用以下四个选项之一替换原始过滤方法:
GL_NEAREST_MIPMAP_NEAREST:采用最近的mipmap来匹配像素大小,并使用最近邻插值进行纹理采样。
GL_LINEAR_MIPMAP_NEAREST:采用最近的 mipmap 级别并使用线性插值对该级别进行采样。
GL_NEAREST_MIPMAP_LINEAR:在最接近像素大小的两个 mipmap 之间进行线性插值,并通过最近邻插值(GL_NEAREST)对插值级别进行采样。
GL_LINEAR_MIPMAP_LINEAR:在两个最接近的 mipmap 之间进行线性插值,并通过线性插值对GL_LINAR得出的值进行采样。
11.Loading and creating textures
引用图片加载库
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
使用:
int width, height, nrChannels;
unsigned char *data = stbi_load("container.jpg", &width, &height, &nrChannels, 0);
12.Generating a texture(生成贴图)
生成id
unsigned int texture;
glGenTextures(1, &texture);
为当前程序,绑定贴图纹理
glBindTexture(GL_TEXTURE_2D, texture);
生成MipMap
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, data);
glGenerateMipmap(GL_TEXTURE_2D);
13.Applying Units
纹理单元的主要目的是允许我们在着色器中使用 1 个以上的纹理。 通过将纹理单元分配给采样器,我们可以一次绑定到多个纹理,只要我们先激活相应的纹理单元。 就像 glBindTexture 一样,我们可以使用 glActiveTexture 传递我们想要使用的纹理单元来激活纹理单元
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, texture1);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, texture2);
glBindVertexArray(VAO);
glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);