乒乓缓冲核心思想
不使用乒乓缓冲,如果要每个滤镜作用下的绘制内容,也就是这个滤镜作用下的帧缓冲,需要创建一个Frame Buffer Object
加上对应的Frame Buffer Object Texture
使用乒乓缓冲,只用两个Frame Buffer Object
加上对应的Frame Buffer Object Texture
,Open GL
渲染管线不允许读取一个帧缓冲的同时,对这个帧缓冲的纹理进行写入,这样会导致读写冲突绘制内容出错,所以用到乒乓缓冲,绑定一个帧缓冲的同时,使用另外一个帧缓冲的纹理,交替使用
XML文件
<?xml version="1.0" encoding="utf-8"?>
< RelativeLayout xmlns: android= " http://schemas.android.com/apk/res/android"
android: layout_width= " match_parent"
android: layout_height= " match_parent" >
< com.example.myapplication.MyGLSurfaceView
android: id= " @+id/gl_surface_view"
android: layout_width= " match_parent"
android: layout_height= " match_parent" />
< ImageView
android: id= " @+id/image_view_1"
android: layout_width= " 180dp"
android: layout_height= " 180dp"
android: layout_alignParentStart= " true"
android: layout_alignParentTop= " true"
android: layout_margin= " 10dp"
android: background= " #33000000" />
< ImageView
android: id= " @+id/image_view_2"
android: layout_width= " 180dp"
android: layout_height= " 180dp"
android: layout_alignParentEnd= " true"
android: layout_alignParentTop= " true"
android: layout_margin= " 10dp"
android: background= " #33000000" />
< ImageView
android: id= " @+id/image_view_3"
android: layout_width= " 180dp"
android: layout_height= " 180dp"
android: layout_alignParentStart= " true"
android: layout_alignParentBottom= " true"
android: layout_margin= " 10dp"
android: background= " #33000000" />
< ImageView
android: id= " @+id/image_view_4"
android: layout_width= " 180dp"
android: layout_height= " 180dp"
android: layout_alignParentEnd= " true"
android: layout_alignParentBottom= " true"
android: layout_margin= " 10dp"
android: background= " #33000000" />
< Button
android: id= " @+id/capture_button"
android: layout_width= " wrap_content"
android: layout_height= " wrap_content"
android: layout_alignParentBottom= " true"
android: layout_centerHorizontal= " true"
android: layout_marginBottom= " 10dp"
android: text= " 滤镜渲染"
android: padding= " 12dp" />
</ RelativeLayout>
Activity
代码
class MainActivity : AppCompatActivity ( ) {
private lateinit var glSurfaceView: MyGLSurfaceView
private lateinit var imageView1: ImageView
private lateinit var imageView2: ImageView
private lateinit var imageView3: ImageView
private lateinit var imageView4: ImageView
private lateinit var captureButton: Button
@SuppressLint ( "MissingInflatedId" )
override fun onCreate ( savedInstanceState: Bundle? ) {
super . onCreate ( savedInstanceState)
setContentView ( R. layout. activity_main)
glSurfaceView = findViewById ( R. id. gl_surface_view)
imageView1 = findViewById ( R. id. image_view_1)
imageView2 = findViewById ( R. id. image_view_2)
imageView3 = findViewById ( R. id. image_view_3)
imageView4 = findViewById ( R. id. image_view_4)
captureButton = findViewById ( R. id. capture_button)
captureButton. setOnTouchListener ( object : View. OnTouchListener {
override fun onTouch ( v: View? , event: MotionEvent? ) : Boolean {
when ( event? . action) {
MotionEvent. ACTION_DOWN -> {
glSurfaceView? . getDrawData ( ) ? . getEdgeFilterBitmap ( ) ? . let {
imageView1. setImageBitmap ( it)
}
glSurfaceView? . getDrawData ( ) ? . getPixelFilterBitmap ( ) ? . let {
imageView2. setImageBitmap ( it)
}
glSurfaceView? . getDrawData ( ) ? . getColorFilterBitmap ( ) ? . let {
imageView3. setImageBitmap ( it)
}
glSurfaceView? . getDrawData ( ) ? . getOriginBitmap ( ) ? . let {
imageView4. setImageBitmap ( it)
}
}
MotionEvent. ACTION_UP -> {
imageView1. setImageBitmap ( null )
imageView2. setImageBitmap ( null )
imageView3. setImageBitmap ( null )
imageView4. setImageBitmap ( null )
}
}
return true
}
} )
}
}
自定义GLSurfaceView
代码
class MyGLSurfaceView ( context: Context, attrs: AttributeSet) : GLSurfaceView ( context, attrs) {
private var mRenderer = MyGLRenderer ( context)
init {
setEGLContextClientVersion ( 3 )
setRenderer ( mRenderer)
renderMode = RENDERMODE_WHEN_DIRTY
}
fun getDrawData ( ) : DrawData? {
return mRenderer? . getDrawData ( )
}
}
自定义GLSurfaceView.Renderer
代码
class MyGLRenderer ( private val mContext: Context) : GLSurfaceView. Renderer {
private var mDrawData: DrawData? = null
override fun onSurfaceCreated ( gl: GL10? , config: EGLConfig? ) {
GLES30. glClearColor ( 0.0f , 0.5f , 0.5f , 1.0f )
mDrawData = DrawData ( ) . apply {
initTexture0 ( mContext, R. drawable. picture)
initShader ( )
initVertexBuffer ( )
initFrameBuffer ( )
initEdgeFilterShader ( )
initPixelFilterShader ( )
initColorFilterShader ( )
initPingFrameBuffer ( )
initPongFrameBuffer ( )
}
}
override fun onSurfaceChanged ( gl: GL10? , width: Int, height: Int) {
GLES30. glViewport ( 0 , 0 , width, height)
mDrawData? . computeMVPMatrix ( width, height)
}
override fun onDrawFrame ( gl: GL10? ) {
GLES30. glClear ( GLES30. GL_COLOR_BUFFER_BIT)
mDrawData? . drawOriginFrameBuffer ( )
mDrawData? . drawPixelFilterBitmap ( )
mDrawData? . drawColorFilterBitmap ( )
mDrawData? . drawEdgeFilterBitmap ( )
mDrawData? . drawGLSurfaceView ( )
}
fun getDrawData ( ) : DrawData? {
return mDrawData
}
}
GLSurfaceView.Renderer
需要的绘制数据
class DrawData {
private var NO_OFFSET = 0
private val VERTEX_POS_DATA_SIZE = 3
private val TEXTURE_POS_DATA_SIZE = 2
private var mProgram: Int = - 1
private var mEdgeProgram : Int = - 1
private var mPixelProgram : Int = - 1
private var mColorProgram : Int = - 1
private var mFBO = IntArray ( 1 )
private var mEdgeFBO = IntArray ( 1 )
private var mPixelFBO = IntArray ( 1 )
private var mColorFBO = IntArray ( 1 )
private var mPingFBO = IntArray ( 1 )
private var mPongFBO = IntArray ( 1 )
private var mVAO = IntArray ( 1 )
private var mVBO = IntArray ( 2 )
private var mIBO = IntArray ( 1 )
private var mTextureID = IntArray ( 1 )
private var mFBOTextureID = IntArray ( 1 )
private var mEdgeFBOTextureID = IntArray ( 1 )
private var mPixelFBOTextureID = IntArray ( 1 )
private var mColorFBOTextureID = IntArray ( 1 )
private var mPingTextureID = IntArray ( 1 )
private var mPongTextureID = IntArray ( 1 )
private var mMVPMatrix = FloatArray ( 16 )
private val mProjectionMatrix = FloatArray ( 16 )
private val mViewMatrix = FloatArray ( 16 )
private var mViewPortRatio = 1f
private var mFrameBufferWidth = 0
private var mFrameBufferHeight = 0
private val mFrameBufferMVPMatrix = FloatArray ( 16 )
val vertex = floatArrayOf (
- 1.0f , 1.0f , 0.0f ,
- 1.0f , - 1.0f , 0.0f ,
1.0f , 1.0f , 0.0f ,
1.0f , - 1.0f , 0.0f ,
)
val vertexBuffer = ByteBuffer. allocateDirect ( vertex. size * 4 )
. order ( ByteOrder. nativeOrder ( ) )
. asFloatBuffer ( )
. put ( vertex)
. position ( NO_OFFSET)
val textureCoords = floatArrayOf (
0.0f , 1.0f ,
0.0f , 0.0f ,
1.0f , 1.0f ,
1.0f , 0.0f ,
)
val textureBuffer = ByteBuffer. allocateDirect ( textureCoords. size * 4 )
. order ( ByteOrder. nativeOrder ( ) )
. asFloatBuffer ( )
. put ( textureCoords)
. 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)
private var mOriginBitmap : Bitmap ? = null
private var mEdgeFilterBitmap : Bitmap ? = null
private var mPixelFilterBitmap : Bitmap ? = null
private var mColorFilterBitmap : Bitmap ? = null
fun initShader ( ) {
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. glUseProgram ( 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,
vertex. size * 4 ,
vertexBuffer,
GLES30. GL_STATIC_DRAW
)
val positionHandle = GLES30. glGetAttribLocation ( mProgram, "aPosition" )
GLES30. glEnableVertexAttribArray ( positionHandle)
GLES30. glVertexAttribPointer (
positionHandle,
VERTEX_POS_DATA_SIZE,
GLES30. GL_FLOAT,
false ,
0 ,
NO_OFFSET
)
GLES30. glBindBuffer ( GLES30. GL_ARRAY_BUFFER, 0 )
GLES30. glBindBuffer ( GLES30. GL_ARRAY_BUFFER, mVBO[ 1 ] )
GLES30. glBufferData (
GLES30. GL_ARRAY_BUFFER,
textureCoords. size * 4 ,
textureBuffer,
GLES30. GL_STATIC_DRAW
)
val textureHandle = GLES30. glGetAttribLocation ( mProgram, "aTexCoord" )
GLES30. glEnableVertexAttribArray ( textureHandle)
GLES30. glVertexAttribPointer (
textureHandle,
TEXTURE_POS_DATA_SIZE,
GLES30. GL_FLOAT,
false ,
0 ,
NO_OFFSET
)
GLES30. glBindBuffer ( GLES30. GL_ARRAY_BUFFER, 0 )
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_ELEMENT_ARRAY_BUFFER, 0 )
}
fun initFrameBuffer ( ) {
GLES30. glGenFramebuffers ( mFBO. size, mFBO, NO_OFFSET)
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, mFBO[ 0 ] )
GLES30. glGenTextures ( mFBOTextureID. size, mFBOTextureID, NO_OFFSET)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, mFBOTextureID[ 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
)
GLES30. glTexImage2D (
GLES30. GL_TEXTURE_2D,
NO_OFFSET,
GLES30. GL_RGBA,
mFrameBufferWidth,
mFrameBufferHeight,
NO_OFFSET,
GLES30. GL_RGBA,
GLES30. GL_UNSIGNED_BYTE,
null
)
GLES30. glFramebufferTexture2D (
GLES30. GL_FRAMEBUFFER,
GLES30. GL_COLOR_ATTACHMENT0,
GLES30. GL_TEXTURE_2D,
mFBOTextureID[ 0 ] ,
0
)
if ( GLES30. glCheckFramebufferStatus ( GLES30. GL_FRAMEBUFFER) != GLES30. GL_FRAMEBUFFER_COMPLETE) {
Log. e ( "yang" , "initFrameBuffer: FBO初始化失败" )
}
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, 0 )
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, 0 )
}
fun drawOriginFrameBuffer ( ) {
val previousProgram = IntArray ( 1 )
val previousFrameBuffer = IntArray ( 1 )
val viewPort = IntArray ( 4 )
try {
GLES30. glGetIntegerv ( GLES30. GL_VIEWPORT, viewPort, NO_OFFSET)
GLES30. glGetIntegerv ( GLES30. GL_CURRENT_PROGRAM, previousProgram, 0 )
GLES30. glGetIntegerv ( GLES30. GL_FRAMEBUFFER_BINDING, previousFrameBuffer, 0 )
GLES30. glViewport ( 0 , 0 , mFrameBufferWidth, mFrameBufferHeight)
enableTexture0 ( mProgram, mTextureID[ 0 ] )
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, mFBO[ 0 ] )
GLES30. glClear ( GLES30. GL_COLOR_BUFFER_BIT)
computeFrameBufferMVPMatrix ( )
drawSomething ( mProgram, mFrameBufferMVPMatrix)
mOriginBitmap = savePixelBufferBitmap ( )
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, 0 )
disableTexture0 ( )
} finally {
GLES30. glViewport ( viewPort[ 0 ] , viewPort[ 1 ] , viewPort[ 2 ] , viewPort[ 3 ] )
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, previousFrameBuffer[ 0 ] )
GLES30. glUseProgram ( previousProgram[ 0 ] )
}
}
fun drawGLSurfaceView ( ) {
val previousProgram = IntArray ( 1 )
val previousFrameBuffer = IntArray ( 1 )
try {
GLES30. glGetIntegerv ( GLES30. GL_CURRENT_PROGRAM, previousProgram, 0 )
GLES30. glGetIntegerv ( GLES30. GL_FRAMEBUFFER_BINDING, previousFrameBuffer, 0 )
enableTexture0 ( mProgram, mPingTextureID[ 0 ] )
drawSomething ( mProgram, mMVPMatrix)
disableTexture0 ( )
} finally {
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, previousFrameBuffer[ 0 ] )
GLES30. glUseProgram ( previousProgram[ 0 ] )
}
}
fun drawEdgeFilterBitmap ( ) {
takeIf { mEdgeFilterBitmap == null } ? . let {
val previousProgram = IntArray ( 1 )
val previousFrameBuffer = IntArray ( 1 )
val viewPort = IntArray ( 4 )
try {
GLES30. glGetIntegerv ( GLES30. GL_VIEWPORT, viewPort, NO_OFFSET)
GLES30. glGetIntegerv ( GLES30. GL_CURRENT_PROGRAM, previousProgram, 0 )
GLES30. glGetIntegerv ( GLES30. GL_FRAMEBUFFER_BINDING, previousFrameBuffer, 0 )
GLES30. glViewport ( 0 , 0 , mFrameBufferWidth, mFrameBufferHeight)
GLES30. glUseProgram ( mEdgeProgram)
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, mPingFBO[ 0 ] )
GLES30. glClear ( GLES30. GL_COLOR_BUFFER_BIT)
enableTexture2 ( mEdgeProgram, mPongTextureID[ 0 ] )
val textureSizeHandle = GLES30. glGetUniformLocation ( mEdgeProgram, "uTextureSize" )
GLES30. glUniform2f ( textureSizeHandle, mFrameBufferWidth. toFloat ( ) , mFrameBufferHeight. toFloat ( ) )
drawSomething ( mEdgeProgram, mFrameBufferMVPMatrix)
mEdgeFilterBitmap = savePixelBufferBitmap ( )
disableTexture2 ( )
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, 0 )
} finally {
GLES30. glViewport ( viewPort[ 0 ] , viewPort[ 1 ] , viewPort[ 2 ] , viewPort[ 3 ] )
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, previousFrameBuffer[ 0 ] )
GLES30. glUseProgram ( previousProgram[ 0 ] )
}
}
}
fun drawPixelFilterBitmap ( ) {
takeIf { mPixelFilterBitmap == null } ? . let {
val previousProgram = IntArray ( 1 )
val previousFrameBuffer = IntArray ( 1 )
val viewPort = IntArray ( 4 )
try {
GLES30. glGetIntegerv ( GLES30. GL_VIEWPORT, viewPort, NO_OFFSET)
GLES30. glGetIntegerv ( GLES30. GL_CURRENT_PROGRAM, previousProgram, 0 )
GLES30. glGetIntegerv ( GLES30. GL_FRAMEBUFFER_BINDING, previousFrameBuffer, 0 )
GLES30. glViewport ( 0 , 0 , mFrameBufferWidth, mFrameBufferHeight)
GLES30. glUseProgram ( mPixelProgram)
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, mPingFBO[ 0 ] )
GLES30. glClear ( GLES30. GL_COLOR_BUFFER_BIT)
enableTexture3 ( mPixelProgram, mFBOTextureID[ 0 ] )
val textureSizeHandle = GLES30. glGetUniformLocation ( mPixelProgram, "uTextureSize" )
GLES30. glUniform2f ( textureSizeHandle, mFrameBufferWidth. toFloat ( ) , mFrameBufferWidth. toFloat ( ) )
val pixelSizeHandle = GLES30. glGetUniformLocation ( mPixelProgram, "uPixelSize" )
GLES30. glUniform1f ( pixelSizeHandle, 15.0f )
drawSomething ( mPixelProgram, mFrameBufferMVPMatrix)
mPixelFilterBitmap = savePixelBufferBitmap ( )
disableTexture3 ( )
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, 0 )
} finally {
GLES30. glViewport ( viewPort[ 0 ] , viewPort[ 1 ] , viewPort[ 2 ] , viewPort[ 3 ] )
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, previousFrameBuffer[ 0 ] )
GLES30. glUseProgram ( previousProgram[ 0 ] )
}
}
}
fun drawColorFilterBitmap ( ) {
takeIf { mColorFilterBitmap == null } ? . let {
val previousProgram = IntArray ( 1 )
val previousFrameBuffer = IntArray ( 1 )
val viewPort = IntArray ( 4 )
try {
GLES30. glGetIntegerv ( GLES30. GL_VIEWPORT, viewPort, NO_OFFSET)
GLES30. glViewport ( 0 , 0 , mFrameBufferWidth, mFrameBufferHeight)
GLES30. glGetIntegerv ( GLES30. GL_CURRENT_PROGRAM, previousProgram, 0 )
GLES30. glGetIntegerv ( GLES30. GL_FRAMEBUFFER_BINDING, previousFrameBuffer, 0 )
GLES30. glUseProgram ( mColorProgram)
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, mPongFBO[ 0 ] )
GLES30. glClear ( GLES30. GL_COLOR_BUFFER_BIT)
enableTexture4 ( mColorProgram, mPingTextureID[ 0 ] )
val timeHandle = GLES30. glGetUniformLocation ( mColorProgram, "uTime" )
if ( timeHandle != - 1 ) {
GLES30. glUniform1f ( timeHandle, ( System. currentTimeMillis ( ) % 10000 ) / 10000.0f )
}
val twistIntensityHandle = GLES30. glGetUniformLocation ( mColorProgram, "uTwistIntensity" )
GLES30. glUniform1f ( twistIntensityHandle, 0.15f )
drawSomething ( mColorProgram, mFrameBufferMVPMatrix)
mColorFilterBitmap = savePixelBufferBitmap ( )
disableTexture4 ( )
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, 0 )
} finally {
GLES30. glViewport ( viewPort[ 0 ] , viewPort[ 1 ] , viewPort[ 2 ] , viewPort[ 3 ] )
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, previousFrameBuffer[ 0 ] )
GLES30. glUseProgram ( previousProgram[ 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 initEdgeFilterShader ( ) {
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_2;
uniform vec2 uTextureSize;
in vec2 vTexCoord;
out vec4 fragColor;
void main ( ) {
float dx = 1.0 / uTextureSize. x;
float dy = 1.0 / uTextureSize. y;
vec4 center = texture ( uTexture_2, vTexCoord) ;
vec4 left = texture ( uTexture_2, vTexCoord - vec2 ( dx, 0.0 ) ) ;
vec4 right = texture ( uTexture_2, vTexCoord + vec2 ( dx, 0.0 ) ) ;
vec4 top = texture ( uTexture_2, vTexCoord - vec2 ( 0.0 , dy) ) ;
vec4 bottom = texture ( uTexture_2, vTexCoord + vec2 ( 0.0 , dy) ) ;
vec4 horizontal = abs ( right - left) ;
vec4 vertical = abs ( bottom - top) ;
float edge = ( horizontal. r + horizontal. g + horizontal. b +
vertical. r + vertical. g + vertical. b) / 6.0 ;
fragColor = vec4 ( vec3 ( 1.0 - edge * 3.0 ) , 1.0 ) ;
} "" ". trimIndent ( )
val vertexShader = LoadShaderUtil. loadShader ( GLES30. GL_VERTEX_SHADER, vertexShaderCode)
val fragmentShader =
LoadShaderUtil. loadShader ( GLES30. GL_FRAGMENT_SHADER, fragmentShaderCode)
mEdgeProgram = GLES30. glCreateProgram ( )
GLES30. glAttachShader ( mEdgeProgram, vertexShader)
GLES30. glAttachShader ( mEdgeProgram, fragmentShader)
GLES30. glLinkProgram ( mEdgeProgram)
GLES30. glDeleteShader ( vertexShader)
GLES30. glDeleteShader ( fragmentShader)
}
fun initPixelFilterShader ( ) {
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_3;
uniform vec2 uTextureSize;
uniform float uPixelSize;
in vec2 vTexCoord;
out vec4 fragColor;
void main ( ) {
float dx = uPixelSize / uTextureSize. x;
float dy = uPixelSize / uTextureSize. y;
vec2 pixelatedCoord;
pixelatedCoord. x = dx * floor ( vTexCoord. x / dx) + dx * 0.5 ;
pixelatedCoord. y = dy * floor ( vTexCoord. y / dy) + dy * 0.5 ;
vec4 pixelColor = texture ( uTexture_3, pixelatedCoord) ;
const float colorLevels = 5.0 ;
pixelColor = floor ( pixelColor * colorLevels) / colorLevels;
vec2 pixelPos = fract ( vTexCoord / vec2 ( dx, dy) ) ;
float borderFactor = step ( 0.95 , max ( pixelPos. x, pixelPos. y) ) ;
pixelColor. rgb *= mix ( 1.0 , 0.8 , borderFactor) ;
fragColor = pixelColor;
} "" ". trimIndent ( )
val vertexShader = LoadShaderUtil. loadShader ( GLES30. GL_VERTEX_SHADER, vertexShaderCode)
val fragmentShader =
LoadShaderUtil. loadShader ( GLES30. GL_FRAGMENT_SHADER, fragmentShaderCode)
mPixelProgram = GLES30. glCreateProgram ( )
GLES30. glAttachShader ( mPixelProgram, vertexShader)
GLES30. glAttachShader ( mPixelProgram, fragmentShader)
GLES30. glLinkProgram ( mPixelProgram)
GLES30. glDeleteShader ( vertexShader)
GLES30. glDeleteShader ( fragmentShader)
}
fun initColorFilterShader ( ) {
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_4;
uniform float uTime;
uniform float uTwistIntensity;
in vec2 vTexCoord;
out vec4 fragColor;
vec3 rgb2hsv ( vec3 c) {
vec4 K = vec4 ( 0.0 , - 1.0 / 3.0 , 2.0 / 3.0 , - 1.0 ) ;
vec4 p = mix ( vec4 ( c. bg, K. wz) , vec4 ( c. gb, K. xy) , step ( c. b, c. g) ) ;
vec4 q = mix ( vec4 ( p. xyw, c. r) , vec4 ( c. r, p. yzx) , step ( p. x, c. r) ) ;
float d = q. x - min ( q. w, q. y) ;
float e = 1.0e-10 ;
return vec3 ( abs ( q. z + ( q. w - q. y) / ( 6.0 * d + e) ) , d / ( q. x + e) , q. x) ;
}
vec3 hsv2rgb ( vec3 c) {
vec4 K = vec4 ( 1.0 , 2.0 / 3.0 , 1.0 / 3.0 , 3.0 ) ;
vec3 p = abs ( fract ( c. xxx + K. xyz) * 6.0 - K. www) ;
return c. z * mix ( K. xxx, clamp ( p - K. xxx, 0.0 , 1.0 ) , c. y) ;
}
void main ( ) {
vec2 center = vec2 ( 0.5 , 0.5 ) ;
vec2 texCoordFromCenter = vTexCoord - center;
float distance = length ( texCoordFromCenter) ;
float angle = atan ( texCoordFromCenter. y, texCoordFromCenter. x) ;
angle += uTwistIntensity * ( 1.0 - distance) ;
vec2 newCoord;
newCoord. x = center. x + distance * cos ( angle) ;
newCoord. y = center. y + distance * sin ( angle) ;
vec4 color = texture ( uTexture_4, newCoord) ;
vec3 hsv = rgb2hsv ( color. rgb) ;
hsv. y = hsv. y * 1.4 ;
hsv. z = hsv. z * 0.9 + 0.1 ;
hsv. x = hsv. x + distance * 0.5 ;
fragColor = vec4 ( hsv2rgb ( hsv) , color. a) ;
} "" ". trimIndent ( )
val vertexShader = LoadShaderUtil. loadShader ( GLES30. GL_VERTEX_SHADER, vertexShaderCode)
val fragmentShader =
LoadShaderUtil. loadShader ( GLES30. GL_FRAGMENT_SHADER, fragmentShaderCode)
mColorProgram = GLES30. glCreateProgram ( )
GLES30. glAttachShader ( mColorProgram, vertexShader)
GLES30. glAttachShader ( mColorProgram, fragmentShader)
GLES30. glLinkProgram ( mColorProgram)
GLES30. glDeleteShader ( vertexShader)
GLES30. glDeleteShader ( fragmentShader)
}
fun initEdgeFrameBuffer ( ) {
GLES30. glGenFramebuffers ( mEdgeFBO. size, mEdgeFBO, NO_OFFSET)
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, mEdgeFBO[ 0 ] )
GLES30. glGenTextures ( mEdgeFBOTextureID. size, mEdgeFBOTextureID, NO_OFFSET)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, mEdgeFBOTextureID[ 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
)
GLES30. glTexImage2D (
GLES30. GL_TEXTURE_2D,
NO_OFFSET,
GLES30. GL_RGBA,
mFrameBufferWidth,
mFrameBufferHeight,
NO_OFFSET,
GLES30. GL_RGBA,
GLES30. GL_UNSIGNED_BYTE,
null
)
GLES30. glFramebufferTexture2D (
GLES30. GL_FRAMEBUFFER,
GLES30. GL_COLOR_ATTACHMENT0,
GLES30. GL_TEXTURE_2D,
mEdgeFBOTextureID[ 0 ] ,
0
)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, 0 )
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, 0 )
}
fun initPixelFrameBuffer ( ) {
GLES30. glGenFramebuffers ( mPixelFBO. size, mPixelFBO, NO_OFFSET)
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, mPixelFBO[ 0 ] )
GLES30. glGenTextures ( mPixelFBOTextureID. size, mPixelFBOTextureID, NO_OFFSET)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, mPixelFBOTextureID[ 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
)
GLES30. glTexImage2D (
GLES30. GL_TEXTURE_2D,
NO_OFFSET,
GLES30. GL_RGBA,
mFrameBufferWidth,
mFrameBufferHeight,
NO_OFFSET,
GLES30. GL_RGBA,
GLES30. GL_UNSIGNED_BYTE,
null
)
GLES30. glFramebufferTexture2D (
GLES30. GL_FRAMEBUFFER,
GLES30. GL_COLOR_ATTACHMENT0,
GLES30. GL_TEXTURE_2D,
mPixelFBOTextureID[ 0 ] ,
0
)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, 0 )
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, 0 )
}
fun initColorFrameBuffer ( ) {
GLES30. glGenFramebuffers ( mColorFBO. size, mColorFBO, NO_OFFSET)
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, mColorFBO[ 0 ] )
GLES30. glGenTextures ( mColorFBOTextureID. size, mColorFBOTextureID, NO_OFFSET)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, mColorFBOTextureID[ 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
)
GLES30. glTexImage2D (
GLES30. GL_TEXTURE_2D,
NO_OFFSET,
GLES30. GL_RGBA,
mFrameBufferWidth,
mFrameBufferHeight,
NO_OFFSET,
GLES30. GL_RGBA,
GLES30. GL_UNSIGNED_BYTE,
null
)
GLES30. glFramebufferTexture2D (
GLES30. GL_FRAMEBUFFER,
GLES30. GL_COLOR_ATTACHMENT0,
GLES30. GL_TEXTURE_2D,
mColorFBOTextureID[ 0 ] ,
0
)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, 0 )
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, 0 )
}
fun initPingFrameBuffer ( ) {
GLES30. glGenFramebuffers ( mPingFBO. size, mPingFBO, NO_OFFSET)
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, mPingFBO[ 0 ] )
GLES30. glGenTextures ( mPingTextureID. size, mPingTextureID, NO_OFFSET)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, mPingTextureID[ 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
)
GLES30. glTexImage2D (
GLES30. GL_TEXTURE_2D,
NO_OFFSET,
GLES30. GL_RGBA,
mFrameBufferWidth,
mFrameBufferHeight,
NO_OFFSET,
GLES30. GL_RGBA,
GLES30. GL_UNSIGNED_BYTE,
null
)
GLES30. glFramebufferTexture2D (
GLES30. GL_FRAMEBUFFER,
GLES30. GL_COLOR_ATTACHMENT0,
GLES30. GL_TEXTURE_2D,
mPingTextureID[ 0 ] ,
0
)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, 0 )
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, 0 )
}
fun initPongFrameBuffer ( ) {
GLES30. glGenFramebuffers ( mPongFBO. size, mPongFBO, NO_OFFSET)
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, mPongFBO[ 0 ] )
GLES30. glGenTextures ( mPongTextureID. size, mPongTextureID, NO_OFFSET)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, mPongTextureID[ 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
)
GLES30. glTexImage2D (
GLES30. GL_TEXTURE_2D,
NO_OFFSET,
GLES30. GL_RGBA,
mFrameBufferWidth,
mFrameBufferHeight,
NO_OFFSET,
GLES30. GL_RGBA,
GLES30. GL_UNSIGNED_BYTE,
null
)
GLES30. glFramebufferTexture2D (
GLES30. GL_FRAMEBUFFER,
GLES30. GL_COLOR_ATTACHMENT0,
GLES30. GL_TEXTURE_2D,
mPongTextureID[ 0 ] ,
0
)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, 0 )
GLES30. glBindFramebuffer ( GLES30. GL_FRAMEBUFFER, 0 )
}
fun savePixelBufferBitmap ( ) : Bitmap? {
val pixelBuffer =
ByteBuffer. allocateDirect ( mFrameBufferWidth * mFrameBufferHeight * 4 )
. order ( ByteOrder. LITTLE_ENDIAN)
GLES30. glReadPixels (
0 , 0 , mFrameBufferWidth, mFrameBufferHeight,
GLES30. GL_RGBA, GLES30. GL_UNSIGNED_BYTE,
pixelBuffer
)
val bitmap = Bitmap. createBitmap (
mFrameBufferWidth,
mFrameBufferHeight,
Bitmap. Config. ARGB_8888
)
pixelBuffer. rewind ( )
bitmap. copyPixelsFromBuffer ( pixelBuffer)
return bitmap
}
fun computeMVPMatrix ( width: Int, height: Int) {
takeIf { width > height } ? . let {
mViewPortRatio = ( width * 1f ) / height
Matrix. orthoM (
mProjectionMatrix,
NO_OFFSET,
- mViewPortRatio,
mViewPortRatio,
- 1f ,
1f ,
0f ,
1f
)
} ?: run {
mViewPortRatio = ( height * 1f ) / width
Matrix. orthoM (
mProjectionMatrix,
NO_OFFSET,
- 1f ,
1f ,
- mViewPortRatio,
mViewPortRatio,
0f ,
1f
)
}
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
)
Matrix. scaleM (
mMVPMatrix,
NO_OFFSET,
1f ,
- 1f ,
1f ,
)
}
fun computeFrameBufferMVPMatrix ( ) {
takeIf { mFrameBufferWidth > mFrameBufferHeight } ? . let {
mViewPortRatio = ( mFrameBufferWidth * 1f ) / mFrameBufferHeight
Matrix. orthoM (
mProjectionMatrix,
NO_OFFSET,
- mViewPortRatio,
mViewPortRatio,
- 1f ,
1f ,
0f ,
1f
)
} ?: run {
mViewPortRatio = ( mFrameBufferHeight * 1f ) / mFrameBufferWidth
Matrix. orthoM (
mProjectionMatrix,
NO_OFFSET,
- 1f ,
1f ,
- mViewPortRatio,
mViewPortRatio,
0f ,
1f
)
}
Matrix. setLookAtM (
mViewMatrix,
NO_OFFSET,
0f ,
0f ,
1f ,
0f ,
0f ,
0f ,
0f ,
1f ,
0f
)
Matrix. multiplyMM (
mFrameBufferMVPMatrix,
NO_OFFSET,
mProjectionMatrix,
NO_OFFSET,
mViewMatrix,
NO_OFFSET
)
}
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 )
mFrameBufferWidth = max ( mFrameBufferWidth, bitmap. width)
mFrameBufferHeight = max ( mFrameBufferHeight, bitmap. height)
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" )
GLES30. glUniform1i ( textureSampleHandle, 0 )
}
fun enableTexture2 ( program: Int, id: Int) {
GLES30. glActiveTexture ( GLES30. GL_TEXTURE2)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, id)
val textureSampleHandle2 = GLES30. glGetUniformLocation ( program, "uTexture_2" )
GLES30. glUniform1i ( textureSampleHandle2, 2 )
}
fun enableTexture3 ( program: Int, id: Int) {
GLES30. glActiveTexture ( GLES30. GL_TEXTURE3)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, id)
val textureSampleHandle3 = GLES30. glGetUniformLocation ( program, "uTexture_3" )
GLES30. glUniform1i ( textureSampleHandle3, 3 )
}
fun enableTexture4 ( program: Int, id: Int) {
GLES30. glActiveTexture ( GLES30. GL_TEXTURE4)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, id)
val textureSampleHandle4 = GLES30. glGetUniformLocation ( program, "uTexture_4" )
GLES30. glUniform1i ( textureSampleHandle4, 4 )
}
fun disableTexture0 ( ) {
GLES30. glActiveTexture ( GLES30. GL_TEXTURE0)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, 0 )
}
fun disableTexture2 ( ) {
GLES30. glActiveTexture ( GLES30. GL_TEXTURE2)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, 2 )
}
fun disableTexture3 ( ) {
GLES30. glActiveTexture ( GLES30. GL_TEXTURE3)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, 3 )
}
fun disableTexture4 ( ) {
GLES30. glActiveTexture ( GLES30. GL_TEXTURE4)
GLES30. glBindTexture ( GLES30. GL_TEXTURE_2D, 4 )
}
fun initTexture0 ( context: Context, resourceId: Int) {
mTextureID[ 0 ] = loadTexture ( context, resourceId)
}
fun getEdgeFilterBitmap ( ) : Bitmap? {
return mEdgeFilterBitmap
}
fun getPixelFilterBitmap ( ) : Bitmap? {
return mPixelFilterBitmap
}
fun getColorFilterBitmap ( ) : Bitmap? {
return mColorFilterBitmap
}
fun getOriginBitmap ( ) : Bitmap? {
return mOriginBitmap
}
object LoadShaderUtil {
fun loadShader ( type: Int, source: String) : Int {
val shader = GLES30. glCreateShader ( type)
GLES30. glShaderSource ( shader, source)
GLES30. glCompileShader ( shader)
return shader
}
}
}
效果图