使用openGL渲染图片纹理,需要特别注意纹理坐标问题:openGL纹理坐标原点在左下角,Android中坐标系原点在左上角,即openGL纹理坐标与Android坐标系在Y轴恰好相反。因此在纹理采样时,按照openGL纹理坐标采样,则Android窗体中显示时会出现上下翻转的问题,未解决此问题,可以在采样阶段将openGL纹理坐标上下翻转,最终采样结束在窗体可以正常显示。(个人理解)
顶点着色器
attribute vec4 a_Position;
attribute vec2 a_TextureCoordinate;
varying vec2 vTextureCoord;
void main() {
vTextureCoord = a_TextureCoordinate;
gl_Position = a_Position;
}
片元着色器
precision mediump float;
uniform sampler2D u_TextureSampler;
varying vec2 vTextureCoord;
void main() {
gl_FragColor = texture2D(u_TextureSampler, vTextureCoord);
}
private val VERTEX = floatArrayOf(
-1f, 1f, 0f,
-1f, -1f, 0f,
1f, 1f, 0f,
1f, -1f, 0f,
)
private val TEXTURE = floatArrayOf(
0f, 0f,
0f, 1f,
1f, 0f,
1f, 1f,
)
private val INDICES = intArrayOf(
0, 1, 2, 1, 2, 3
)
class OpenGLImageActivity : Activity(), GLSurfaceView.Renderer {
private var mProgram: Int = GLES30.GL_NONE
private var mVao: Int = GLES30.GL_NONE
private var mTextureId: Int = GLES30.GL_NONE
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_opengl_video)
findViewById(R.id.surfaceView).apply {
setEGLContextClientVersion(3)
setRenderer(this@OpenGLImageActivity)
}
}
override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) {
GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT or GLES30.GL_DEPTH_BUFFER_BIT)
mProgram = newProgram(R.raw.vertex_image, R.raw.fragment_image)
bufferData()
mTextureId = createTexture()
}
override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) {
GLES30.glViewport(0, 0, width, height)
}
override fun onDrawFrame(gl: GL10?) {
GLES30.glClearColor(0f, 0f, 0f, 1f)
GLES30.glActiveTexture(GLES30.GL_TEXTURE0)
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextureId)
GLUtils.texImage2D(GLES30.GL_TEXTURE_2D, 0, decodeResource(resources, R.drawable.scs), 0)
GLES30.glUseProgram(mProgram)
GLES30.glBindVertexArray(mVao)
GLES30.glActiveTexture(GLES30.GL_TEXTURE0)
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, mTextureId)
GLES30.glDrawElements(GLES30.GL_TRIANGLES, INDICES.size, GLES30.GL_UNSIGNED_INT, 0)
}
private fun newProgram(vertex: Int, fragment: Int): Int {
val vShader = GLES30.glCreateShader(GLES30.GL_VERTEX_SHADER)
GLES30.glShaderSource(vShader, ResReadUtils.readResource(this, vertex))
GLES30.glCompileShader(vShader)
val fShader = GLES30.glCreateShader(GLES30.GL_FRAGMENT_SHADER)
GLES30.glShaderSource(fShader, ResReadUtils.readResource(this, fragment))
GLES30.glCompileShader(fShader)
val program = GLES30.glCreateProgram()
GLES30.glAttachShader(program, vShader)
GLES30.glAttachShader(program, fShader)
GLES30.glLinkProgram(program)
return program
}
private fun bufferData() {
val aPosition = GLES30.glGetAttribLocation(mProgram, "a_Position")
val uTexturePosition = GLES30.glGetAttribLocation(mProgram, "a_TextureCoordinate")
val vao = IntArray(1)
val vbo = IntArray(2)
GLES30.glGenVertexArrays(vao.size, vao, 0)
GLES30.glGenBuffers(vbo.size, vbo, 0)
GLES30.glBindVertexArray(vao[0])
GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, vbo[0])
GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, VERTEX.size * 4 + TEXTURE.size * 4, null, GLES30.GL_STATIC_DRAW)
GLES30.glBufferSubData(GLES30.GL_ARRAY_BUFFER, 0, VERTEX.size * 4, RenderUtils.floatBuffer(VERTEX))
GLES30.glBufferSubData(GLES30.GL_ARRAY_BUFFER, VERTEX.size * 4, TEXTURE.size * 4, RenderUtils.floatBuffer(TEXTURE))
GLES30.glEnableVertexAttribArray(aPosition)
GLES30.glVertexAttribPointer(aPosition, 3, GLES30.GL_FLOAT, false, 3 * 4, 0)
GLES30.glEnableVertexAttribArray(uTexturePosition)
GLES30.glVertexAttribPointer(uTexturePosition, 2, GLES30.GL_FLOAT, false, 2 * 4, VERTEX.size * 4)
GLES30.glBindBuffer(GLES30.GL_ELEMENT_ARRAY_BUFFER, vbo[1])
GLES30.glBufferData(GLES30.GL_ELEMENT_ARRAY_BUFFER, INDICES.size * 4, RenderUtils.intBuffer(INDICES), GLES30.GL_STATIC_DRAW)
mVao = vao[0]
}
private fun createTexture(): Int {
val textureArray = IntArray(1)
GLES30.glGenTextures(1, textureArray, 0)
GLES30.glBindTexture(GLES30.GL_TEXTURE_2D, textureArray[0])
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)
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MAG_FILTER, GLES30.GL_LINEAR)
GLES30.glTexParameteri(GLES30.GL_TEXTURE_2D, GLES30.GL_TEXTURE_MIN_FILTER, GLES30.GL_LINEAR)
return textureArray[0]
}
}