OpenGL ES3.0 实现灵魂出窍效果

OpenGL ES3.0 实现灵魂出窍效果

分为两步:1使用GLSurfaceView 实现摄像头预览, 2实现具体的效果

  • 用GLSurfaceView实现摄像头预览,刚开始感觉很难,实际上很简单,生成TextureId, 根据TextureId,生成SurfaceTexture,用SurfaceTexture来存储摄像头的预览数据,然后用OpenGl把纹理画出来

生成TextureId代码如下:

//生成纹理Id
fun createTextureObject(): Int {
var tex = IntArray(1)

//生成一个纹理
GLES30.glGenTextures(1, tex, 0)

//将此纹理绑定到外部纹理上
GLES30.glBindTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES, tex[0])
//设置纹理过滤参数
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]
}

根据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作为相机预览输出
mCamera?.let {
it.setPreviewTexture(mSurfaceTexture!!)
it.startPreview()
}

return true
}

得到纹理矩阵并且绘制出来

override fun onDrawFrame(gl: GL10?) {
val t1 = System.currentTimeMillis()

mSurfaceTexture?.updateTexImage()
mSurfaceTexture?.getTransformMatrix(transformMatrix)

if (!isPreviewStarted) {
//在onDrawFrame方法中调用此方法initSurfaceTexture();
// 有了外部纹理,现在可以实例化一个SurfaceTexture了,之后即可开启Camera预览
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")
}

至此通过OpenGL预览摄像头完成,需要注意的是SurfaceTexture的监听setOnFrameAvailableListener,当摄像头有帧可用时,会不听的回调此方法,之后通过GLSurfaceView的requestRender()方法来请求绘制,此时onDrawFrame()会被会掉,之后SurfaceView刷新并把纹理数据传递到纹理矩阵供OpenGL 绘制画面

  • 实现灵魂出窍效果,代码如下
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)
}

画两层,第一层是预览的原始画面,第二层是灵魂出窍的效果,灵魂出窍的效果,实际就是把当前帧的不断的放大并且变得透明,代码很简单,需要注意的是混合因子

你可能感兴趣的:(OpenGL ES3.0 实现灵魂出窍效果)