本文正在参加「金石方案」

这是Opengl ES入门系列的第17篇博文啦…

OpenglES之纹理数组

今日的内容比较简单,给咱们介绍一下纹路数组,它是OpenGL ES 3.0引进的一个新特性,它能让咱们以数组的方法往shader中传递纹路。

2D纹路数组是OpenGL ES 3.0开端支撑的纹路类型。经过运用2D纹路数组,在同一个着色器中运用多个2D纹路的情况下能够简化开发。 试想一下,假如没有2D纹路数组技能,当一个着色器中需求运用多个2D纹路时就需求声明多个采样器变量,而假如运用2D纹路数组则同样的功用只需声明一个sampler2DArray类型的变量即可,便利高效, 并且扩展性更强。

假如是单单运用2D纹路的话,一旦着色器程序确认了,那么内部可运用的纹路个数就确认了,而假如运用2D纹路数组的话,即使着色器程序确认了,咱们依然能够按照不同的需求运用不同个数的纹路, 这就大大提高了咱们编程的灵活性。

2D纹路数组的运用

2D纹路数组的运用和一般的纹路贴图过程差不多,只是一般纹路运用绑定的是GL_TEXTURE_2D,而2D纹路数组绑定的类型是GL_TEXTURE_2D_ARRAY,同时2D纹路数组分配纹路空间时需求运用函数glTexImage3D而不是glTexImage2D

另外在运用2D纹路数组进行采样时,需求提供的纹路坐标有3个重量也便是vec3,前两个与一般2D纹路坐标意义相同,为S、T重量,第三个重量则为2D纹路数组中的索引。

下面是一个简单的运用2D纹路数组的片元着色器:

#version 300 es
precision mediump float;
precision mediump sampler2DArray;
out vec4 FragColor;
in vec3 TexCoord;
uniform sampler2DArray ourTexture;
void main()
{
    FragColor = texture(ourTexture, TexCoord);
}

能够看到纹路坐标运用的是三个重量变量,并且需求声明sampler2DArray精度类型。

以下是运用纹路数组制作两张不同的图片的一个demo源码实例:


TextureArrayOpengl.cpp
// 极点着色器
static const char *ver = "#version 300 es\n"
                         "in vec4 aPosition;\n"
                         "in vec3 aTexCoord;\n"
                         "out vec3 TexCoord;\n"
                         "void main() {\n"
                         "  TexCoord = aTexCoord;\n"
                         "  gl_Position = aPosition;\n"
                         "}";
// 片元着色器
static const char *fragment = "#version 300 es\n"
                              "precision mediump float;\n"
                              "precision mediump sampler2DArray;\n"
                              "out vec4 FragColor;\n"
                              "in vec3 TexCoord;\n"
                              "uniform sampler2DArray ourTexture; \n"
                              "void main()\n"
                              "{\n"
                              "    FragColor = texture(ourTexture, TexCoord);\n"
                              "}";
// 运用制作两个三角形组成一个矩形的方式(三角形带)
// 第一第二第三个点组成一个三角形,第二第三第四个点组成一个三角形
const static GLfloat VERTICES[] = {
        0.5f,0.0f, // 右下
        0.5f,0.5f, // 右上
        0.0f,0.0f, // 左下
        0.0f,0.5f, // 左上
        0.0f,-0.5f, // 右下
        0.0f,0.0f, // 右上
        -0.5f,-0.5f, // 左下
        -0.5f,0.0f // 左上
};
// 贴图纹路坐标(参考手机屏幕坐标系统,原点在左上角)
//由于对一个OpenGL纹路来说,它没有内涵的方向性,因此咱们能够运用不同的坐标把它定向到任何咱们喜爱的方向上,然而大多数计算机图像都有一个默认的方向,它们通常被规定为y轴向下,X轴向右
const static GLfloat TEXTURE_COORD[] = {
        1.0f,1.0f,0, // 右下
        1.0f,0.0f,0, // 右上
        0.0f,1.0f,0, // 左下
        0.0f,0.0f,0, // 左上
        1.0f,1.0f,1, // 右下
        1.0f,0.0f,1, // 右上
        0.0f,1.0f,1, // 左下
        0.0f,0.0f,1 // 左上
};
TextureArrayOpengl::TextureArrayOpengl():BaseOpengl() {
    initGlProgram(ver,fragment);
    positionHandle = glGetAttribLocation(program,"aPosition");
    textureHandle = glGetAttribLocation(program,"aTexCoord");
    textureSampler = glGetUniformLocation(program,"ourTexture");
    LOGD("program:%d",program);
    LOGD("positionHandle:%d",positionHandle);
    LOGD("textureHandle:%d",textureHandle);
    LOGD("textureSample:%d",textureSampler);
}
void TextureArrayOpengl::setPixel(void *data, int width, int height, int length) {
    LOGD("texture setPixel");
    glGenTextures(1, &textureId);
    // 绑定纹路
    glBindTexture(GL_TEXTURE_2D_ARRAY, textureId);
    // 为当时绑定的纹路目标设置盘绕、过滤方法
    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);
    // 运用glTexStorage3D搭配glTexSubImage3D也是能够的
    // 留意这儿是GL_RGBA8而不是GL_RGBA
//    glTexStorage3D(GL_TEXTURE_2D_ARRAY, 1, GL_RGBA8, width, height,2);
    glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGBA, width, height,2, 0, GL_RGBA, GL_UNSIGNED_BYTE,
                 nullptr);
    glTexSubImage3D(GL_TEXTURE_2D_ARRAY,0,0,0,0,width,height,1,GL_RGBA,GL_UNSIGNED_BYTE,data);
    // 解绑定
    glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
}
// 首要先调用setPixel设置第一张纹路,在setPixel中声明晰一个容量为2的纹路数组,先调用setPixel2的话是不可的哦
void TextureArrayOpengl::setPixel2(void *data, int width, int height, int length) {
    LOGD("texture setPixel2");
    // 绑定纹路
    glBindTexture(GL_TEXTURE_2D_ARRAY, textureId);
    // 为当时绑定的纹路目标设置盘绕、过滤方法
    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);
    glTexSubImage3D(GL_TEXTURE_2D_ARRAY,0,0,0,1,width,height,1,GL_RGBA,GL_UNSIGNED_BYTE,data);
    // 解绑定
    glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
}
void TextureArrayOpengl::onDraw() {
    glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(program);
    // 激活纹路
    glActiveTexture(GL_TEXTURE2);
    glUniform1i(textureSampler, 2);
    // 绑定纹路
    glBindTexture(GL_TEXTURE_2D_ARRAY, textureId);
    /**
     * size 几个数字表明一个点,显现是两个数字表明一个点
     * normalized 是否需求归一化,不用,这儿现已归一化了
     * stride 步长,接连极点之间的间隔,假如极点直接是接连的,也可填0
     */
    // 启用极点数据
    glEnableVertexAttribArray(positionHandle);
    glVertexAttribPointer(positionHandle,2,GL_FLOAT,GL_FALSE,0,VERTICES);
    // 纹路坐标
    glEnableVertexAttribArray(textureHandle);
    glVertexAttribPointer(textureHandle,3,GL_FLOAT,GL_FALSE,0,TEXTURE_COORD);
    // 4个极点制作两个三角形组成矩形
    glDrawArrays(GL_TRIANGLE_STRIP,0,8);
    glUseProgram(0);
    // 禁用极点
    glDisableVertexAttribArray(positionHandle);
    if(nullptr != eglHelper){
        eglHelper->swapBuffers();
    }
    glBindTexture(GL_TEXTURE_2D_ARRAY, 0);
}
TextureArrayOpengl::~TextureArrayOpengl() {
    LOGD("TextureArrayOpengl析构函数");
}

运转成果显现:

OpenglES之纹理数组

留意事项

查阅相关材料解说运用2D纹路数组时,一般会使数组中的纹路保持相同的尺度。

可是笔者在某些机型上实测发现只需加载的纹路巨细不要超越glTexImage3D中声明的宽高也能正常加载运用,不知道假如尺度纷歧只是否有兼容性问题, 实践开发中还是主张咱们尽量保存纹路数组的尺度巨细都一致。

系列教程源码

github.com/feiflyer/ND…

Opengl ES系列入门介绍

Opengl ES之EGL环境建立
Opengl ES之着色器
Opengl ES之三角形制作
Opengl ES之四边形制作
Opengl ES之纹路贴图
Opengl ES之VBO和VAO
Opengl ES之EBO
Opengl ES之FBO
Opengl ES之PBO
Opengl ES之YUV数据烘托
YUV转RGB的一些理论知识
Opengl ES之RGB转NV21
Opengl ES之踩坑记
Opengl ES之矩阵改换(上)
Opengl ES之矩阵改换(下)
Opengl ES之水印贴图
Opengl ES之文字烘托

重视我,一起进步,人生不止coding!!!