在 GPUImage 中,如果你需要加载两张图片作为输入纹理用于过渡效果,你需要自定义处理多个纹理。以下是解决方法:
步骤
1. 修改自定义滤镜类支持两张纹理
GPUImage 的默认实现只支持一张图片。你需要扩展 GPUImageFilter
,为第二张图片添加纹理支持。
更新你的 CustomTransitionFilter
类:
class CustomTransitionFilter(context: Context) : GPUImageFilter(NO_FILTER_VERTEX_SHADER, loadShaderFromAssets(context)) {
private var progressLocation: Int = 0
private var dotsLocation: Int = 0
private var centerLocation: Int = 0
private var secondTextureHandle: Int = -1
private var secondTextureLocation: Int = 0
override fun onInit() {
super.onInit()
// 获取 Uniform 参数的位置
progressLocation = GLES20.glGetUniformLocation(program, "progress")
dotsLocation = GLES20.glGetUniformLocation(program, "dots")
centerLocation = GLES20.glGetUniformLocation(program, "center")
secondTextureLocation = GLES20.glGetUniformLocation(program, "inputImageTexture2")
}
override fun onInitialized() {
super.onInitialized()
// 初始化 Uniform 参数
setProgress(0f)
setDots(20f)
setCenter(floatArrayOf(0.5f, 0.5f))
}
override fun onDrawFrame(textureId: Int, cubeBuffer: FloatBuffer, textureBuffer: FloatBuffer) {
// 激活并绑定第一个纹理
GLES20.glActiveTexture(GLES20.GL_TEXTURE0)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId)
GLES20.glUniform1i(getTextureUniformLocation(), 0)
// 激活并绑定第二个纹理
if (secondTextureHandle != -1) {
GLES20.glActiveTexture(GLES20.GL_TEXTURE1)
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, secondTextureHandle)
GLES20.glUniform1i(secondTextureLocation, 1)
}
super.onDrawFrame(textureId, cubeBuffer, textureBuffer)
}
fun setSecondTexture(secondBitmap: Bitmap) {
// 加载第二张纹理
val textures = IntArray(1)
GLES20.glGenTextures(1, textures, 0)
secondTextureHandle = textures[0]
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, secondTextureHandle)
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, secondBitmap, 0)
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR.toFloat())
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR.toFloat())
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE.toFloat())
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE.toFloat())
}
fun setProgress(progress: Float) {
setFloat(progressLocation, progress)
}
fun setDots(dots: Float) {
setFloat(dotsLocation, dots)
}
fun setCenter(center: FloatArray) {
setFloatVec2(centerLocation, center)
}
private fun loadShaderFromAssets(context: Context): String {
return context.assets.open("shaders/transition.glsl").bufferedReader().use { it.readText() }
}
}
2. 加载两张图片作为纹理
你可以在初始化时加载两张图片,并将第二张图片设置为自定义滤镜的第二纹理。
val gpuImageView = findViewById<GPUImageView>(R.id.gpuImageView)
// 初始化 GPUImage 和自定义滤镜
val gpuImage = GPUImage(this)
val customFilter = CustomTransitionFilter(this)
// 加载第一张图片
val bitmap1 = BitmapFactory.decodeResource(resources, R.drawable.image1)
gpuImage.setImage(bitmap1)
// 加载第二张图片作为纹理
val bitmap2 = BitmapFactory.decodeResource(resources, R.drawable.image2)
customFilter.setSecondTexture(bitmap2)
// 应用自定义滤镜
gpuImage.setFilter(customFilter)
// 动态更新过渡进度
val animator = ValueAnimator.ofFloat(0f, 1f).apply {
duration = 2000
addUpdateListener { animation ->
val progress = animation.animatedValue as Float
customFilter.setProgress(progress)
gpuImageView.requestRender() // 通知视图刷新
}
}
animator.start()
3. 动态过渡效果
如上代码,通过动画设置 progress
的值,完成从 bitmap1
到 bitmap2
的过渡效果。
总结
- 自定义
CustomTransitionFilter
类,添加对第二张图片纹理的支持。 - 使用
setSecondTexture()
方法加载第二张图片。 - 动态更新
progress
参数,实现过渡效果。
这种方式利用 GPUImage 的底层 OpenGL 渲染能力,同时支持自定义 GLSL 文件的动态过渡逻辑。如果有其他问题,随时告诉我!