GLSurfaceView绘制图形拉伸问题
 
- 假如在XML文件中声明GLSurfaceView的宽高为- android:layout_width="match_parent"
- android:layout_height="match_parent
 
- GLSurfaceView绘制的图形在- Open GL ES坐标系中,而- Open GL ES坐标系会根据- GLSurfaceView的宽高将绘制的图形拉伸,比如绘制一个正方形,有可能绘制成矩形,解决方案:
- Matrix.frustumM透视投影解决
- Matrix.orthoM正交投影解决
public static void frustumM(float[] m, int offset,float left, float right, float bottom, float top,float near, float far) {}
public static void orthoM(float[] m, int mOffset,float left, float right, float bottom, float top,float near, float far) {}
 
OpenGL ES坐标系
 

 
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()init {setEGLContextClientVersion(3)setRenderer(mRenderer)renderMode = RENDERMODE_WHEN_DIRTY}
}
 
自定义GLSurfaceView.Renderer代码
 
class MyGLRenderer : 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()}}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)mDrawData?.drawSomething()}
}
 
GLSurfaceView需要的绘制数据
 
class DrawData{var mProgram : Int = -1var NO_OFFSET = 0var VERTEX_POS_DATA_SIZE = 3val vertex = floatArrayOf(-0.5f,  0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, 0.5f, 0.0f, 0.5f, -0.5f, 0.0f, )val vertexBuffer = ByteBuffer.allocateDirect(vertex.size * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer()fun initVertexBuffer(){vertexBuffer.put(vertex) 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,vertex.size * 4, vertexBuffer,GLES30.GL_STATIC_DRAW)}fun initShader()  {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()         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)}fun drawSomething(){val positionHandle = GLES30.glGetAttribLocation(mProgram, "aPosition")GLES30.glEnableVertexAttribArray(positionHandle)GLES30.glVertexAttribPointer(positionHandle, VERTEX_POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, 0)val colorHandle = GLES30.glGetUniformLocation(mProgram, "vColor")GLES30.glUniform4f(colorHandle, 1.0f, 0.5f, 0.5f, 1.0f) GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, NO_OFFSET, vertex.size / VERTEX_POS_DATA_SIZE)GLES30.glDisableVertexAttribArray(positionHandle)}
}object LoadShaderUtil{fun loadShader(type: Int, source: String): Int {val shader = GLES30.glCreateShader(type)GLES30.glShaderSource(shader, source)GLES30.glCompileShader(shader)return shader}
}
 
效果图
 

 
透视投影绘制不拉伸的正方形
 
透视投影PerspectiveProjection
 
自定义GLSurfaceView代码
 
class MyGLSurfaceView(context: Context, attrs: AttributeSet) : GLSurfaceView(context, attrs) {private var mRenderer = MyGLRenderer()init {setEGLContextClientVersion(3)setRenderer(mRenderer)renderMode = RENDERMODE_WHEN_DIRTY}
}
 
自定义GLSurfaceView.Renderer代码
 
class MyGLRenderer : GLSurfaceView.Renderer {private var mDrawData: DrawDataWithPerspectiveProjection? = nulloverride fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {GLES30.glClearColor(0.0f, 0.5f, 0.5f, 1.0f)mDrawData = DrawDataWithPerspectiveProjection().apply {initVertexBuffer()initShader()}}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?.drawSomething()}
}
 
GLSurfaceView需要的绘制数据
 
class DrawDataWithPerspectiveProjection {var mProgram : Int = -1var NO_OFFSET = 0var VERTEX_POS_DATA_SIZE = 3val vertex = floatArrayOf(-0.5f,  0.5f, 0.0f, -0.5f, -0.5f, 0.0f, 0.5f, 0.5f, 0.0f, 0.5f, -0.5f, 0.0f, )val vertexBuffer = ByteBuffer.allocateDirect(vertex.size * 4) .order(ByteOrder.nativeOrder()) .asFloatBuffer()fun initVertexBuffer(){vertexBuffer.put(vertex) 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,vertex.size * 4, vertexBuffer,GLES30.GL_STATIC_DRAW)}fun initShader()  {val vertexMapShaderCode = """#version 300 esuniform mat4 uMVPMatrix;layout (location = 0) in vec4 aPosition;void main() {gl_Position = uMVPMatrix * aPosition;}""".trimIndent()val fragmentShaderCode = """#version 300 esprecision mediump float;uniform vec4 vColor;out vec4 fragColor;void main() {fragColor = vColor;}""".trimIndent()         val vertexShader = LoadShaderUtil.loadShader(GLES30.GL_VERTEX_SHADER, vertexMapShaderCode)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)}fun drawSomething(){val matrixHandle = GLES30.glGetUniformLocation(mProgram, "uMVPMatrix")GLES30.glUniformMatrix4fv(matrixHandle, 1, false, mMVPMatrix, 0)val positionHandle = GLES30.glGetAttribLocation(mProgram, "aPosition")GLES30.glEnableVertexAttribArray(positionHandle)GLES30.glVertexAttribPointer(positionHandle, VERTEX_POS_DATA_SIZE, GLES30.GL_FLOAT, false, 0, 0)val colorHandle = GLES30.glGetUniformLocation(mProgram, "vColor")GLES30.glUniform4f(colorHandle, 1.0f, 0.5f, 0.5f, 1.0f) GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, NO_OFFSET, vertex.size / VERTEX_POS_DATA_SIZE)GLES30.glDisableVertexAttribArray(positionHandle)}private val mMVPMatrix = FloatArray(16)private val mProjectionMatrix = FloatArray(16)private val mViewMatrix = FloatArray(16)private var mViewPortRatio = 1ffun computeMVPMatrix(width: Float, height: Float) {takeIf { width > height }?.let {mViewPortRatio = width / heightMatrix.frustumM(mProjectionMatrix, NO_OFFSET, -mViewPortRatio, mViewPortRatio, -1f, 1f, 1f, 2f )} ?: run {mViewPortRatio = height / widthMatrix.frustumM(mProjectionMatrix, NO_OFFSET, -1f, 1f, -mViewPortRatio, mViewPortRatio, 1f, 2f )}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 )}
}
 
效果图
 
