Android平臺美顏相機/Camera實時濾鏡/視頻編解碼/影像後期/人臉技術探索——2.2 來一份LOMO濾鏡

Github項目地址

回到目錄

瞭解了濾鏡的基本知識以後,我們就可以試着來做我們的第一個濾鏡了

雖然之前做過一個灰度濾鏡,但是是採用直接修改片元着色器代碼的方式,非常“不優雅”,所以這次我們試着來搭一個框架,讓增加新的濾鏡變得更加容易。
由於相關代碼過多,本文只會貼出關鍵部分,其餘的請去項目中查找
省略的內容包括但不限於:

  • 類似GPU-Image的濾鏡組
  • 相關工具類

固定頂點着色器

由於大部分濾鏡都是在片元着色器當中進行,我們可以直接固定頂點着色器部分的代碼

代碼很簡單,只有頂點相關信息

attribute vec4 aPosition;
attribute vec4 aTextureCoord;
varying vec2 vTextureCoord;
void main() {
  gl_Position = aPosition;
  vTextureCoord = aTextureCoord.xy;
}

然後寫一個簡單的類包裝一下,以後我們只修改fragmentShader的濾鏡都可以繼承這個類


public class SimpleFragmentShaderFilter extends AbsFilter {

    protected GLSimpleProgram glSimpleProgram;
    protected Plain plain;

    public SimpleFragmentShaderFilter(Context context,
                                      final String fragmentShaderPath) {
        glSimpleProgram=new GLSimpleProgram(context, "filter/vsh/simple.glsl",fragmentShaderPath);
        plain=new Plain(true);
    }

    @Override
    public void init() {
        glSimpleProgram.create();
    }

    @Override
    public void onPreDrawElements() {
        super.onPreDrawElements();
        glSimpleProgram.use();
        plain.uploadTexCoordinateBuffer(glSimpleProgram.getTextureCoordinateHandle());
        plain.uploadVerticesBuffer(glSimpleProgram.getPositionHandle());
    }

    @Override
    public void destroy() {
        glSimpleProgram.onDestroy();
    }

    @Override
    public void onDrawFrame(int textureId) {
        onPreDrawElements();
        TextureUtils.bindTexture2D(textureId, GLES20.GL_TEXTURE0,glSimpleProgram.getTextureSamplerHandle(),0);
        GLES20.glViewport(0,0,surfaceWidth,surfaceHeight);
        plain.draw();
    }
}

來一份LOMO濾鏡

嚴格來說這個應該是炫影(Vignette)效果,而不是LOMO效果

/**
 * Created by Ads on 2017/1/31.
 * VignetteFilter (炫影)
 */

public class VignetteFilter extends SimpleFragmentShaderFilter {
    public VignetteFilter(Context context) {
        super(context, "filter/fsh/mx_vignette.glsl");
    }
}

類的代碼異常簡單有沒有,因爲變化的只有着色器代碼而已

美麗的濾鏡背後都是數學和藝術在支撐,但是本文暫時還不會詳細闡述每個濾鏡的原理,代碼來自某個相機app(侵刪),就直接貼出來吧

mx_vignette.glsl

precision mediump float;
uniform sampler2D sTexture;
varying vec2 vTextureCoord;
vec4 calVignette2(vec4 color, vec2 coord, float strength) {
    float distance = (coord.x - 0.5) * (coord.x - 0.5) + (coord.y - 0.5) * (coord.y - 0.5);
    float scale = distance / 0.5 * strength;
    color.r =  color.r - scale;
    color.g = color.g - scale;
    color.b = color.b - scale;
    return color;
}
vec4 calNewSaturation(vec4 color,float saturation) {
    float gray = dot(color.rgb, vec3(0.299,0.587,0.114));
    return vec4(gray + (saturation / 100.0 + 1.0) * (color.r - gray), gray + (saturation / 100.0 + 1.0) * (color.g - gray), gray + (saturation / 100.0 + 1.0) * (color.b - gray), color.a);
}
void main() {
    vec4 color = texture2D(sTexture, vTextureCoord);
    color = calVignette2(color, vTextureCoord,1.0);
    color = calNewSaturation(color, 57.0);
    gl_FragColor = color;
}

效果預覽

把剛做好的濾鏡加進濾鏡組:

filterGroup.addFilter(spherePlugin);
filterGroup.addFilter(new VignetteFilter(statusHelper.getContext()));

這裏寫圖片描述

這個濾鏡放在渲染到球體之後(如果放在前面又是另一番效果)。可以和原圖對比一下:
這裏寫圖片描述

是不是感覺不加濾鏡簡直醜爆了(雖然加了好像也好看不到哪裏去嘛)?

Github項目地址

回到目錄

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章