前言
在前面的文章里流程已經(jīng)基本講完了,這篇文章只是在前面文章的基礎(chǔ)上制作幾個(gè)濾鏡。
本文目標(biāo)
制作簡單的濾鏡款票,讓大家明白濾鏡的原理踏幻,濾鏡從代碼層面來說其實(shí)很簡單枷颊,復(fù)雜的是探索他們的具體算法,好在有很多前人已經(jīng)幫我們完成了這一步该面,我們直接使用就可以了夭苗。
正文
在寫這篇文章之前,我在網(wǎng)絡(luò)上搜了一下隔缀,發(fā)現(xiàn)已經(jīng)有很多簡單濾鏡的文章了题造,其實(shí)濾鏡代碼大同小異,只是算法不同猾瘸,所以這里僅僅實(shí)現(xiàn)幾個(gè)簡單的濾鏡以后可能會(huì)繼續(xù)添加界赔,方便大家理解,大家如果想繼續(xù)研究可以自行搜索牵触。
1.灰度圖
灰度圖有一個(gè)很著名的心理學(xué)公式
Gray = R*0.299 + G*0.587 + B*0.114
通過這個(gè)公式仔蝌,我們就可以將彩色轉(zhuǎn)成灰度圖,當(dāng)然荒吏,這個(gè)公式現(xiàn)在有很多優(yōu)化后的寫法敛惊,如果大家以后用到,可以自行搜索一下绰更。
不知道大家還記不記得瞧挤,在使用紋理的文章里,我們在寫Fragment Shader
的時(shí)候儡湾,代碼是這樣的
gl_FragColor = vec4(1.0) * texture2D(u_texture,v_texcoord);
當(dāng)時(shí)說的是vec4(1.0)
代表的是白色特恬,任何紋理的顏色*白色都是本來的顏色,其實(shí)我們要把它變成灰度圖徐钠,就是改變這個(gè)vec4(1.0)
癌刽,就是這么簡單,代碼如下。
vec4 texColor = texture2D(u_texture,v_texcoord); // 使用系統(tǒng)函數(shù)獲取圖像紋理
float gray = texColor.r * 0.299 + texColor.g * 0.587 + texColor.b * 0.114; // 套入公式
gl_FragColor = vec4(gray,gray,gray,1.0);
就這一步显拜,我們就完成了灰度圖濾鏡衡奥,它的效果如下。
2.黑白圖
黑白圖就更加簡單了远荠,有一部分人一直以為灰度圖就是黑白圖矮固,其實(shí)這是不對的,灰度圖有256種顏色譬淳,而黑白圖只有兩種档址,就是黑跟白,所以處理起來也簡單邻梆,只需要判斷一下當(dāng)前RGB的平均值守伸,如果大于128就是白色,小于則是黑色浦妄,另外需要注意的是Shader里的取值范圍是0.0~1.0尼摹。
代碼如下。
vec4 texColor = texture2D(u_texture,v_texcoord);
float avg = (texColor.r + texColor.g + texColor.b) / 3.0;
if (avg >= 0.5) { // 取值范圍是0~1
texColor = vec4(1.0);
}
else {
texColor = vec4(0.0,0.0,0.0,1.0);
}
gl_FragColor = vec4(texColor.rgb,1.0);
效果如下校辩。
3.底片效果
底片效果也很簡單窘问,就是把當(dāng)前像素點(diǎn)的RGB值分別與255之差后的值作為當(dāng)前點(diǎn)的RGB值,這個(gè)效果的代碼如下宜咒。
vec4 texColor = texture2D(u_texture,v_texcoord);
gl_FragColor = vec4(1.0 - texColor.r,1.0 - texColor.g,1.0 - texColor.b, 1.0);
效果如下惠赫。
4.連環(huán)畫效果
連環(huán)畫具體算法如下圖。
代碼如下故黑。
vec4 texColor = texture2D(u_texture,v_texcoord);
float r = abs(texColor.g - texColor.b + texColor.g + texColor.r) * texColor.r / 1.0;
float g = abs(texColor.b - texColor.g + texColor.b + texColor.r) * texColor.r / 1.0;
float b = abs(texColor.b - texColor.g + texColor.b + texColor.r) * texColor.g / 1.0;
float gray = r * 0.299 + g * 0.587 + b * 0.114;
gl_FragColor = vec4(gray, gray, gray, 1.0);
效果如下儿咱。
5.復(fù)古圖
復(fù)古圖算法如下圖。
代碼如下场晶。
vec4 texColor = texture2D(u_texture,v_texcoord);
float r = 0.393 * texColor.r + 0.769 * texColor.g + 0.189 * texColor.b;
float g = 0.349 * texColor.r + 0.686 * texColor.g + 0.168 * texColor.b;
float b = 0.272 * texColor.r + 0.534 * texColor.g + 0.131 * texColor.b;
gl_FragColor = vec4(r, g, b, 1.0);
效果如下混埠。
6.馬賽克
最后再來一個(gè)阻止人類進(jìn)步的最大障礙——馬賽克。記得以前還老有朋友問我是不是在搞計(jì)算機(jī)诗轻,我說是啊钳宪,然后排名第一的問題就是電腦怎么著了讓我修修,第二的問題就是能不能給他去了馬賽克扳炬,當(dāng)然其實(shí)我很想幫朋友們?nèi)サ暨@些讓我進(jìn)步的阻礙(大霧)吏颖,但是事實(shí)上就是,知道它的原理你就會(huì)明白恨樟,這個(gè)很難實(shí)現(xiàn)半醉,因?yàn)樗菙?shù)據(jù)丟失不是壓縮當(dāng)然有人說他瞇著眼睛看能達(dá)到心中無碼的狀態(tài)我也無fuck說。
通常情況下劝术,馬賽克的實(shí)現(xiàn)有兩種缩多。
第一種是把圖片相當(dāng)大小的一塊區(qū)域當(dāng)做一個(gè)小塊呆奕,然后計(jì)算這個(gè)小塊內(nèi)部的平均值,再把計(jì)算后的結(jié)果給這個(gè)小塊里的每一個(gè)像素衬吆。
第二種是在小塊內(nèi)隨機(jī)取一個(gè)像素梁钾,把這個(gè)像素賦值給小塊里的每一個(gè)像素。
這里是用的第二種方法實(shí)現(xiàn)的咆槽,取的是小塊中心的像素陈轿,在這里添加了兩個(gè)屬性圈纺,分別是texSize
和mosaicSize
秦忿,其他不變,代碼如下蛾娶。
const vec2 texSize = vec2(512.0, 512.0); // 紋理的大小
const vec2 mosaicSize = vec2(8.0, 8.0); // 小塊元素個(gè)數(shù)
void main()
{
vec2 xy = vec2(v_texcoord.x * texSize.x, v_texcoord.y * texSize.y);// 取值范圍換算到圖像尺寸大小
vec2 XYMosaic = vec2(floor(xy.x / mosaicSize.x) * mosaicSize.x, floor(xy.y / mosaicSize.y) * mosaicSize.y); // 計(jì)算某一個(gè)小mosaic的中心坐標(biāo)
vec2 UVMosaic = vec2(XYMosaic.x / texSize.x, XYMosaic.y / texSize.y); // 換算回紋理坐標(biāo)系
gl_FragColor = texture2D(u_texture, UVMosaic);
}
效果如下灯谣。
果然是阻止人類進(jìn)步的存在,一旦使用了這個(gè)效果蛔琅,相片馬上變得不可描述起來胎许。
結(jié)束
其實(shí)大家了解這幾個(gè)濾鏡之后,就會(huì)發(fā)現(xiàn)從代碼層面來講罗售,濾鏡都不是很復(fù)雜辜窑,在知道算法的前提下,我們很容易的就可以寫出具體的濾鏡寨躁。主要還是前面文章里的流程跟基礎(chǔ)穆碎,大家在練習(xí)的過程中可以從網(wǎng)絡(luò)上搜集一些具體的算法自己動(dòng)手看看效果。