OpenGL ES 高级进阶:纹理数组

栏目: 后端 · 发布时间: 5年前

内容简介:大家好,这是我的今天给大家介绍一下在这个

大家好,这是我的 OpenGL ES 高级进阶系列文章,在我的 github 上有一个与本系列文章对应的项目,欢迎关注,链接: github.com/kenneycode/…

今天给大家介绍一下 纹理数组 ,它是 OpenGL ES 3.0 引入的一个新特性,它能让我们以数组的方式往 shader 中传递纹理,我们先来看看一个普通的 fragment shader

#version 300 es
precision mediump float;
layout(location = 0) out vec4 fragColor;
layout(location = 0) uniform sampler2D u_texture;
in vec2 v_textureCoordinate;
void main() {
    fragColor = texture(u_texture, v_textureCoordinate);
}
复制代码

在这个 shader 中我们声明了一个 uniform sampler2D 变量,即我们只能传递一个纹理,如果要传递多个纹理,就要声明多个 uniform sampler2D

#version 300 es
precision mediump float;
...
layout(location = 0) uniform sampler2D u_texture0;
layout(location = 1) uniform sampler2D u_texture1;
layout(location = 2) uniform sampler2D u_texture2;
...

复制代码

这样一方面会占用多个纹理单元,另一方面一旦 shader 定了,里面支持的纹理数量也就定了,不利于各种数量的纹理,除非自己去生成 shader 。 纹理数组的出现让我们可以像传递一个数组一样将纹理传给 shader ,我们来看一下使用纹理数组时的 shader

// vertex shader
#version 300 es
precision mediump float;
layout(location = 0) in vec4 a_Position;
layout(location = 1) in vec3 a_textureCoordinate;
out vec3 v_textureCoordinate;
void main() {
    v_textureCoordinate = a_textureCoordinate;
    gl_Position = a_Position;
}

// fragment shader
#version 300 es
precision mediump float;
precision mediump sampler2DArray;
layout(location = 0) out vec4 fragColor;
in vec3 v_textureCoordinate;
layout(location = 0) uniform sampler2DArray u_texture;
void main() {
    fragColor = texture(u_texture, v_textureCoordinate);
}
复制代码

我们先来看 fragment shader ,可以看到, sampler2D 变成了 sampler2DArray ,表示它是一个数组,然后使用的时候,也是 texture(u_texture, v_textureCoordinate) ,似乎看越来和不使用纹理数组时一样?其实不一样,也许细心的朋友发现了差别, v_textureCoordinate 此时是 vec3 而不是 vec2 了,我们知道纹理坐标是二维的,这里 vec3 的第三维就是取对应的纹理,可以理解成是数组的下标。 我们还能看到,纹理数组不需要在 shader 先声明数组的大小,它是在代码里控制的,这样就很灵活,我们来看看代码是怎样写的,大部分的操作和使用普通纹理时一样(可参考我的另一篇文章: 《Android OpenGL ES 2.0 手把手教学(6)- 纹理》 ),不一样的地方是首先绑定纹理时的类型不一样:

// 创建图片纹理数组
// Create texture for image
val textures = IntArray(1)
GLES30.glGenTextures(textures.size, textures, 0)
imageTexture = textures[0]

// 注意这里是GL_TEXTURE_2D_ARRAY
// Note that the type is GL_TEXTURE_2D_ARRAY
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D_ARRAY, textures[0])
复制代码

普通纹理是按 GL_TEXTURE_2D 的类型绑定的,这里是 GL_TEXTURE_2D_ARRAY ,另外,还要像给数组分配空间一样给纹理数组分配大小:

GLES30.glTexStorage3D(GLES30.GL_TEXTURE_2D_ARRAY, 1, GLES30.GL_RGBA8, 390, 270, 2)
复制代码

比如在我们的例子中,我们创建了一个大小为2的纹理数组,每个纹理的大小是390*270,这里用的 APIglTexStorage3D ,实际上还有一种纹理叫3D纹理,它和纹理数组有些类似,我们使用纹理数组的时候,有些 API 就是使用了操作3D纹理时的 API

接下来我们就把2张图片加载到我们的纹理数组中:

// 通过glTexSubImage3D指定每层的纹理
// Specify the texture of each layer via glTexSubImage3D
for (i in 0 until 2) {
    val bitmap = Util.decodeBitmapFromAssets("image_$i.jpg")
    val b = ByteBuffer.allocate(bitmap.width * bitmap.height * 4)
    bitmap.copyPixelsToBuffer(b)
    b.position(0)
    GLES30.glTexSubImage3D(GLES30.GL_TEXTURE_2D_ARRAY, 0, 0, 0, i, bitmap.width, bitmap.height, 1, GLES30.GL_RGBA, GLES30.GL_UNSIGNED_BYTE, b)
    bitmap.recycle()
}
复制代码

这步操作和我们使用单个纹理时很类似,单个纹理时是用 glTexImage2D ,这里是用 glTexSubImage3D 并且需要指定当前是给纹理数组的哪层纹理载入数据。

我们前面提到, v_textureCoordinate 此时是 vec3 而不是 vec2 了,因此我们传的纹理坐标也要相应的变化:

// 纹理坐标
// The texture coordinate
private val textureCoordinateData = floatArrayOf(
                                        0f, 1f, 0f, 
                                        0f, 0f, 0f, 
                                        1f, 0f, 0f, 
                                        0f, 1f, 0f, 
                                        1f, 0f, 0f, 
                                        1f, 1f, 0f,
                                        0f, 1f, 1f, 
                                        0f, 0f, 1f, 
                                        1f, 0f, 1f, 
                                        0f, 1f, 1f, 
                                        1f, 0f, 1f, 
                                        1f, 1f, 1f
                                    )
复制代码

另外,在这里我将顶点坐标设置为左下角和右上角,因此会在左下角和右上角分配渲染纹理数组中的第0个和第1个纹理,效果如下:

OpenGL ES 高级进阶:纹理数组

代码在我 githubOpenGLESPro 项目中,本文对应的是 SampleTextureArray ,项目链接: github.com/kenneycode/…

感谢阅读!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Objective-C编程

Objective-C编程

[美] Aaron Hillegass / 夏伟频、李骏 / 华中科技大学出版社 / 2012-9-25 / 58.00元

《Objective-C编程》讲述Objective-C编程语言和基本的iOS/Mac开发知识。作者首先从基本的编程概念讲起(变量、条件语句、循环结构等),接着用浅显易懂的语言讲解Objective-C和Foundation的知识,包括Objective-C的基本语法、 Foundation常用类 、内存管理、常用设计模式等,最后手把手教读者编写完整的、基于事件驱动的iOS/Mac应用。作者还穿插......一起来看看 《Objective-C编程》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

URL 编码/解码
URL 编码/解码

URL 编码/解码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具