贴图

XML文件
<?xml version="1.0" encoding="utf-8"?>
<com.example.myapplication.MyGLSurfaceViewxmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent" />
自定义GLSurfaceView
代码
class MyGLSurfaceView(context: Context, attrs: AttributeSet) : GLSurfaceView(context, attrs) {private var mRenderer = MyGLRenderer(context)init {setEGLContextClientVersion(3)setRenderer(mRenderer)renderMode = RENDERMODE_WHEN_DIRTY}
}
自定义GLSurfaceView.Renderer
代码
class MyGLRenderer(private val mContext: Context) : GLSurfaceView.Renderer {private var mDrawData: DrawData? = nulloverride fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {GLES30.glClearColor(0.0f, 0.5f, 0.5f, 1.0f)mDrawData = DrawData().apply {initVertexBuffer()initShader()mTextureID[0] = loadTexture(mContext, R.drawable.bitmap_shader)}}override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {GLES30.glViewport(0, 0, width, height)mDrawData?.computeMVPMatrix(width.toFloat(), height.toFloat())}override fun onDrawFrame(gl: GL10?) {GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT)mDrawData?.enableTexture()mDrawData?.drawSomething()}
}
GLSurfaceView.Renderer
需要的绘制数据
class DrawData {private var mProgram: Int = -1private var NO_OFFSET = 0private val VERTEX_POS_DATA_SIZE = 3private val TEXTURE_POS_DATA_SIZE = 2private var mVertexVBO = 0private var mTexCoordVBO = 0private val mMVPMatrix = FloatArray(16)private val mProjectionMatrix = FloatArray(16)private val mViewMatrix = FloatArray(16)private var mViewPortRatio = 1fvar mTextureID = IntArray(1)val vertex = floatArrayOf(-1.0f, 1.0f, 0.0f, -1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, -1.0f, 0.0f, )val vertexBuffer = ByteBuffer.allocateDirect(vertex.size * 4).order(ByteOrder.nativeOrder()).asFloatBuffer()val textureCoords = floatArrayOf(0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, )val textureBuffer = ByteBuffer.allocateDirect(textureCoords.size * 4).order(ByteOrder.nativeOrder()).asFloatBuffer()fun initVertexBuffer() {vertexBuffer.put(vertex)vertexBuffer.position(NO_OFFSET)textureBuffer.put(textureCoords)textureBuffer.position(NO_OFFSET)val vbo = IntArray(2)GLES30.glGenBuffers(vbo.size, vbo, NO_OFFSET) GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo[0])GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,vertex.size * 4, vertexBuffer,GLES30.GL_STATIC_DRAW)GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo[1])GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER,textureCoords.size * 4, textureBuffer,GLES30.GL_STATIC_DRAW)mVertexVBO = vbo[0]mTexCoordVBO = vbo[1]}fun initShader() {val vertexShaderCode = """#version 300 esuniform mat4 uMVPMatrix; in vec4 aPosition; in vec2 aTexCoord; out vec2 vTexCoord; void main() {gl_Position = uMVPMatrix * aPosition; vTexCoord = aTexCoord;}""".trimIndent() val fragmentShaderCode = """#version 300 esprecision mediump float; uniform sampler2D uTexture; in vec2 vTexCoord; out vec4 fragColor; void main() {fragColor = texture(uTexture, vTexCoord); }""".trimIndent()val vertexShader = LoadShaderUtil.loadShader(GLES30.GL_VERTEX_SHADER, vertexShaderCode)val fragmentShader = LoadShaderUtil.loadShader(GLES30.GL_FRAGMENT_SHADER, fragmentShaderCode)mProgram = GLES30.glCreateProgram()GLES30.glAttachShader(mProgram, vertexShader)GLES30.glAttachShader(mProgram, fragmentShader)GLES30.glLinkProgram(mProgram)GLES30.glUseProgram(mProgram)GLES30.glDeleteShader(vertexShader)GLES30.glDeleteShader(fragmentShader)}fun computeMVPMatrix(width: Float, height: Float) {takeIf { width > height }?.let {mViewPortRatio = width / heightMatrix.orthoM(mProjectionMatrix, NO_OFFSET, -mViewPortRatio, mViewPortRatio, -1f, 1f, 0f, 1f )} ?: run {mViewPortRatio = height / widthMatrix.orthoM(mProjectionMatrix, NO_OFFSET, -1f, 1f, -mViewPortRatio, mViewPortRatio, 0f, 1f )}Matrix.setLookAtM(mViewMatrix, NO_OFFSET, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f )Matrix.multiplyMM(mMVPMatrix, NO_OFFSET, mProjectionMatrix, NO_OFFSET, mViewMatrix, NO_OFFSET )Matrix.scaleM(mMVPMatrix,NO_OFFSET,1f,-1f,1f,)}fun drawSomething() {val matrixHandle = GLES30.glGetUniformLocation(mProgram, "uMVPMatrix")GLES30.glUniformMatrix4fv(matrixHandle, 1, false, mMVPMatrix, NO_OFFSET)val positionHandle = GLES30.glGetAttribLocation(mProgram, "aPosition")GLES30.glEnableVertexAttribArray(positionHandle)GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mVertexVBO)GLES30.glVertexAttribPointer(positionHandle,VERTEX_POS_DATA_SIZE,GLES30.GL_FLOAT,false,0,NO_OFFSET)val textureHandle = GLES30.glGetAttribLocation(mProgram, "aTexCoord")GLES30.glEnableVertexAttribArray(textureHandle)GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mTexCoordVBO)GLES30.glVertexAttribPointer(textureHandle,TEXTURE_POS_DATA_SIZE,GLES30.GL_FLOAT,false,0,NO_OFFSET)GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, NO_OFFSET, vertex.size / VERTEX_POS_DATA_SIZE)GLES30.glDisableVertexAttribArray(positionHandle)GLES30.glDisableVertexAttribArray(textureHandle)}fun enableTexture() {GLES30.glActiveTexture(GLES30.GL_TEXTURE0)GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextureID[0])val textureSampleHandle = GLES30.glGetUniformLocation(mProgram, "uTexture")GLES30.glUniform1i(textureSampleHandle, 0)}fun loadTexture(context: Context, resourceId: Int) : Int {val textureId = IntArray(1)GLES30.glGenTextures(1, textureId, 0)GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureId[0])GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D,GLES30.GL_TEXTURE_MIN_FILTER,GLES30.GL_LINEAR) GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D,GLES30.GL_TEXTURE_MAG_FILTER,GLES30.GL_LINEAR) GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D,GLES30.GL_TEXTURE_WRAP_S,GLES30.GL_CLAMP_TO_EDGE) GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D,GLES30.GL_TEXTURE_WRAP_T,GLES30.GL_CLAMP_TO_EDGE) val options = BitmapFactory.Options().apply {inScaled = false }val bitmap = BitmapFactory.decodeResource(context.resources, resourceId, options)GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, bitmap, 0)bitmap.recycle()GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, 0)return textureId[0]}object LoadShaderUtil {fun loadShader(type: Int, source: String): Int {val shader = GLES30.glCreateShader(type)GLES30.glShaderSource(shader, source)GLES30.glCompileShader(shader)return shader}}
}
效果图
