XML
文件
<?xml version="1.0" encoding="utf-8"?>
< com.example.myapplication.MyGLSurfaceView2 xmlns: android= " http://schemas.android.com/apk/res/android" android: id= " @+id/glSurfaceView" android: layout_width= " match_parent" android: layout_height= " match_parent" />
Activity
代码
class MainActivity6 : AppCompatActivity ( ) { override fun onCreate ( savedInstanceState: Bundle? ) { super . onCreate ( savedInstanceState) setContentView ( R. layout. activity_main6) }
}
GLSurfaceView
代码
class MyGLSurfaceView2 ( context: Context, attrs: AttributeSet) : GLSurfaceView ( context, attrs) { private var mRenderer = MyMatrixRenderer2 ( context) init { setEGLContextClientVersion ( 3 ) setRenderer ( mRenderer) renderMode = RENDERMODE_WHEN_DIRTY}
}
GLSurfaceView.Renderer
代码
class MyMatrixRenderer2 ( private val mContext: Context) : GLSurfaceView. Renderer { var mDrawData: MyDrawData2? = null override fun onSurfaceCreated ( gl: GL10? , config: EGLConfig? ) { GLES30. glClearColor ( 0.0f , 0.5f , 0.5f , 1.0f ) mDrawData = MyDrawData2 ( ) . apply { initTexture0 ( mContext, R. drawable. picture) initShaderProgram ( ) initVertexBuffer ( ) } } override fun onSurfaceChanged ( gl: GL10? , width: Int, height: Int) { GLES30. glViewport ( 0 , 0 , width, height) mDrawData? . resetMatrix ( ) mDrawData? . computeMVPMatrix ( width, height) } override fun onDrawFrame ( gl: GL10? ) { GLES30. glClear ( GLES30. GL_COLOR_BUFFER_BIT) mDrawData? . drawCurrentOutput ( ) }
}
GLSurfaceView.Renderer
需要的绘制数据
class MyDrawData2 { private var mProgram: Int = - 1 private var NO_OFFSET = 0 private val VERTEX_POS_DATA_SIZE = 3 private val TEXTURE_POS_DATA_SIZE = 2 private val STRIDE = ( VERTEX_POS_DATA_SIZE + TEXTURE_POS_DATA_SIZE) * 4 private var mVAO = IntArray ( 1 ) private var mVBO = IntArray ( 1 ) private var mIBO = IntArray ( 1 ) private var mTextureID = IntArray ( 1 ) private var mMVPMatrix = FloatArray ( 16 ) private val mProjectionMatrix = FloatArray ( 16 ) private val mViewMatrix = FloatArray ( 16 ) private val mModelMatrix = FloatArray ( 16 ) private var mViewPortRatio = 1f val vertexData = floatArrayOf ( - 1.0f , 1.0f , 0.0f , 0.0f , 1.0f , - 1.0f , - 1.0f , 0.0f , 0.0f , 0.0f , 1.0f , 1.0f , 0.0f , 1.0f , 1.0f , 1.0f , - 1.0f , 0.0f , 1.0f , 0.0f ) val vertexDataBuffer = ByteBuffer. allocateDirect ( vertexData. size * 4 ) . order ( ByteOrder. nativeOrder ( ) ) . asFloatBuffer ( ) . put ( vertexData) . position ( NO_OFFSET) val index = shortArrayOf ( 0 , 1 , 2 , 1 , 3 , 2 ) val indexBuffer = ByteBuffer. allocateDirect ( index. size * 2 ) . order ( ByteOrder. nativeOrder ( ) ) . asShortBuffer ( ) . put ( index) . position ( NO_OFFSET) fun initShaderProgram ( ) { 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_0; in vec2 vTexCoord; out vec4 fragColor; void main ( ) { fragColor = texture ( uTexture_0, 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. glDeleteShader ( vertexShader) GLES30. glDeleteShader ( fragmentShader) } fun initVertexBuffer ( ) { GLES30. glGenVertexArrays ( mVAO. size, mVAO, NO_OFFSET) GLES30. glBindVertexArray ( mVAO[ 0 ] ) GLES30. glGenBuffers ( mVBO. size, mVBO, NO_OFFSET) GLES30. glBindBuffer ( GLES30. GL_ARRAY_BUFFER, mVBO[ 0 ] ) GLES30. glBufferData ( GLES30. GL_ARRAY_BUFFER, vertexData. size * 4 , vertexDataBuffer, GLES30. GL_STATIC_DRAW) val positionHandle = GLES30. glGetAttribLocation ( mProgram, "aPosition" ) GLES30. glEnableVertexAttribArray ( positionHandle) GLES30. glVertexAttribPointer ( positionHandle, VERTEX_POS_DATA_SIZE, GLES30. GL_FLOAT, false , STRIDE, NO_OFFSET ) val textureHandle = GLES30. glGetAttribLocation ( mProgram, "aTexCoord" ) GLES30. glEnableVertexAttribArray ( textureHandle) GLES30. glVertexAttribPointer ( textureHandle, TEXTURE_POS_DATA_SIZE, GLES30. GL_FLOAT, false , STRIDE, VERTEX_POS_DATA_SIZE * 4 ) GLES30. glGenBuffers ( mIBO. size, mIBO, NO_OFFSET) GLES30. glBindBuffer ( GLES30. GL_ELEMENT_ARRAY_BUFFER, mIBO[ 0 ] ) GLES30. glBufferData ( GLES30. GL_ELEMENT_ARRAY_BUFFER, index. size * 2 , indexBuffer, GLES30. GL_STATIC_DRAW) GLES30. glBindVertexArray ( 0 ) GLES30. glBindBuffer ( GLES30. GL_ARRAY_BUFFER, 0 ) GLES30. glBindBuffer ( GLES30. GL_ELEMENT_ARRAY_BUFFER, 0 ) } fun drawSomething ( program: Int, mvpMatrix: FloatArray) { val matrixHandle = GLES30. glGetUniformLocation ( program, "uMVPMatrix" ) GLES30. glUniformMatrix4fv ( matrixHandle, 1 , false , mvpMatrix, NO_OFFSET) GLES30. glBindVertexArray ( mVAO[ 0 ] ) GLES30. glDrawElements ( GLES30. GL_TRIANGLES, index. size, GLES30. GL_UNSIGNED_SHORT, NO_OFFSET) GLES30. glBindVertexArray ( 0 ) } fun resetMatrix ( ) { Matrix. setIdentityM ( mModelMatrix, NO_OFFSET) Matrix. setIdentityM ( mViewMatrix, NO_OFFSET) Matrix. setIdentityM ( mProjectionMatrix, NO_OFFSET) Matrix. setIdentityM ( mMVPMatrix, NO_OFFSET) } fun computeMVPMatrix ( width: Int, height: Int) { val isLandscape = width > heightmViewPortRatio = if ( isLandscape) width. toFloat ( ) / height else height. toFloat ( ) / widthval radius = sqrt ( 1f + mViewPortRatio * mViewPortRatio) val near = 0.1f val far = near + 2 * radiusval distance = near / ( near + radius) Matrix. setLookAtM ( mViewMatrix, NO_OFFSET, 0f , 0f , near + radius, 0f , 0f , 0f , 0f , 1f , 0f ) Matrix. frustumM ( mProjectionMatrix, NO_OFFSET, if ( isLandscape) ( - mViewPortRatio * distance) else ( - 1f * distance) , if ( isLandscape) ( mViewPortRatio * distance) else ( 1f * distance) , if ( isLandscape) ( - 1f * distance) else ( - mViewPortRatio * distance) , if ( isLandscape) ( 1f * distance) else ( mViewPortRatio * distance) , near, far ) Matrix. multiplyMM ( mMVPMatrix, NO_OFFSET, mViewMatrix, NO_OFFSET, mModelMatrix, NO_OFFSET) Matrix. multiplyMM ( mMVPMatrix, NO_OFFSET, mProjectionMatrix, NO_OFFSET, mMVPMatrix, NO_OFFSET) Matrix. scaleM ( mMVPMatrix, NO_OFFSET, 1f , - 1f , 1f , ) } 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 ) Log. e ( "yang" , "loadTexture: 纹理加载成功 bitmap.width:${ bitmap. width} bitmap.height:${ bitmap. height} " ) return textureId[ 0 ] } fun enableTexture0 ( program: Int, id: Int) { GLES30. glActiveTexture ( GLES30. GL_TEXTURE0) GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, id) val textureSampleHandle = GLES30. glGetUniformLocation ( program, "uTexture_0" ) if ( textureSampleHandle != - 1 ) { GLES30. glUniform1i ( textureSampleHandle, 0 ) } } fun disableTexture0 ( ) { GLES30. glActiveTexture ( GLES30. GL_TEXTURE0) GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, 0 ) } fun initTexture0 ( context: Context, resourceId: Int) { mTextureID[ 0 ] = loadTexture ( context, resourceId) } fun drawCurrentOutput ( ) { val state = saveGLState ( ) try { GLES30. glUseProgram ( mProgram) enableTexture0 ( mProgram, mTextureID[ 0 ] ) drawSomething ( mProgram, mMVPMatrix) disableTexture0 ( ) } finally { restoreGLState ( state) } } private fun saveGLState ( ) : GLState { val viewport = IntArray ( 4 ) val program = IntArray ( 1 ) val framebuffer = IntArray ( 1 ) GLES30. glGetIntegerv ( GLES30. GL_VIEWPORT, viewport, 0 ) GLES30. glGetIntegerv ( GLES30. GL_CURRENT_PROGRAM, program, 0 ) GLES30. glGetIntegerv ( GLES30. GL_FRAMEBUFFER_BINDING, framebuffer, 0 ) return GLState ( viewport, program[ 0 ] , framebuffer[ 0 ] ) } private fun restoreGLState ( state: GLState) { GLES30. glViewport ( state. viewport[ 0 ] , state. viewport[ 1 ] , state. viewport[ 2 ] , state. viewport[ 3 ] ) GLES30. glUseProgram ( state. program) GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, state. framebuffer) } data class GLState ( val viewport: IntArray, val program: Int, val framebuffer: Int) object LoadShaderUtil { fun loadShader ( type: Int, source: String) : Int { val shader = GLES30. glCreateShader ( type) GLES30. glShaderSource ( shader, source) GLES30. glCompileShader ( shader) return shader} }
}
解析说明
顶点坐标和纹理坐标的存储
顶点坐标的四个角和纹理坐标的四个角进行对应,顶点由(x, y, z)
三个点构成,纹理由(u, v)
两个点构成
val vertexData = floatArrayOf ( - 1.0f , 1.0f , 0.0f , 0.0f , 1.0f , - 1.0f , - 1.0f , 0.0f , 0.0f , 0.0f , 1.0f , 1.0f , 0.0f , 1.0f , 1.0f , 1.0f , - 1.0f , 0.0f , 1.0f , 0.0f
)
顶点坐标和纹理坐标的解析
生成并绑定需要存储顶点坐标和纹理坐标的顶点缓冲对象(Vertex Buffer Object)VBO
方法: GLES30.glGenBuffers()
和GLES30.glBufferData()
向顶点缓冲对象中写入顶点坐标和纹理坐标数组的数组缓冲GL_ARRAY_BUFFER
方法: GLES30.glBufferData()
获取顶点坐标和纹理坐标的属性指针并启用 方法:GLES30.glGetAttribLocation()
和GLES30.glEnableVertexAttribArray()
按照步长和偏移量解析顶点坐标和纹理坐标, 步长 = (顶点坐标三个点 + 纹理坐标两个点) * Float数据类型字节数为4
偏移量 = 顶点坐标三个点 * Float数据类型字节数为4
方法: GLES30.glVertexAttribPointer()
fun initVertexBuffer ( ) { GLES30. glGenVertexArrays ( mVAO. size, mVAO, NO_OFFSET) GLES30. glBindVertexArray ( mVAO[ 0 ] ) GLES30. glGenBuffers ( mVBO. size, mVBO, NO_OFFSET) GLES30. glBindBuffer ( GLES30. GL_ARRAY_BUFFER, mVBO[ 0 ] ) GLES30. glBufferData ( GLES30. GL_ARRAY_BUFFER, vertexData. size * 4 , vertexDataBuffer, GLES30. GL_STATIC_DRAW) val positionHandle = GLES30. glGetAttribLocation ( mProgram, "aPosition" ) GLES30. glEnableVertexAttribArray ( positionHandle) GLES30. glVertexAttribPointer ( positionHandle, VERTEX_POS_DATA_SIZE, GLES30. GL_FLOAT, false , STRIDE, NO_OFFSET ) val textureHandle = GLES30. glGetAttribLocation ( mProgram, "aTexCoord" ) GLES30. glEnableVertexAttribArray ( textureHandle) GLES30. glVertexAttribPointer ( textureHandle, TEXTURE_POS_DATA_SIZE, GLES30. GL_FLOAT, false , STRIDE, VERTEX_POS_DATA_SIZE * 4 ) GLES30. glGenBuffers ( mIBO. size, mIBO, NO_OFFSET) GLES30. glBindBuffer ( GLES30. GL_ELEMENT_ARRAY_BUFFER, mIBO[ 0 ] ) GLES30. glBufferData ( GLES30. GL_ELEMENT_ARRAY_BUFFER, index. size * 2 , indexBuffer, GLES30. GL_STATIC_DRAW) GLES30. glBindVertexArray ( 0 ) GLES30. glBindBuffer ( GLES30. GL_ARRAY_BUFFER, 0 ) GLES30. glBindBuffer ( GLES30. GL_ELEMENT_ARRAY_BUFFER, 0 )
}
效果图