OpenGL ES 之attribute

时间:2022-07-24
本文章向大家介绍OpenGL ES 之attribute,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
注意:无特殊说明,文中的GLSL均指OpenGL ES 2.0版本。

attribute是GLSL中特殊的变量类型,用于从“外部”到顶点着色器的通信,只能用于Vertex Shader(顶点着色器),不能用于其他Shader中,attribute 通常用来存储位置坐标、法向量、纹理坐标和颜色等,定义如下:

attribute vec4 vPosition;

OpenGL 标准化组织规定OpenGL ES 2.0 至少支持8个attribute,OpenGL ES 3.0至少支持16个attribute,注意这里是至少,也可以多于8个,通过代码获取支持attribute的最大个数,Kotlin代码如下:

var count = IntArray(1)
GLES20.glGetIntegerv(GLES20.GL_MAX_VERTEX_ATTRIBS, count, 0)
Log.d("OpenGL ES", "attribute支持的最大数量:${count[0]}")

下面是一个非常简单的Vertex Shader:

attribute vec4 vPosition;
void main() {
    gl_Position = vPosition;
}

vPosition就是顶点数据,这个数据需要应用程序从外部传入,下面介绍如何将应用程序的顶点数据传递给我vPosition。

01

获取attribute句柄

在Android中获取句柄Kotlin代码如下:

val loc = GLES20.glGetAttribLocation(programHandle, attrName)

programHandle是program的句柄,attrName是attribute的名称。

02

定义顶点数据

在Android中通常情况下顶点数据的类型是FloatBuffer,定义了3个顶点的Kotlin代码如下:

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代码如下:

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的一块内存中,上面定义的顶点数据结构如下图:

顶点数据的结构别不是都这样,数据结构取决于你定义的顶点数据。