读取图像
在使用纹理前,我们需要将读取对应的图像文件到CPU并对其进行解析。然而OpenGL作为图形API并不提供读取、解析图像文件的功能,因此我们需要自己实现或调用第三方库,这里就以第三方项目stb 的stb_image为例。
stb_image 是一个广泛使用的单头文件图像加载库,支持多种常见图像格式(如JPEG、PNG、BMP等),旨在提供一种简便的方法以将图像数据加载到C或C++程序中。它不依赖于外部库,便于集成和使用。
引入stb_image
通过官方仓库下载:https://github.com/nothings/stb/blob/master/stb_image.h
#define STB_IMAGE_IMPLEMENTATION // 引入前需要定义该宏
#include "stb_image.h"读取图像
// 8位色深
unsigned char *stbi_load(
char const *filename,
int *x,
int *y,
int *comp,
int req_comp,
)
// 16位色深
unsigned short *stbi_load_16( /* 参数8位相同 */)- 参数:
filename—— 图像文件路径x和y—— 指定用于存储图像宽高的变量的指针comp—— 指定用于存储图像类型的变量的指针req_comp—— 期望的图像类型,填STBI_default表示接受所有
- 返回值:返回读取到的图像数据指针
- 图像类型枚举:
STBI_grey、STBI_grey_alpha、STBI_rgb、STBI_rgb_alpha示例:
unsigned char *data; // 存数据
int width = 0; // 存宽
int height = 0; // 存高
int PicType = 0; // 存图像类型
unsigned char *buf = stbi_load(img_path, &width, &height, &PicType, STBI_default);
if (PicType == STBI_rgb) {
const unsigned int buf_size = width * height * 4; // 数据长度(注意通道数量!)
// ...
}
stbi_image_free(buf); // 注意释放内存
注意:
- 图像数据
*buf的长度为长 ✕ 宽 ✕ 通道数 - 图像数据
*buf需要调用函数stbi_image_free进行释放
创建纹理
示例
GLuint texture;
glGenTextures(1, &texture); // 创建纹理对象
glBindTexture(GL_TEXTURE_2D, texture); // 绑定纹理对象
/* 设置纹理参数 */
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); // X轴上环绕方式为Repeat
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // Y轴上环绕方式为Repeat
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); // 纹理缩小时使用邻近过滤
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // 纹理放大时使用线性过滤
/* - */
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buf); // 上传图像到GPU
glGenerateMipmap(GL_TEXTURE_2D); // 生成Mipmap(可选)
glBindTexture(GL_TEXTURE_2D, 0); // 解绑纹理对象
创建纹理对象
void glGenTextures(GLsizei n, GLuint * textures)- 参数:
n—— 要生成的纹理对象数量textures—— 用于存储纹理对象ID的变量的指针,生成多个对象时需要传入数组指针
- 无返回值
绑定纹理对象
void glBindTexture(GLenum target, GLuint texture);- 参数:
target—— 指定纹理对象的绑定目标,将决定纹理的用途 -> 纹理目标texture—— 纹理对象。如果为0,则解绑指定的目标。
- 无返回值
备注
- 可以对多个纹理目标同时分别绑定,不会相互影响
- 可以调用该函数并对参数
buffer传入0以解绑纹理目标,上传阶段最好解绑
设置纹理参数
设置纹理的各种参数,通常需要设置 纹理环绕 和 纹理过滤 -> [纹理环绕 和 纹理过滤](/posts/纹理环绕 和 纹理过滤) 具体参数过多,参考:glTexParameter - OpenGL 4 Reference Pages
上传图像
void glTexImage2D(
GLenum target,
GLint level,
GLint internalformat,
GLsizei width,
GLsizei height,
GLint border,
GLenum format,
GLenum type,
const void *data,
);- 参数:
target—— 纹理目标 -> 纹理目标level—— LOD编号internalformat—— 内部纹理格式 -> [内部纹理存储格式 internalformat](/posts/内部纹理存储格式 internalformat)width—— 图像宽度- OpenGL保证最差的硬件会至少支持1024px宽度的2D纹理
height—— 图像高度- 若目标为
GL_TEXTURE_1D_ARRAY或GL_PROXY_TEXTURE_1D_ARRAY,则表示纹理数组的层数 - OpenGL保证最差的硬件会至少支持1024px高度的2D纹理,或256层的纹理数组
- 若目标为
border—— 该值必须为0(现代OpenGL已废弃边框纹理功能)format—— 指定像素数据的格式 -> 颜色信息type—— 指定像素数据的数据类型 -> 颜色信息、[颜色信息](/posts/颜色信息#打包格式 Packed Formats)data—— 存储图像数据的指针
- 无返回值
使用纹理
示例
glActiveTexture(GL_TEXTURE0); // 激活纹理单元0
glBindTexture(GL_TEXTURE_2D, texture1); // 绑定纹理对象
glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture1"), 0); // 设置Uniform
glActiveTexture(GL_TEXTURE1); // 或者 GL_TEXTURE0 + 1
glBindTexture(GL_TEXTURE_2D, texture2);
glUniform1i(glGetUniformLocation(ourShader.Program, "ourTexture2"), 1);- 设置
sampler2D类型的Uniform前需要先激活纹理单元,并绑定纹理对象(不需要解绑),最后将纹理单元编号传入Uniform - 注意Uniform设置的内容是纹理单元编号
- 纹理单元Active后不需要手动关闭
- OpenGL保证最差的硬件至少有16个纹理单元可用
释放纹理对象
void glDeleteTextures(GLsizei n, const GLuint * textures);- 参数:
n—— 要删除的纹理对象数量textures—— 用于存储纹理对象ID的变量的指针,删除多个对象时需要传入数组指针
- 无返回值
纹理目标
| 纹理目标 (Texture Target) | 维度 | 描述 | 主要用途 | 特点 |
|---|---|---|---|---|
| GL_TEXTURE_1D | 1D | 单行像素数据 | 渐变、高度图 | 使用 s 坐标采样 |
| GL_TEXTURE_2D | 2D | 标准二维图像 | 贴图、渲染目标 | 最常用,支持Mipmap |
| GL_TEXTURE_3D | 3D | 体积数据(体素) | 医学成像、烟雾 | 采样需要 (s, t, r) 坐标 |
| GL_TEXTURE_1D_ARRAY | 1D+Layer | 多个1D纹理组合 | 动画序列、批量1D数据 | 通过 (s, layer) 访问 |
| GL_TEXTURE_2D_ARRAY | 2D+Layer | 多个2D纹理堆叠 | 地形图集、帧动画 | 通过 (s, t, layer) 访问 |
| GL_TEXTURE_RECTANGLE | 2D (非归一化) | 任意尺寸的2D纹理 | 屏幕后处理、临时存储 | 不支持Mipmap,使用像素坐标 |
| GL_TEXTURE_CUBE_MAP | 立方体 (6面) | 6个2D纹理组成立方体 | 天空盒、环境反射 | 采样使用3D方向向量 (s, t, r) |
| GL_TEXTURE_CUBE_MAP_ARRAY | 立方体+Layer | 多个立方体贴图 | 动态环境反射、VR | 通过 (s, t, r, layer) 访问 |
| GL_TEXTURE_BUFFER (TBO) | 1D (Buffer) | 绑定到缓冲区对象 | 大数据流(如粒子系统) | 尺寸大,但采样功能有限 |
| GL_TEXTURE_2D_MULTISAMPLE | 2D (MSAA) | 多重采样抗锯齿纹理 | 抗锯齿渲染 | 采样由硬件处理,无Mipmap |
| GL_TEXTURE_2D_MULTISAMPLE_ARRAY | 2D+Layer (MSAA) | 多重采样纹理数组 | 分层抗锯齿(VR/立体渲染) | 通过 (s, t, layer) 访问 |