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 es
uniform mat4 uMVPMatrix;
in vec4 aPosition;
in vec2 aTexCoord;
out vec2 vTexCoord;
void main ( ) {
gl_Position = uMVPMatrix * aPosition;
vTexCoord = aTexCoord;
} """.trimIndent()
val fragmentShaderCode = """ #version 300 es
precision 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 > height
mViewPortRatio = if ( isLandscape) width. toFloat ( ) / height else height. toFloat ( ) / width
val radius = sqrt ( 1f + mViewPortRatio * mViewPortRatio)
val near = 0.1f
val far = near + 2 * radius
val 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 )
}
效果图