OpenGL ES3.0 實(shí)現(xiàn)靈魂出竅效果
分為兩步:1使用GLSurfaceView 實(shí)現(xiàn)攝像頭預(yù)覽, 2實(shí)現(xiàn)具體的效果
- 用GLSurfaceView實(shí)現(xiàn)攝像頭預(yù)覽,剛開始感覺(jué)很難妥色,實(shí)際上很簡(jiǎn)單,生成TextureId, 根據(jù)TextureId,生成SurfaceTexture,用SurfaceTexture來(lái)存儲(chǔ)攝像頭的預(yù)覽數(shù)據(jù)缝驳,然后用OpenGl把紋理畫出來(lái)
生成TextureId代碼如下:
//生成紋理Id
fun createTextureObject(): Int {
var tex = IntArray(1)
//生成一個(gè)紋理
GLES30.glGenTextures(1, tex, 0)
//將此紋理綁定到外部紋理上
GLES30.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, tex[0])
//設(shè)置紋理過(guò)濾參數(shù)
GLES30.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_NEAREST.toFloat())
GLES30.glTexParameterf(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR.toFloat())
GLES30.glTexParameterf(
GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GL10.GL_TEXTURE_WRAP_S,
GL10.GL_CLAMP_TO_EDGE.toFloat()
)
GLES30.glTexParameterf(
GLES11Ext.GL_TEXTURE_EXTERNAL_OES,
GL10.GL_TEXTURE_WRAP_T,
GL10.GL_CLAMP_TO_EDGE.toFloat()
)
GLES30.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0)
return tex[0]
}
根據(jù)TextureId生成SurfaceTexture
fun initSurfaceTexture(): Boolean {
if (mCamera == null || mGLSurfaceView == null) {
Log.i(TAG, "mCamera or mGLSurfaceView is null!")
return false
}
mSurfaceTexture = SurfaceTexture(mOESTextureId)
mSurfaceTexture?.let {
it.setOnFrameAvailableListener {
mGLSurfaceView.requestRender()
}
}
//將此SurfaceTexture作為相機(jī)預(yù)覽輸出
mCamera?.let {
it.setPreviewTexture(mSurfaceTexture!!)
it.startPreview()
}
return true
}
得到紋理矩陣并且繪制出來(lái)
override fun onDrawFrame(gl: GL10?) {
val t1 = System.currentTimeMillis()
mSurfaceTexture?.updateTexImage()
mSurfaceTexture?.getTransformMatrix(transformMatrix)
if (!isPreviewStarted) {
//在onDrawFrame方法中調(diào)用此方法initSurfaceTexture();
// 有了外部紋理,現(xiàn)在可以實(shí)例化一個(gè)SurfaceTexture了归苍,之后即可開啟Camera預(yù)覽
isPreviewStarted = initSurfaceTexture()
isPreviewStarted = true
return
}
GLES30.glClearColor(1.0f, 0.0f, 0.0f, 0.0f)
mCameraEngine?.drawTexture(transformMatrix)
GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0)
val t2 = System.currentTimeMillis()
val t = t2 - t1
Log.i("onDrawFrame", "onDrawFrame: time: $t")
}
至此通過(guò)OpenGL預(yù)覽攝像頭完成用狱,需要注意的是SurfaceTexture的監(jiān)聽setOnFrameAvailableListener,當(dāng)攝像頭有幀可用時(shí)拼弃,會(huì)不聽的回調(diào)此方法夏伊,之后通過(guò)GLSurfaceView的requestRender()方法來(lái)請(qǐng)求繪制,此時(shí)onDrawFrame()會(huì)被會(huì)掉吻氧,之后SurfaceView刷新并把紋理數(shù)據(jù)傳遞到紋理矩陣供OpenGL 繪制畫面
- 實(shí)現(xiàn)靈魂出竅效果溺忧,代碼如下
override fun drawTexture(transformMatrix: FloatArray) {
GLES30.glEnable(GLES30.GL_BLEND)
GLES30.glBlendFunc(GLES30.GL_SRC_ALPHA, GLES30.GL_ONE_MINUS_SRC_ALPHA)
GLES30.glUseProgram(mShaderProgram)
aPositionLocation = GLES30.glGetAttribLocation(mShaderProgram, POSITION_ATTRIBUTE)
aTextureCoordLocation = GLES30.glGetAttribLocation(mShaderProgram, TEXTURE_COORD_ATTRIBUTE)
uTextureMatrixLocation = GLES30.glGetUniformLocation(mShaderProgram, TEXTURE_MATRIX_UNIFORM)
uTextureSamplerLocation = GLES30.glGetUniformLocation(mShaderProgram, TEXTURE_SAMPLER_UNIFORM)
uTextureAlphaLocation = GLES30.glGetUniformLocation(mShaderProgram, TEXTURE_APLHA_UNIFORM)
uMvpMatrixLocation = GLES30.glGetUniformLocation(mShaderProgram, MVP_MATRIX)
mProgress = mFrames.toFloat() / mMaxFrames
if (mProgress > 1f) {
mProgress = 0f
}
mFrames++
if (mFrames > mMaxFrames + mSkipFrames) {
mFrames = 0
}
var backAlpha = 1f
var alpha = 0f
if (mProgress > 0f) {
alpha = 0.2f - mProgress * 0.2f
backAlpha = 1 - alpha
}
GLES30.glActiveTexture(GLES30.GL_TEXTURE0)
GLES30.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, mOESTextureId)
GLES30.glUniform1i(uTextureSamplerLocation, 0)
GLES30.glUniformMatrix4fv(uTextureMatrixLocation, 1, false, transformMatrix, 0)
Matrix.setIdentityM(mMvpMatrix, 0)
GLES30.glUniformMatrix4fv(uMvpMatrixLocation, 1, false, mMvpMatrix, 0)
GLES30.glUniform1f(uTextureAlphaLocation, backAlpha)
if (mBuffer != null) {
mBuffer!!.position(0)
GLES30.glEnableVertexAttribArray(aPositionLocation)
GLES30.glVertexAttribPointer(aPositionLocation, 2, GLES30.GL_FLOAT, false, 16, mBuffer)
mBuffer!!.position(2)
GLES30.glEnableVertexAttribArray(aTextureCoordLocation)
GLES30.glVertexAttribPointer(aTextureCoordLocation, 2, GLES30.GL_FLOAT, false, 16, mBuffer)
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 6)
}
if (mProgress > 0f) {
GLES30.glUniform1f(uTextureAlphaLocation, alpha)
val scale = 1.0f + 1f * mProgress
Matrix.scaleM(mMvpMatrix, 0, scale, scale, scale)
GLES30.glUniformMatrix4fv(uMvpMatrixLocation, 1, false, mMvpMatrix, 0)
GLES30.glDrawArrays(GLES30.GL_TRIANGLES, 0, 6)
}
GLES30.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, 0);
GLES30.glDisable(GLES30.GL_BLEND)
}
畫兩層,第一層是預(yù)覽的原始畫面盯孙,第二層是靈魂出竅的效果鲁森,靈魂出竅的效果,實(shí)際就是把當(dāng)前幀的不斷的放大并且變得透明振惰,代碼很簡(jiǎn)單刀森,需要注意的是混合因子