attribute是GLSL中特殊的变量类型,用于从“外部”到顶点着色器的通信,只能用于Vertex Shader(顶点着色器),不能用于其他Shader中,attribute 通常用来存储位置坐标、法向量、纹理坐标和颜色等,定义如下:
代码语言:javascript复制attribute vec4 vPosition;
OpenGL 标准化组织规定OpenGL ES 2.0 至少支持8个attribute,OpenGL ES 3.0至少支持16个attribute,注意这里是至少,也可以多于8个,通过代码获取支持attribute的最大个数,Kotlin代码如下:
代码语言:javascript复制var count = IntArray(1)
GLES20.glGetIntegerv(GLES20.GL_MAX_VERTEX_ATTRIBS, count, 0)
Log.d("OpenGL ES", "attribute支持的最大数量:${count[0]}")
下面是一个非常简单的Vertex Shader:
代码语言:javascript复制attribute vec4 vPosition;
void main() {
gl_Position = vPosition;
}
vPosition就是顶点数据,这个数据需要应用程序从外部传入,下面介绍如何将应用程序的顶点数据传递给我vPosition。
01
获取attribute句柄
在Android中获取句柄Kotlin代码如下:
代码语言:javascript复制val loc = GLES20.glGetAttribLocation(programHandle, attrName)
programHandle是program的句柄,attrName是attribute的名称。
02
定义顶点数据
在Android中通常情况下顶点数据的类型是FloatBuffer,定义了3个顶点的Kotlin代码如下:
代码语言:javascript复制var vertexBuffer = array2Buffer(
floatArrayOf(
0.0f, 0.5f, 0.0f, // top
-0.5f, -0.5f, 0.0f, // bottom left
0.5f, -0.5f, 0.0f // bottom right
)
)
fun array2Buffer(array: FloatArray): FloatBuffer {
val bb = ByteBuffer.allocateDirect(array.size * 4)
bb.order(ByteOrder.nativeOrder())
var buffer = bb.asFloatBuffer()
buffer.put(array)
buffer.position(0)
return buffer
}
03
设置attribute数据
设置顶点数据,即将顶点数据从CPU传递到GPU,Kotlin代码如下:
代码语言:javascript复制fun setAttributePointer(location: Int, buffers: FloatBuffer, pointSize: Int) {
buffers.position(0)
GLES20.glEnableVertexAttribArray(location)
GLES20.glVertexAttribPointer(location, pointSize, GLES20.GL_FLOAT, false, 0, buffers)
}
这里定义了一个通用的方法,方法说明如下:
- GLES20.glEnableVertexAttribArray(location)
激活当前attribute,location就是第一步中获取的vPosition的句柄,
- GLES20.glVertexAttribPointer
设置attribute属性如何从buffers中获取数据。官方API地址:https://www.khronos.org/registry/OpenGL-Refpages/es2.0/ ,参数说明如下:
- location:attribute属性的句柄,对于本应用程序是指第一步中获取的vPosition的句柄。
- pointSize:每一个attribute顶点数据的个数,返回看下第二步中定义顶点数据的数组,每个顶点由3个float组成,代表x,y,z,也可以由2个float代表一个顶点(x,y),对于本应用程序值是3。
- type(第三个参数):顶点数据的类型,对于本应用程序是float,值是GLES20.GL_FLOAT。
- normalized(第四个参数):是否归一化,将不是float的类型转为float,比如short转float,Android正常情况下不需要归一化,所以设置false。
- stride(第五个参数):两个连续顶点之间的偏移量,对于本应用程序来说,顶点之间是连续的,设置为0。
- 顶点buffer
attribute参数的数据并不是一个内存的索引,而是定义了去哪个内存区域取数据,在GPU中attribute存放在一块固定区域,GPU计算的时候去buffer处取数据,结构如下图:
应用程序将数据传递给GPU后,这些数据保存在GPU的一块内存中,上面定义的顶点数据结构如下图:
顶点数据的结构别不是都这样,数据结构取决于你定义的顶点数据。