zoukankan      html  css  js  c++  java
  • OpenGL 12.2

    最终实现滤镜效果:

    详细Demo文章见底部

    一、缩放

    1)实现思路:修改顶点坐标和纹理坐标的对应关系。纹理坐标不变的情况下,对顶点坐标进行放大.

    缩放过程:

    1、设置一次缩放效果的时长 duration 0.6

    2、设置最大振幅 maxAmplitude 0.3 --> 放大程度 [1 ~ 1.3]

    3、将时间控制在 缩放时长的范围内变动 --> 通过mod(Time, duration),计算当前时间Time 所处在[0 ~ 0.6]的时间位置 time

    4、计算当前振幅 amplitude --> 通过 sin() 函数 --> sin()值的范围是[-1 ~ 1],取绝对值得范围 [0 ~ 1] --> maxAmplitude *abs( sin(time*(PI/duration))) -->

    例:当前时间 time = 0.3, sin(0.3*PI/0.6) = sin(PI/2) = 1, amplitude = 0.3*1 = 0.3

    5、对顶点坐标的 x, y 进行放大

    2)顶点着色器代码

     1 attribute vec4 Position;// 顶点坐标
     2 attribute vec2 TextureCoords;// 纹理坐标
     3 varying vec2 TextureCoordsVarying;// 纹理坐标 传入片元着色器
     4 
     5 uniform float Time;// 传入的时间戳
     6 
     7 const float PI = 3.1415926;
     8 
     9 void main (void) {
    10     
    11     // 一次缩放的效果时长
    12     float duration = 0.6;
    13     // 最大发达幅度 - 振幅
    14     float maxAmplitude = 0.3;
    15     // 传入的时间周期控制在 0~0.6,  mod 求模: mod(0.9,0.6)=0.3 
    16     float time = mod(Time, duration);
    17     // 求振幅 - sin值范围-1~1, abs(sin())范围0~1,* 0.3 即所要范围 0~0.3
    18     float amplitude = 1.0 + maxAmplitude * abs(sin(time * (PI / duration)));
    19     // 将顶点坐标的 x, y 分别乘放大系数,纹理坐标不变
    20     gl_Position = vec4(Position.x * amplitude, Position.y * amplitude, Position.zw);
    21 
    22     TextureCoordsVarying = TextureCoords;
    23 }

    二、灵魂出窍

    1)实现思路:两个图层叠加,使上面那层图层随时间推移放大,并降低不透明度。通过片元着色器完成。

    --> 图层的放大原理:顶点坐标不变,纹理坐标取值时向中心位置偏差

    缩放消失过程

    坐标变换,不同位置时:

     

    1、设置每次动画时长 duration 0.7,范围 [0 ~ 0.7];

    最大透明度 maxAlpha 0.4;

    最大放大比例 maxScale 1.8;

    2、当前放大的进度 progress = mod(Time, duration) / duration -->  0~0.7  / 0.7 ==> 0 ~ 1

    3、设置当前的透明度 alpha = maxAlpha * (1.0 - progress) --> 0~0.4

    4、计算缩放倍数 scale = 1.0 + (maxScale - 1.0) * progress --> 1.0 + 0.8 *[0~1] --> 1~1.8

    5、上面图层的缩放处理, x,y值 同理: 0.5 + (TextureCoordsVarying.x - 0.5) / scale --> 原理如上图 --> 得到缩放后的纹理坐标

    6、拿到原纹理坐标 和 缩放后纹理坐标对应的纹素:texture2D()

    7、两个图层进行混合 混合方程式:mask * (1 - alpha) + weakMask * alpha --> OpenGL 颜色混合

    2)片元着色器代码

     1 precision highp float;
     2 
     3 uniform sampler2D Texture;
     4 varying vec2 TextureCoordsVarying;
     5 
     6 uniform float Time;
     7 
     8 void main (void) {
     9     float duration = 0.7;// 一次动效时长
    10     float maxAlpha = 0.4;// 最大透明度
    11     float maxScale = 1.8;// 缩放最大系数
    12     
    13     float progress = mod(Time, duration) / duration;// mod(Time, duration):0~0.7 --> 0~1
    14     float alpha = maxAlpha * (1.0 - progress);// 计算透明度
    15     float scale = 1.0 + (maxScale - 1.0) * progress;// 计算缩放倍数
    16     
    17     float weakX = 0.5 + (TextureCoordsVarying.x - 0.5) / scale;// 纹理坐标值缩放
    18     float weakY = 0.5 + (TextureCoordsVarying.y - 0.5) / scale;
    19     vec2 weakTextureCoords = vec2(weakX, weakY);// 缩放后纹理坐标
    20     // 缩放后纹理坐标对应的纹素
    21     vec4 weakMask = texture2D(Texture, weakTextureCoords);
    22     // 原纹理坐标对应纹素
    23     vec4 mask = texture2D(Texture, TextureCoordsVarying);
    24     // 混合2个图层 
    25     gl_FragColor = mask * (1.0 - alpha) + weakMask * alpha;// mix
    26 }

    三、抖动

    1)实现原理:颜色偏移 + 放大效果

    1、放大原理同 “二、灵魂出窍”

    2、纹理左边偏移也同理:

    3、对 红蓝 RB 两个颜色值进行偏移:maskR = texture2D(Texture, ScaleTextureCoords + offsetCoords);

    2)片段着色器代码

     1 precision highp float;
     2 
     3 uniform sampler2D Texture;
     4 varying vec2 TextureCoordsVarying;
     5 
     6 uniform float Time;
     7 
     8 void main (void) {
     9     float duration = 0.7;
    10     float maxScale = 1.1;
    11     float offset = 0.02;
    12     
    13     float progress = mod(Time, duration) / duration; // 0~1
    14     vec2 offsetCoords = vec2(offset, offset) * progress;// 偏移量
    15     float scale = 1.0 + (maxScale - 1.0) * progress;// 缩放
    16     
    17     vec2 ScaleTextureCoords = vec2(0.5, 0.5) + (TextureCoordsVarying - vec2(0.5, 0.5)) / scale;// 纹理坐标缩放 - 向量的加减 例:向量 AB, A+B=(Ax+Bx, Ay+By)
    18     
    19     vec4 maskR = texture2D(Texture, ScaleTextureCoords + offsetCoords);// red
    20     vec4 maskB = texture2D(Texture, ScaleTextureCoords - offsetCoords);// blue
    21     vec4 mask = texture2D(Texture, ScaleTextureCoords);// 原纹素
    22     
    23     gl_FragColor = vec4(maskR.r, mask.g, maskB.b, mask.a);// RGB 中 RB 取b偏移后的值
    24 }

    四、闪白

    1)实现原理:添加一层透明度变化的白色图层进行混合

    1、动画效果时长 0.6

    2、白色图层透明度范围 0 ~ 1

    2)片元着色器代码

     1 precision highp float;
     2 
     3 uniform sampler2D Texture;
     4 varying vec2 TextureCoordsVarying;
     5 
     6 uniform float Time;
     7 
     8 const float PI = 3.1415926;
     9 
    10 void main (void) {
    11     float duration = 0.6;// 动画时长
    12     
    13     float time = mod(Time, duration);// 当前时间 0 ~ 0.6
    14     
    15     vec4 whiteMask = vec4(1.0, 1.0, 1.0, 1.0);// 白色图层
    16     float amplitude = abs(sin(time * (PI / duration)));// 透明度
    17     // 纹理坐标对应纹素
    18     vec4 mask = texture2D(Texture, TextureCoordsVarying);
    19     // mix
    20     gl_FragColor = mask * (1.0 - amplitude) + whiteMask * amplitude;
    21 }

    五、毛刺 - 噪声效果

    1)实现原理:撕裂(x方向) + 颜色偏移

    1、设置最大抖动值 maxJitter 0.06

    一次滤镜动画时长 duration 0.3

    颜色偏移colorROffset 0.01; colorBOffset -0.025

    2、振幅 amplitude [1.0 ~ 1.3] 

    3、偏移随机值 jitter [-1 ~ 1]

    4、判断是否要偏移 jitter < maxJitter * amplitude

    5、偏移纹理坐标的 X: x + jitter

    6、设置颜色偏移

    2)片元着色器代码

     1 precision highp float;
     2 
     3 uniform sampler2D Texture;
     4 varying vec2 TextureCoordsVarying;
     5 
     6 uniform float Time;
     7 
     8 const float PI = 3.1415926;
     9 
    10 // 获取一个随机值
    11 float rand(float n) {
    12     return fract(sin(n) * 43758.5453123);
    13 }
    14 
    15 void main (void) {
    16     float maxJitter = 0.06;// 最大抖动
    17     float duration = 0.3;// 一次动画时长
    18     float colorROffset = 0.01;// 红色偏移
    19     float colorBOffset = -0.025;// 蓝色偏移
    20     
    21     float time = mod(Time, duration * 2.0);// 时间周期 0 ~ 0.6
    22     float amplitude = max(sin(time * (PI / duration)), 0.0);// 振幅
    23     
    24     float 0 = rand(TextureCoordsVarying.y) * 2.0 - 1.0; // 向所偏移随机值 -1 ~ 1
    25     bool needOffset = abs(jitter) < maxJitter * amplitude;// 是否需要偏移 --> yes:撕裂大  no:撕裂小
    26     
    27     float textureX = TextureCoordsVarying.x + (needOffset ? jitter : (jitter * amplitude * 0.006));// 纹理坐标的 X 撕裂
    28     
    29     // 撕裂后纹理坐标
    30     vec2 textureCoords = vec2(textureX, TextureCoordsVarying.y);
    31     
    32     // 颜色偏移
    33     vec4 mask = texture2D(Texture, textureCoords);// 
    34     vec4 maskR = texture2D(Texture, textureCoords + vec2(colorROffset * amplitude, 0.0));
    35     vec4 maskB = texture2D(Texture, textureCoords + vec2(colorBOffset * amplitude, 0.0));
    36     
    37     // 颜色 RB 
    38     gl_FragColor = vec4(maskR.r, mask.g, maskB.b, mask.a);
    39 }

    六、幻觉 - 综合

    1)实现原理:残影效果 + 颜色偏移

    这里:

    残影效果:在移动的过程中,每经过⼀段时间间隔,根据当前的位置去创建一个新图层,并且新层的不透明度随着时间逐渐减弱。于是在⼀个移动周期内,可以看到很多透明度不同的图层叠加在一起,从⽽形成残影的效果。残影,让图⽚随着时间做圆周运动。

    颜色偏移:物体移动的过程是蓝色在前面,红⾊在后。整个过程可以理解成:在移动的过程中,每间隔一段时间,遗失了一部分红色通道的值在原来的位置,并且这部分红⾊通道的值,随着时间偏移,会逐渐恢复。

    2)片元着色器代码

     1 precision highp float;
     2 
     3 uniform sampler2D Texture;
     4 varying vec2 TextureCoordsVarying;
     5 
     6 uniform float Time;
     7 
     8 const float PI = 3.1415926;
     9 const float duration = 2.0;
    10 
    11 // 自定义函数 - 计算在某个时刻图片的具体位置,通过它可以每经过一个时间段,生层一个新的图层
    12 vec4 getMask(float time, vec2 textureCoords, float padding) {
    13    // 圆周坐标
    14     vec2 translation = vec2(sin(time * (PI * 2.0 / duration)),
    15                             cos(time * (PI * 2.0 / duration)));
    16     // 纹理坐标 = 纹理坐标 + 偏移量 * 圆周坐标
    17     vec2 translationTextureCoords = textureCoords + padding * translation;
    18     // 新图层的坐标
    19     vec4 mask = texture2D(Texture, translationTextureCoords);
    20     
    21     return mask;
    22 }
    23 
    24 // 计算某个时刻创建的层在当前的 透明度
    25 float maskAlphaProgress(float currentTime, float hideTime, float startTime) {
    26     float time = mod(duration + currentTime - startTime, duration);
    27     return min(time, hideTime);
    28 }
    29 
    30 void main (void) {
    31 
    32     float time = mod(Time, duration);// 时间 [0 ~ 2.0]
    33     float scale = 1.2;// 放大倍数 1.2
    34     float padding = 0.5 * (1.0 - 1.0 / scale);// 偏移量
    35     vec2 textureCoords = vec2(0.5, 0.5) + (TextureCoordsVarying - vec2(0.5, 0.5)) / scale;// 放大后的纹理坐标
    36     
    37     float hideTime = 0.9;// 隐藏时间
    38     float timeGap = 0.2;// 时间间隔
    39     
    40     // 只保留了红色的透明通道值,我们这里设置幻影效果红色,可设其他色值
    41     // 新图层的最大 RGB
    42     float maxAlphaR = 0.5; // max R
    43     float maxAlphaG = 0.05; // max G
    44     float maxAlphaB = 0.05; // max B
    45 
    46     // 获得新的图层坐标
    47     vec4 mask = getMask(time, textureCoords, padding);
    48     float alphaR = 1.0; // R
    49     float alphaG = 1.0; // G
    50     float alphaB = 1.0; // B
    51 
    52     // 最终图层颜色
    53     vec4 resultMask = vec4(0, 0, 0, 0);
    54     
    55     // 循环 多个图层
    56     for (float f = 0.0; f < duration; f += timeGap) {
    57 
    58         float tmpTime = f;
    59         // 获取 0 ~ 2 秒内的, 运动后的 纹理坐标
    60         vec4 tmpMask = getMask(tmpTime, textureCoords, padding);
    61         
    62         // 某时刻创建的层,在当前的 RGB 透明度
    63         float tmpAlphaR = maxAlphaR - maxAlphaR * maskAlphaProgress(time, hideTime, tmpTime) / hideTime;
    64         float tmpAlphaG = maxAlphaG - maxAlphaG * maskAlphaProgress(time, hideTime, tmpTime) / hideTime;
    65         float tmpAlphaB = maxAlphaB - maxAlphaB * maskAlphaProgress(time, hideTime, tmpTime) / hideTime;
    66 
    67         // 积累每一层 的 每个通道 乘以 透明度颜色值 
    68         resultMask += vec4(tmpMask.r * tmpAlphaR,
    69                            tmpMask.g * tmpAlphaG,
    70                            tmpMask.b * tmpAlphaB,
    71                            1.0);
    72         // 透明度递减
    73         alphaR -= tmpAlphaR;
    74         alphaG -= tmpAlphaG;
    75         alphaB -= tmpAlphaB;
    76     }
    77 
    78     // 最终颜色 += 红绿蓝 * 透明度
    79     resultMask += vec4(mask.r * alphaR, mask.g * alphaG, mask.b * alphaB, 1.0);
    80     // 填充到像素点
    81     gl_FragColor = resultMask;
    82 }     

    Demo地址

  • 相关阅读:
    DROP,TRUNCATE 和DELETE的区别
    工作手记之Cransoft
    Java输入输出流
    上海植物园
    eclipse中开发android程序时,打开layout配置文件eclipse关闭
    Android SDK 2.2 开发环境搭建
    Android读取电话薄中的电话号码
    Android模拟器大小
    工作手记之Cransoft(二)
    工作手记之Cransoft(三)
  • 原文地址:https://www.cnblogs.com/zhangzhang-y/p/13516339.html
Copyright © 2011-2022 走看看