【iOS】(一)GPUImage的結構,濾鏡鏈的實現原理
- 2020 年 3 月 31 日
- 筆記
前言
學了OpenGL,OpenGLES後,去閱讀了GPUImage的源碼,使用了一段時間,接下來,記錄一下我對GPUImage使用和源碼閱讀的一些分析吧。 相關引用 從0打造一個GPUImage(6)-GPUImage的多濾鏡處理邏輯
GPUImage結構

GPUImage目錄.png
對於GPUImage,可以分為
- GLProgram 用於加載shader,鏈接program的類
- GPUImageContext 用於OpenGLContext上下文管理的
- GPUImageFrameBuffer 用於frameBuffer的管理,GPUImage的濾鏡鏈靠的就是傳遞
GPUImageFrameBuffer - GPUImageFrameBufferCache 用於緩存frameBuffer的類,會根據texture的option屬性,已經size生成key,作為緩存
- Sources 可以理解為萬惡之源吧,所有的渲染處理,都是從這裡開始的,必須繼承GPUImageOutput
- Filter 濾鏡類 既繼承了GPUImageOutput,也遵守GPUImageInput的類,從而實現GPUImageOutput -> filter -> filter -> GPUImageInput的濾鏡鏈的關鍵
- Outputs,實現了GPUImageInput的組件,是渲染結果的終點
GPUImage的濾鏡鏈
上面也提了,所謂的GPUImage濾鏡鏈就是 GPUImageOutput -> filter -> filter -> GPUImageInput GPUImageOutput通過target數組(裏面都是實現GPUImageInput組件),組成了濾鏡鏈的關係,我們需要牢牢的記住這個濾鏡鏈的關係,這樣開發的時候,我們就知道如何Debug,如何實現我們需要的效果。那麼問題來了,為什麼GPUImage可以實現這樣的濾鏡鏈呢?
濾鏡鏈實現的原理
這裡我們先拋開GPUImage,用OpenGL ES去實現一個具有濾鏡疊加效果的Demo,這裡的Demo我是參考葉孤城的這篇文章,從0打造一個GPUImage(6)-GPUImage的多濾鏡處理邏輯
Demo需要實現的效果,是將一張圖片,先後通過疊加亮度濾鏡,飽和度濾鏡最後顯示在屏幕上。
使用GPUImage的渲染步驟
- 通過
GPUImagePicture加載圖片(這裡就是source) - source addTarget
亮度濾鏡 -
亮度濾鏡傳遞渲染結果給飽和度濾鏡 -
飽和度濾鏡傳遞給GPUImageView,GPUImageView顯示渲染結果,
使用OpenGLES的渲染步驟
那麼對應的OpenGLES,我們會怎麼做呢?首先我們需要以下東西
- 一個源,其實就是將圖片信息加載為紋理的過程,這裡對應
GPUImagePicture - 3個frameBuffer,前兩個掛載
亮度濾鏡和飽和度濾鏡的texture,通過glFramebufferTexture2D綁定texture到frameBuffer上,最後一個frameBuffer掛載的是renderBuffer用於顯示
// 綁定texture glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, brightnessTexture, 0) glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, saturationTexture, 0) // 綁定renderBuffer glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, _renderBuffer);
- 3個Program,前兩個Program用於加載
亮度濾鏡和飽和度濾鏡的frameShader文件(這裡就相當於GPUImageInput),最後一個Program加載的frameShader只需要把rgb信息從紋理中取出,然後展示就行了(這裡就相當於GPUImageView)。
從以上的步驟,我們可以總結以下結論
- 1、源總是會產生
texture開始傳遞的,這裡其實就是GPUImageOutput的職責 - 2、每個濾鏡Filter都是通過傳遞frameBuffer掛載
texture來傳遞渲染結果的(這裡的濾鏡對應一個program,一個frameBuffer) - 3、對於需要顯示的渲染結果的
GPUImageInput,例如GPUImageView,需要依賴frameBuffer掛載renderBuffer進行顯示
對於這個Demo的一個流程圖,可以參考從0打造一個GPUImage(6)-GPUImage的多濾鏡處理邏輯的一幅圖,Demo的詳細實現請看原文吧。

OpenGLES濾鏡疊加流程圖
總結
以上就是GPUImage對於濾鏡鏈的實現原理,只有你懂了OpenGL ES的渲染流程,才能徹底的明白GPUImage的濾鏡鏈的原理。所以時時刻刻記住以下關係 GPUImageOutput -> filter -> filter -> GPUImageInput 當然也可以存在多個Source,多個Input的情況,例如要給一個視頻添加水印,用GPUImageMovie用於輸出視頻紋理,用GPUImageUIElement輸出UI空間的紋理,通過一個filter進行Blend,最後用一個GPUImageView進行預覽,用GPUImageMovieWriter進行輸出,濾鏡鏈關係如下
GPUImageOutput -> filter -> filter -> GPUImageInput ↑ ↓ GPUImageOutput -----> GPUImageInput


