GPUImage是一個開源的圖像處理工具,它基于OpenGL ES實現(xiàn),Git地址為:https://github.com/BradLarson/GPUImage。GPUImage最大的好處是它提供了一套非常好的圖像處理架構(gòu),并且提供了各種PhotoShop中常見的濾鏡的著色器。使用者只需要通過對這些濾鏡的組合,即可實現(xiàn)非常好的濾鏡效果。安卓版也有一個GPUImage:https://github.com/CyberAgent/android-gpuimage,但是這個版本遠遠沒有iOS版本的強大功能,支持的特性也相對少很多。最近項目中需要在Android上也實現(xiàn)一個濾鏡框架,那就順便詳細研究一下GPUImage的源碼,然后自己實現(xiàn)一個安卓版啦。
OpenGL ES基礎(chǔ)
OpenGL ES是基于OpenGL簡化而來的用于嵌入式系統(tǒng)的圖像處理框架,基本上所有的嵌入式系統(tǒng)的圖像渲染最終都基于OpenGL ES。OpenGL ES提供了強大的圖形處理能力,以及完善的上下文讓系統(tǒng)能將CPU中的數(shù)據(jù)傳輸?shù)紾PU中,并且進行渲染。GPUImage也是基于OpenGL ES實現(xiàn)的。因此,了解一些OpenGL ES的基礎(chǔ)對于理解GPUImage的源碼也是非常有幫助的。
簡單的術(shù)語:
Vertex(頂點):在OpenGL中,所有的物體都是由頂點拼湊而成的,即使是一個圓或者一個球。每個球也是通過分解成非常小的三角形進行渲染的。OpenGL中,渲染的最小元素包括三角形(GL_TRIANGLES),線(GL_LINES)以及點(GL_POINTS)。因此,他們都需要由頂點來定義他們在坐標系中的位置;
Fragment(片元):在OpenGL中,所有的顯示都是由片元來完成的,OpenGL通過著色器為每一個片元設(shè)定顏色,然后GPU通過這些片元的顏色進行渲染。Fragment可以說是OpenGL顯示的最小單元。
Texture(紋理):紋理是一個包含元素信息的對象,OpenGL通過讀取紋理中的每個紋素(Texel)的顏色來給不同的片元進行上色。
Shader(著色器):OpenGL中包含了兩種著色器,頂點著色器(VertexShader)以及片元著色器(FragmentShader)。著色器使用的是Shading Language進行書寫,相當于是另一門語言了,這里就不具體介紹了,有興趣的同學可以參考https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.3.30.pdf。
????VertexShader:主要作用是確定每個頂點在渲染坐標系中的位置,并且確定每個頂點的紋理位置坐標;
? ? FragmentShader:通過每個頂點的紋理坐標和紋理,給每一個片元進行上色。
坐標系(Coordinate System):OpenGL之所以能夠很好地實現(xiàn)3D的效果,就是因為有一個非常完善的坐標系系統(tǒng),這些坐標系系統(tǒng)可以將一個點從自己的坐標系映射到屏幕中的3D位置。坐標系之間的變換通常通過矩陣進行,包括Model-View-Projection矩陣,簡稱MVP Matrix。
????Model Matrix是將一個點的位置從自己的坐標系映射到周圍環(huán)境中(world coordinate);
????View Matrix是將點的位置從世界坐標系中,通過調(diào)整眼睛(或者說攝像頭)的位置,展示同一個物體不同方面的景象;
? ? Projection Matrix則是將點的位置最終轉(zhuǎn)化成在屏幕上顯示的位置;
由于GPUImage中主要實現(xiàn)的是2D的圖片處理,并沒有涉及到太多的3D效果,因此基本沒有涉及到MVP矩陣變換。
幀緩存(FrameBuffer):我們在移動設(shè)備屏幕上看到的顯示其實都是一幀一幀的內(nèi)存。因此OpenGL使用了幀緩存的機制,現(xiàn)在緩存中完成渲染,然后再將渲染好的幀呈現(xiàn)到屏幕上。其實在OpenGL中,還有很多的Buffer,如RenderBuffer, DepthBuffer, Vertex Buffer, IndexBuffer等等,我們在使用到的時候再進行具體介紹。
上下文(EGLContext):EGLContext是OpenGL用來渲染的一個上下文,包含了很多的環(huán)境變量。在不同的系統(tǒng)中,都有不同的實現(xiàn),在iOS中,已經(jīng)封裝好的EAGLContext就非常容易使用了;而在Android中,如果需要自己控制每一個顯示的環(huán)節(jié)的話,則需要自己創(chuàng)建EGLContext。
Shader中的常用術(shù)語:
Attribute: 在Shader中,有些屬性是針對每個頂點都不同的,比如它們的位置(position),紋理坐標(TextureCoordinate),這些信息必須要在CPU中計算好,然后放入VertexBuffer或者VertexBufferObject中;GPU會在VB或者VBO中讀取到這些信息,才能計算出每個頂點顯示的位置;
Uniform:不同于Attribute,uniform是對于所有的頂點或者片元都相同的一些參數(shù),比如MVPMatrix,Sampler以及一些其他的環(huán)境變量;
Sampler:采樣器,OpenGL通過Sampler和TextureCoordinate來確定一個片元的顏色。
OpenGL ES 渲染流程
1. Vertex Specification: 這個過程中,主要是計算出每個頂點在自己坐標系中的位置,并且將頂點的Attributes放置到VertexBuffer中,GPU會通過VertexBuffer中的信息讀取到每個頂點的Attribute并進行處理;
2. Vertex Processing: 這個過程主要通過VertexShader以及MVP Matrix獲取到每個頂點的位置;
3. Primitive Assembly: 在頂點的信息確定完成了之后,通過Primitive Assembly將這些頂點拼成最終需要顯示的圖形;
4. Rasterization:柵格化的過程是將圖形的立體位置轉(zhuǎn)換成在屏幕上顯示的位置的過程;
5. Fragment Processing:通過采樣器,紋理坐標給每個片元進行著色;
6. Per-Fragment Operation:在每個片元的顏色確定了之后,還可以對每個片元進行一些操作,比如Stencil Test,Depth Test等等。
這邊主要是介紹了一些OpenGL ES的基礎(chǔ),以便更好的理解GPUImage的源代碼,現(xiàn)在一切就緒,我們就可以開始擼代碼啦!