自定义View
代码
class MyGLSurfaceView(context: Context, attrs: AttributeSet) : GLSurfaceView(context, attrs), GLSurfaceView.Renderer {var mProgrem = 0init {setEGLContextClientVersion(3)setRenderer(this)renderMode = RENDERMODE_WHEN_DIRTY}override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {GLES30.glClearColor(0.0f, 0.0f, 0.0f, 1.0f)initializeBuffers()val vertexShaderCode = """#version 300 eslayout (location = 0) in vec4 aPosition;void main() {gl_Position = aPosition;}""".trimIndent()val fragmentShaderCode = """#version 300 esprecision mediump float;uniform vec4 vColor;out vec4 fragColor;void main() {fragColor = vColor;}""".trimIndent()mProgrem = initializeShaders(vertexShaderCode, fragmentShaderCode)}override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {GLES30.glViewport(0, 0, width, height)}override fun onDrawFrame(gl: GL10?) {GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT or GLES30.GL_DEPTH_BUFFER_BIT)drawSomething(mProgrem)}fun initializeBuffers(){val vertices = floatArrayOf(0.0f, 0.5f, 0.0f, -0.5f, 0.0f, 0.0f, 0.5f, 0.0f, 0.0f, 0.0f, -0.5f, 0.0f )val vertexBuffer = ByteBuffer.allocateDirect(vertices.size * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer() vertexBuffer.put(vertices) vertexBuffer.position(0) val vbo = IntArray(1)GLES30.glGenBuffers(1, vbo, 0) GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo[0]) GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, vertices.size * 4, FloatBuffer.wrap(vertices), GLES30.GL_STATIC_DRAW)}fun drawSomething(program : Int){val positionHandle = GLES30.glGetAttribLocation(program, "aPosition")GLES30.glEnableVertexAttribArray(positionHandle)GLES30.glVertexAttribPointer(positionHandle, 3, GLES30.GL_FLOAT, false, 0, 0)val colorHandle = GLES30.glGetUniformLocation(program, "vColor")GLES30.glUniform4f(colorHandle, 1.0f, 0.0f, 0.0f, 1.0f) GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4)GLES30.glDisableVertexAttribArray(positionHandle)}fun initializeShaders(vertexShaderCode: String, fragmentShaderCode: String) : Int {val vertexShader = GLES30.glCreateShader(GLES30.GL_VERTEX_SHADER)GLES30.glShaderSource(vertexShader, vertexShaderCode)GLES30.glCompileShader(vertexShader)val fragmentShader = GLES30.glCreateShader(GLES30.GL_FRAGMENT_SHADER)GLES30.glShaderSource(fragmentShader, fragmentShaderCode)GLES30.glCompileShader(fragmentShader)val program = GLES30.glCreateProgram()GLES30.glAttachShader(program, vertexShader)GLES30.glAttachShader(program, fragmentShader)GLES30.glLinkProgram(program)GLES30.glUseProgram(program)return program}
}
总结
-
- 准备菱形的顶点数据:需要绘制的顶点数据存放在
Float
的数组中
-
- 分配顶点数据的直接字节缓冲区,使用
ByteBuffer
直接与底层硬件进行数据传输,避免了不必要的内存拷贝,从而提高性能
- 常见内存拷贝图
+--------------+ +--------------+ +--------------+
| float[] | ----> | FloatBuffer | ----> | GPU |
| (Java Heap) | | (Java Heap) | | (Native) |
+--------------+ +--------------+ +--------------+
- 使用
ByteBuffer
+--------------+ +--------------+ +--------------+
| float[] | ----> | ByteBuffer | ----> | GPU |
| (Java Heap) | | (Direct) | | (Native) |
+--------------+ +--------------+ +--------------+
-
- 创建顶点缓冲区对象
(Vertex Buffer Object, VBO)
-
- 将顶点数据复制到缓冲区中
-
- 创建和编译顶点着色器程序
val vertexShaderCode = """#version 300 es layout (location = 0) in vec4 aPosition; void main() { gl_Position = aPosition; }
""".trimIndent()
-
- 创建和编译片段着色器程序
val fragmentShaderCode = """#version 300 es precision mediump float; uniform vec4 vColor; out vec4 fragColor; void main() { fragColor = vColor; }
""".trimIndent()
-
- 创建着色器程序, 将顶点着色器和片段着色器链接到一起
-
- 获取顶点数据的位置, 并使用该位置的数据
-
- 设置片段着色器的颜色
-
- 绘制菱形
-
- 禁用顶点数据
+---------------------+ +-------------------+ +------------------+
| Application (Java) | ----> | OpenGL Driver | ----> | GPU |
+---------------------+ +-------------------+ +------------------+
| float[] vertices | | Bind VBO | | Process VBO |
| | | Upload Data | | Use Data |
+---------------------+ +-------------------+ +------------------+