【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