自定义View
代码
class MyGLSurfaceView(context: Context, attrs: AttributeSet) : GLSurfaceView(context, attrs), GLSurfaceView.Renderer {
var mProgrem = 0
init {
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 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()
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 |
+---------------------+ +-------------------+ +------------------+