Quantcast
Channel: CSDN博客移动开发推荐文章
Viewing all articles
Browse latest Browse all 5930

[OpenGL]从零开始写一个Android平台下的全景视频播放器——6.2 来一份LOMO滤镜~

$
0
0

Github项目地址

为了方便没有准备好梯子的同学,我把项目在CSDN上打包下载,不过不会继续更新(保留在初始版本)

回到目录

了解了滤镜的基本知识以后,我们就可以试着来做我们的第一个滤镜了

虽然之前做过一个灰度滤镜,但是是采用直接修改片元着色器代码的方式,非常“不优雅”,所以这次我们试着来搭一个框架,让增加新的滤镜变得更加容易。
由于相关代码过多,本文只会贴出关键部分,其余的请去项目中查找
省略的内容包括但不限于:

  • 类似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()));

这里写图片描述

这个滤镜放在渲染到球体之后(如果放在前面又是另一番效果)。可以和原图对比一下:
这里写图片描述

是不是感觉不加滤镜简直丑爆了(虽然加了好像也好看不到哪里去嘛)?

扩展

为什么要花这么多时间搞这种东西呢?好像还不如先加个热点,加个头控什么的。。
对于全景视频来说,滤镜的应用主要可以在直播上,交给客户端(发送方或接受方均可)来实时处理视频流,最近VR直播虚火(全景视频直播算什么VR。。),连春晚都上VR直播了,所以我们也顺应时代潮流写一个吧。

挖个坑:关于更多的滤镜、美颜、人脸检测、换脸、直播推流相关内容,可以关注我的专栏

Github项目地址
回到目录

作者:Martin20150405 发表于2017/2/9 19:31:59 原文链接
阅读:9 评论:0 查看评论

Viewing all articles
Browse latest Browse all 5930

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>