美文网首页UnityShader
十六、利用GLSL实现动态滤镜

十六、利用GLSL实现动态滤镜

作者: 夏天的枫_ | 来源:发表于2020-08-16 19:33 被阅读0次

    工程是在另一文:[利用GLSL实现分屏滤镜] 基础上增加滤镜功能;核心是在着色器程序的编写。

    先来喵一波


    喵之滤镜

    缩放滤镜
    缩小放大是通过改变顶点坐标和纹理坐标的对应关系来实现缩放,纹理坐标不变,对顶点坐标进行一定程度的缩小放大。定义一个动画循环,让它的顶点坐标在1-1.2倍间放大,反复循环。

    //在顶点着色程序中
    
    attribute vec4 att_position;
    attribute vec2 att_textuteCoords;
    varying vec2 var_textureCoords;
    // 由代码传入的时间戳,记录动画
    uniform float Time;
    
    const float PI = 3.141592654;
    
    void main()
    {
        // 动画总时长
        float duration = 0.4;
        // 最大幅度
        float maxAmplitude = 0.2;
        // 动画时间间隔
        float timeInterval = mod(Time,duration);
        // 利用余弦[-1,1]的编号,对其取绝对值则就是[0,1]的变化,则整个幅度变量就是在1~1.2之间缩放
        float amplitude = 1.0 + maxAmplitude * abs(sin(timeInterval * (PI / duration)));
        // 将计算好的x,y坐标赋值给顶点坐标的内建变量,zw无需变化
        gl_Position = vec4(att_position.x * amplitude , att_position.y * amplitude, att_position.zw);
        var_textureCoords = att_textuteCoords;
    }
    

    灵魂出窍滤镜
    灵魂出窍滤镜的实现可以通过两个图层的叠加,使得处于上层的图层随着时间的衰减让其透明度不断降低,该过程中同时让其放大。

    precision highp float;
    uniform sampler2D un_texture;
    varying vec2 var_textureCoords;
    
    uniform float Time;
    
    void main()
    {
    
        float duration = 0.7;
        // 最大的透明度,不断降低至0
        float maxAlpha = 0.4;
        // 图层被放大的最大比例
        float maxScale = 1.8;
        // 定义一个进度来记录动画
        float progress = mod(Time , duration) / duration;
        float curAlpha = maxAlpha * (1.0 - progress);
        // 根据进度的快慢来描述当前纹理的尺寸
        float size = 1.0 + (maxScale - 1.0) * progress;
        // 被放大的纹理坐标x,y
        float zoomInTextureX = 0.5 + (var_textureCoords.x - 0.5) / size;
        float zoomInTextureY = 0.5 + (var_textureCoords.y - 0.5) / size;
        // 放大后纹理坐标
        vec2 zoomInTextureCoord = vec2(zoomInTextureX,zoomInTextureY);
        // 被放大后纹理颜色值
        vec4 zoomInTextureCoordColor = texture2D(un_texture,zoomInTextureCoord);
        // 原始的纹理颜色值
        vec4 originTextureCoordColor = texture2D(un_texture,var_textureCoords);
        // 将不断变化的颜色值赋值给内建变量片元颜色值
        gl_FragColor = originTextureCoordColor * (1.0 - curAlpha) + zoomInTextureCoordColor * curAlpha ;
        
    }
    

    抖动滤镜
    抖动滤镜的实现是通过图层的放大,并对其颜色值加之一定的偏移实现的。

    
    precision highp float;
    
    uniform sampler2D un_texture;
    varying vec2 var_textureCoords;
    
    uniform float Time;
    
    
    void main()
    {
        float duration = 0.4;
        // 颜色偏移量
        float offset = 0.02;
        // 放大最多1.5倍
        float maxSize = 1.5;
        
        float progress = mod(Time,duration);
        // 颜色偏移值  0~0.02
        vec2 offsetCoord = vec2(offset,offset) * progress;
        // 尺寸在1~1.5
        float size = 1.0 + (maxSize - 1.0) * progress;
        // 放大后的纹理坐标
        vec2 sizeTextureCoord = vec2(0.5, 0.5) + (var_textureCoords - vec2(0.5,0.5)) / size;
        // 定义三组纹素
        // 原始颜色 (red) + 颜色偏移值
        vec4 colorTexelR = texture2D(un_texture, sizeTextureCoord + offsetCoord);
        // 原始颜色 (green) + 颜色偏移值    
        vec4 colorTexelG = texture2D(un_texture, sizeTextureCoord - offsetCoord);
            // 原始颜色 
        vec4 colorTexel = texture2D(un_texture, sizeTextureCoord);
        // 取出三组颜色填充到片元颜色值,
        gl_FragColor = vec4(colorTexelR.r , colorTexelG.g, colorTexel.b, colorTexel.a);
     
    }
    

    闪白滤镜
    闪白滤镜的实现通过添加一个白色图层,并且让其透明度伴随时间变化。

    
    precision highp float;
    uniform sampler2D un_texture;
    varying vec2 var_textureCoords;
    
    uniform float Time;
    
    const float PI = 3.141593653589793;
    
    void main()
    {
        // 一次滤镜的动效时长
        float duration = 0.4;
        // 0~0.4间
        float timeInterval = mod(Time,duration);
        // 定义一个白色遮罩
        vec4 whiteMask = vec4(1.0,1.0,1.0,1.0);
        // 振幅,0.0~1.0
        float amplitude = abs(sin(timeInterval * ( PI / duration)));
        // 获取纹理坐标的颜色值
        vec4 texelColor = texture2D(un_texture,var_textureCoords);
        //利⽤混合⽅程式: 将纹理颜⾊与⽩⾊遮罩融合. 注意: ⽩⾊遮罩的透明度会随着时间变化做调整 。利用当前的透明度来计算最终的颜⾊值即可。
        gl_FragColor = (1.0 - amplitude) * texelColor + amplitude * whiteMask;
        
    }
    

    毛刺滤镜
    毛刺滤镜的实现可以让每一行的像素产生一个随机偏移,使得其纹理坐标在-1,1的随机变化。是否随机偏移,判断随机偏移量是否超过一个阈值,如果小于,就将其与一个缩小系数相乘,这样就实现了两层把控,图层并不是每一行像素都发生撕裂以及颜色偏移。

    
    precision highp float;
    uniform sampler2D un_texture;
    varying vec2 var_textureCoords;
    
    uniform float Time;
    
    const float PI = 3.141592653589793;
    // 产生一个随机数
    float rand(float n){
        // fract(x) - 返回x的小数部分
        return fract(sin(n) * 38989.128938897);
    }
    
    void main()
    {
        // 最大抖动
        float maxJitter = 0.06;
        // 毛刺滤镜时长
        float duration = 0.3;
        // 红色偏移
        float colorR_Offset = 0.01;
        // 绿色偏移
        float colorB_Offset = -0.025;
        //将传⼊的时间转换到⼀个周期内,  0 ~ 0.06
        float time = mod(Time , duration * 2.0);
        float amplitude = max(sin(time * (PI/duration)),0.0);
        // 像素随机范围 -1~1
        float jitter = rand(var_textureCoords.y) * 2.0 - 1.0;
        // 判断是否需要偏移,如果jitter范围< 最⼤抖动*振幅,为ture
        bool needOffset = abs(jitter) < maxJitter * amplitude;
        //获取纹理x 坐标,根据needOffset,来计算它的X撕裂,如果是needOffset = yes 则撕裂⼤;如果 needOffset = no 则撕裂⼩;
        float textureX = var_textureCoords.x + (needOffset ? jitter : (jitter * amplitude * 0.006));
        // 纹理撕裂后的x,y坐标
        vec2 textureCoords = vec2(textureX, var_textureCoords.y);
        // 纹素偏移
        vec4 texel = texture2D(un_texture, textureCoords);
        vec4 texelR = texture2D(un_texture, textureCoords + vec2(colorR_Offset * amplitude, 0.0));
        vec4 texelB = texture2D(un_texture, textureCoords + vec2(colorB_Offset * amplitude, 0.0));
        
      
        gl_FragColor = vec4(texelR.r, texel.g, texelR.b, texel.a);
        
    }
    

    眩晕滤镜
    眩晕滤镜的实现可以通过残影和颜色偏移的叠加。
    残影的效果: 是在移动的过程中,每经过⼀段时间间隔,根据当前的位置去创建⼀个新层,并且新层的不透明度随着时间逐
    渐减弱。于是在⼀个移动周期内,可以看到很多透明度不同的层叠加在⼀起,从⽽形成残影的效果。残影,让图⽚随着时间
    做圆周运动
    颜⾊偏移: 物体移动的过程是蓝⾊在前⾯,红⾊在后⾯。所以整个过程可以理解成:在移动的过程中,每间隔⼀段时间,遗
    失了⼀部分红⾊通道的值在原来的位置,并且这部分红⾊通道的值,随着时间偏移,会逐渐恢复

    
    precision highp float;
    uniform sampler2D un_texture;
    varying vec2 var_textureCoords;
    
    
    uniform float Time;
    
    const float PI = 3.141592653589793;
    
    const float duration = 2.0;
    //    在每一个时间间隔后获得一个新的层
    vec4 getTexelLevel(float time, vec2 textureCoords, float padding){
       // 圆周坐标
       vec2 translation = vec2(sin(time * (PI * 2.0 / duration)));
       // 新的纹理坐标 = 旧纹理坐标 + 偏移量 * 圆周坐标,
       vec2 translationTextureCoord = textureCoords + padding * translation;
       // 返回一个新的图层坐标
       return texture2D(un_texture, translationTextureCoord);
       
    }
    // 获取某个时刻图层的当前的透明度
    float levelAlphaProgress(float curTime, float hideTime ,float startTime){
       // 前一个时间
       float beforeTime = duration + curTime - startTime;
       // 对时间取模
       float laterTime = mod(beforeTime, duration);
       // 返回最小的时间,作为当前图层的透明度
       return min(laterTime, beforeTime);
       
    }
    
    void main()
    {
       //  一个时间周期,0~2.0
       float timeInterval = mod(Time,duration);
       // 放大倍数
       float zoomSize = 1.3;
       // 偏移量
       float padding = 0.5 * (1.0 - 1.0 / zoomSize);
       // 放大后的纹理坐标
       vec2 textureCoords = vec2(0.5,0.5) + (var_textureCoords - vec2(0.5,0.5)) / zoomSize;
      // 隐藏时间
       float hideTime = 0.9;
       // 时间间隔
       float timeGap = 0.2;
       // 实现的效果是残留红色
       float maxAlphaR = 0.5;
       float maxAlphaG = 0.05;
       float maxAlphaB = 0.06;
       // 获得一个新的图层坐标
       vec4 texelLevel = getTexelLevel(timeInterval,textureCoords,padding);
       float alphaR = 1.0;
       float alphaG = 1.0;
       float alphaB = 1.0;
       // 最终的图层颜色
       vec4 lastLevel = vec4(0,0,0,0);
       // 开启循环,不断的衰减透明度
       for(float f = 0.0; f < duration; f += timeGap){
           
           float tmpTime = f;
          //获取到0-2.0秒内所获取的运动后的纹理坐标
           vec4 tmpLevel = getTexelLevel(tmpTime,textureCoords,padding);
           //某个时刻创建的层,在当前时刻的红绿蓝的透明度
           float tmpAlphaR = maxAlphaR - maxAlphaR * levelAlphaProgress(timeInterval,hideTime,tmpTime)/hideTime;
           float tmpAlphaG = maxAlphaG - maxAlphaG * levelAlphaProgress(timeInterval,hideTime,tmpTime)/hideTime;
           float tmpAlphaB = maxAlphaB - maxAlphaB * levelAlphaProgress(timeInterval,hideTime,tmpTime)/hideTime;
         //累积每⼀层每个通道乘以透明度颜⾊通道
           lastLevel  = lastLevel + vec4(tmpLevel.r * tmpAlphaR,tmpLevel.g * tmpAlphaG,tmpLevel.b * tmpAlphaB,1.0);
           // 透明度不断衰减
           alphaR = alphaR - tmpAlphaR;
           alphaG = alphaG - tmpAlphaG;
           alphaB = alphaB - tmpAlphaB;
           
           
       }
       // 计算最终颜色 
       lastLevel = lastLevel + vec4(texelLevel.r * alphaR,texelLevel.g * alphaG,texelLevel.b * alphaB,1.0);
       gl_FragColor = lastLevel;
       
    }
    

    相关文章

      网友评论

        本文标题:十六、利用GLSL实现动态滤镜

        本文链接:https://www.haomeiwen.com/subject/omlndktx.html