GPUImage是一個開源的圖像處理工具谈山,它基于OpenGL ES實(shí)現(xiàn),Git地址為:https://github.com/BradLarson/GPUImage剖效。GPUImage最大的好處是它提供了一套非常好的圖像處理架構(gòu)寺董,并且提供了各種PhotoShop中常見的濾鏡的著色器。使用者只需要通過對這些濾鏡的組合猛遍,即可實(shí)現(xiàn)非常好的濾鏡效果。安卓版也有一個GPUImage:https://github.com/CyberAgent/android-gpuimage,但是這個版本遠(yuǎn)遠(yuǎn)沒有iOS版本的強(qiáng)大功能懊烤,支持的特性也相對少很多梯醒。最近項目中需要在Android上也實(shí)現(xiàn)一個濾鏡框架,那就順便詳細(xì)研究一下GPUImage的源碼腌紧,然后自己實(shí)現(xiàn)一個安卓版啦茸习。
OpenGL ES基礎(chǔ)
OpenGL ES是基于OpenGL簡化而來的用于嵌入式系統(tǒng)的圖像處理框架,基本上所有的嵌入式系統(tǒng)的圖像渲染最終都基于OpenGL ES壁肋。OpenGL ES提供了強(qiáng)大的圖形處理能力号胚,以及完善的上下文讓系統(tǒng)能將CPU中的數(shù)據(jù)傳輸?shù)紾PU中,并且進(jìn)行渲染浸遗。GPUImage也是基于OpenGL ES實(shí)現(xiàn)的猫胁。因此,了解一些OpenGL ES的基礎(chǔ)對于理解GPUImage的源碼也是非常有幫助的跛锌。
簡單的術(shù)語:
Vertex(頂點(diǎn)):在OpenGL中弃秆,所有的物體都是由頂點(diǎn)拼湊而成的,即使是一個圓或者一個球髓帽。每個球也是通過分解成非常小的三角形進(jìn)行渲染的菠赚。OpenGL中,渲染的最小元素包括三角形(GL_TRIANGLES)氢卡,線(GL_LINES)以及點(diǎn)(GL_POINTS)锈至。因此晨缴,他們都需要由頂點(diǎn)來定義他們在坐標(biāo)系中的位置译秦;
Fragment(片元):在OpenGL中,所有的顯示都是由片元來完成的击碗,OpenGL通過著色器為每一個片元設(shè)定顏色筑悴,然后GPU通過這些片元的顏色進(jìn)行渲染。Fragment可以說是OpenGL顯示的最小單元稍途。
Texture(紋理):紋理是一個包含元素信息的對象阁吝,OpenGL通過讀取紋理中的每個紋素(Texel)的顏色來給不同的片元進(jìn)行上色。
Shader(著色器):OpenGL中包含了兩種著色器械拍,頂點(diǎn)著色器(VertexShader)以及片元著色器(FragmentShader)突勇。著色器使用的是Shading Language進(jìn)行書寫,相當(dāng)于是另一門語言了坷虑,這里就不具體介紹了甲馋,有興趣的同學(xué)可以參考https://www.khronos.org/registry/OpenGL/specs/gl/GLSLangSpec.3.30.pdf。
????VertexShader:主要作用是確定每個頂點(diǎn)在渲染坐標(biāo)系中的位置迄损,并且確定每個頂點(diǎn)的紋理位置坐標(biāo)定躏;
? ? FragmentShader:通過每個頂點(diǎn)的紋理坐標(biāo)和紋理,給每一個片元進(jìn)行上色。
坐標(biāo)系(Coordinate System):OpenGL之所以能夠很好地實(shí)現(xiàn)3D的效果痊远,就是因?yàn)橛幸粋€非常完善的坐標(biāo)系系統(tǒng)垮抗,這些坐標(biāo)系系統(tǒng)可以將一個點(diǎn)從自己的坐標(biāo)系映射到屏幕中的3D位置。坐標(biāo)系之間的變換通常通過矩陣進(jìn)行碧聪,包括Model-View-Projection矩陣冒版,簡稱MVP Matrix。
????Model Matrix是將一個點(diǎn)的位置從自己的坐標(biāo)系映射到周圍環(huán)境中(world coordinate)逞姿;
????View Matrix是將點(diǎn)的位置從世界坐標(biāo)系中壤玫,通過調(diào)整眼睛(或者說攝像頭)的位置,展示同一個物體不同方面的景象哼凯;
? ? Projection Matrix則是將點(diǎn)的位置最終轉(zhuǎn)化成在屏幕上顯示的位置欲间;
由于GPUImage中主要實(shí)現(xiàn)的是2D的圖片處理,并沒有涉及到太多的3D效果断部,因此基本沒有涉及到MVP矩陣變換猎贴。
幀緩存(FrameBuffer):我們在移動設(shè)備屏幕上看到的顯示其實(shí)都是一幀一幀的內(nèi)存。因此OpenGL使用了幀緩存的機(jī)制蝴光,現(xiàn)在緩存中完成渲染她渴,然后再將渲染好的幀呈現(xiàn)到屏幕上。其實(shí)在OpenGL中蔑祟,還有很多的Buffer趁耗,如RenderBuffer, DepthBuffer, Vertex Buffer, IndexBuffer等等,我們在使用到的時候再進(jìn)行具體介紹疆虚。
上下文(EGLContext):EGLContext是OpenGL用來渲染的一個上下文苛败,包含了很多的環(huán)境變量。在不同的系統(tǒng)中径簿,都有不同的實(shí)現(xiàn)罢屈,在iOS中,已經(jīng)封裝好的EAGLContext就非常容易使用了篇亭;而在Android中缠捌,如果需要自己控制每一個顯示的環(huán)節(jié)的話,則需要自己創(chuàng)建EGLContext译蒂。
Shader中的常用術(shù)語:
Attribute: 在Shader中曼月,有些屬性是針對每個頂點(diǎn)都不同的,比如它們的位置(position)柔昼,紋理坐標(biāo)(TextureCoordinate)哑芹,這些信息必須要在CPU中計算好,然后放入VertexBuffer或者VertexBufferObject中岳锁;GPU會在VB或者VBO中讀取到這些信息绩衷,才能計算出每個頂點(diǎn)顯示的位置蹦魔;
Uniform:不同于Attribute,uniform是對于所有的頂點(diǎn)或者片元都相同的一些參數(shù)咳燕,比如MVPMatrix勿决,Sampler以及一些其他的環(huán)境變量;
Sampler:采樣器招盲,OpenGL通過Sampler和TextureCoordinate來確定一個片元的顏色低缩。
OpenGL ES 渲染流程
1. Vertex Specification: 這個過程中,主要是計算出每個頂點(diǎn)在自己坐標(biāo)系中的位置曹货,并且將頂點(diǎn)的Attributes放置到VertexBuffer中咆繁,GPU會通過VertexBuffer中的信息讀取到每個頂點(diǎn)的Attribute并進(jìn)行處理;
2. Vertex Processing: 這個過程主要通過VertexShader以及MVP Matrix獲取到每個頂點(diǎn)的位置顶籽;
3. Primitive Assembly: 在頂點(diǎn)的信息確定完成了之后玩般,通過Primitive Assembly將這些頂點(diǎn)拼成最終需要顯示的圖形;
4. Rasterization:柵格化的過程是將圖形的立體位置轉(zhuǎn)換成在屏幕上顯示的位置的過程礼饱;
5. Fragment Processing:通過采樣器坏为,紋理坐標(biāo)給每個片元進(jìn)行著色;
6. Per-Fragment Operation:在每個片元的顏色確定了之后镊绪,還可以對每個片元進(jìn)行一些操作匀伏,比如Stencil Test,Depth Test等等蝴韭。
這邊主要是介紹了一些OpenGL ES的基礎(chǔ)够颠,以便更好的理解GPUImage的源代碼,現(xiàn)在一切就緒榄鉴,我們就可以開始擼代碼啦履磨!