最近要学习纹理数组,网上查了下资料并不多,可能是本身用到就比较少吧,正好学习了下也算补充下笔记了。
首先,纹理数组有两种:
目录
1.sampler2DArray textures
从网上搜索的结果来看,第一种用的可能是更多的。sampler2DArray也是个类型,和普通单张纹理不一样的地方可能这是一个纹理集合体吧。所以,它在绑定纹理时也只需要一个纹理ID,使用时也是一个纹理单元,和普通单张纹理绑定和使用是一样的,只是在创建加载纹理时有些差别,具体从代码里看:
//生成纹理
glGenTextures(1, &textureID);
//绑定纹理
glBindTexture(GL_TEXTURE_2D_ARRAY, textureID); //绑定时选择纹理数组类型
//设置如何从数据缓冲区去读取图像数据
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
//设置纹理过滤的参数
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D_ARRAY, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//接下来就是不同的地方了--
//两种分配方式都可以,glTexImage3D好像是老版本的方式
glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, 1000, 1000, 2);
//glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 1000, 1000, 2, 0,GL_RGB, GL_UNSIGNED_BYTE, NULL);
const char* path[2] = { "D:\\My Document\\1213.jpg","D:\\My Document\\R-C.jpg" };
//加载图片
for (int i = 0; i < 2; i++) {
unsigned char* pBits;
int nWidth, nHeight, nComponents;
// Read the texture bits 读取纹理数据
stbi_set_flip_vertically_on_load(true); //告诉stb_image.h在y轴上翻转加载的纹理。
pBits = stbi_load(path, &nWidth, &nHeight, &nComponents, 0);
//更新纹理 这里把深度进行了修改,下面的i就代表深度
glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, i, nWidth, nHeight, 1, GL_RGB, GL_UNSIGNED_BYTE, pBits);
stbi_image_free(pBits);
}
纹理使用时:
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D_ARRAY, textureID);
glUniform1i(glGetUniformLocation(programObject[0], "TextureArray"), 2);//纹理传入binding=2
着色器纹理使用:
#version 430 core
out vec4 FragColor;
in vec2 vTexPosition1;
layout(binding = 2) uniform sampler2DArray TextureArray;
void main()
{
FragColor = texture(TextureArray, vec3(vTexPosition1,1));//纹理坐标第三位为纹理序号索引
}
经过加载不同纹理发现,如果尺寸大于设置的尺寸,纹理就加载不出来了,尺寸小了也会出现填不满的现象,所以个人以为,这种方式可能只适合加载统一尺寸的多张纹理。
2.sampler2D textures[16]
这一种就是真正意义的纹理数组了,起初我以为可以像传入普通数组一样传入纹理,并用glUniform1iv去传入,但是我不知道此刻应该先绑定哪一个纹理ID,尝试下来都没有成功加载。之后又通过UBO的方式将纹理ID数组传入,依然没有加载出纹理。之后学习无绑定纹理,才了解到纹理与着色器的联系并不是通过纹理ID,所以索性通过无绑定的方式加载纹理数组。
GLuint textureArray[3]; //纹理数组
//此处省略纹理创建过程
//.....
//
GLuint64 handles[3]; //纹理句柄
for (int i = 0; i < 3; i++)
{
glBindTexture(GL_TEXTURE_2D, textureArray[i]);
handles[i] = glGetTextureHandleARB(textureArray[i]);
glMakeTextureHandleResidentARB(handles[i]);
}
使用纹理时有两种,我都尝试了:
//第一种--单独的纹理数组--uniform sampler2D textArray[3];
glUniformHandleui64vARB(glGetUniformLocation(programObject[0], "textArray"), 3,handles);
//第二种--被UBO包裹的纹理数组
//glBindBuffer(GL_UNIFORM_BUFFER, UBO);
//glBufferSubData(GL_UNIFORM_BUFFER, 0, 3*sizeof(GLuint64), &handles);
着色器里写法:
#version 430 core
#extension GL_ARB_bindless_texture : require //无绑定纹理必须要有的
out vec4 FragColor;
in vec2 vTexPosition1;
//第一种--单独的纹理数组
//uniform sampler2D textArray[3];
//第二种--被UBO包裹的纹理数组
layout(binding = 0) uniform UBO_data
{
sampler2D textArray[3];
};
void main()
{
//纹理采样
FragColor = texture(textArray[0], vTexPosition1);//以数组成员方式采样
}
经过试验发现,这种方式加载的纹理尺寸可以不受限制了,而且加载出来都可以自适应窗口。
之后想尝试绑定的方式加载,如果有大佬有办法,看到的话希望可以指点一下。