• 记一次干扰后处理特效的实现


    最近策划希望给游戏中的视频增加一个类似抖音的滤镜特效,如下所示:

    可以看到,有条纹状和点状的干扰信息时不时出现在视频中。
    我在网络上找了一下,还真的没有找到有人实现过这个滤镜的shader,因此只能靠我自己分析滤镜内容来反向推shader了。
    首先我们可以发现,在这个特效中,干扰的效果都是呈现为方块的形状:

    于是我想到可以将图片分割为一块一块的,具体的做法就是在frag shader里处理每个像素时,给它的uv坐标乘以一个倍数,并取其整数部分,利用它们来进行计算,判断该像素是否产生干扰:

    float intx = floor(texcoord.x * 40.0);
    float inty = floor(texcoord.y * 35.0);
    
    float t = fmod(time, 5.0);
    float line_disturb = sin(frac(inty * t + t * 4.5));
    line_disturb *= step(max(0.8405, saturate(sign(sin(time)))),  line_disturb);
    
    float dot_disturb = sin(intx * intx * inty * t * 0.01);
    dot_disturb = sign(dot_disturb * step(max(0.999995, saturate(sign(sin(time)))) , dot_disturb) * 0.5);
    	
    float disturb = max(line_disturb, dot_disturb);
    texcoord = float2(fmod(texcoord.x + disturb * 0.2, 1.0), fmod(texcoord.y + disturb * 0.2, 1.0));
    

    其中line_disturb决定了线段干扰的程度(图中干扰整行的部分),由inty决定;dot_disturb决定了格子干扰的程度,由intx和inty共同决定,并加入时间因素t,引入一些随机性。
    在上述代码的最后一行,如果disturb为0,那么我们认为这个像素不需要干扰,那么只需正常地根据texcoord的值采样图片即可。若disturb大于0,那么我们会对该像素采样的位置引入一定偏移,产生干扰的效果。
    经过以上修改后,效果如下:

    可以看到产生了干扰效果,但是干扰的部分只是简单采样了图片内容,颜色本身没有变化。
    接下来,我参考这篇文章给扰动的部分加了一个如下图的抖音特效:

    代码如下所示:

    diffuse = DiffuseTexture.Sample(DiffuseTexture_Sampler, texcoord);
    float3 shift_color1 = DiffuseTexture.Sample(DiffuseTexture_Sampler, float2(texcoord.x + 0.01, texcoord.y + 0.01));
    float3 shift_color2 = DiffuseTexture.Sample(DiffuseTexture_Sampler, float2(texcoord.x - 0.01, texcoord.y - 0.01));
    
    float3 blend_first_color = float3(diffuse.r, diffuse.g, shift_color1.b);
    float3 blend_3d_color = float3(shift_color2.r, blend_first_color.g, blend_first_color.b);
    float sign_disturb = sign(disturb);
    diffuse.rgb = sign_disturb * blend_3d_color + (1.0 - sign_disturb) * diffuse.rgb;
    

    相当于是加以适当偏移采样了三次图片,然后将三次采样的颜色混合起来。若disturb为0则用正常采样的颜色diffuse,反之则用混合后的颜色。
    加上颜色变换后,效果如下:

    可以看到扰动的部分颜色明显有变化了。
    完整frag shader的(伪)代码如下,去掉了一些不相干的代码:

    float4 UIShowDrawPS(in VertexOutput IN) : SV_Target
    {
          float4 diffuse;
    
          float2 texcoord = IN.TexCoord.xy;
          float disturb = 0.0;
    	
          float intx = floor(texcoord.x * 40.0);
          float inty = floor(texcoord.y * 35.0);
    
          float t = fmod(time, 5.0);
          float line_disturb = sin(frac(inty * t + t * 4.5));
          line_disturb *= step(max(0.8405, saturate(sign(sin(time)))),  line_disturb);
    
          float dot_disturb = sin(intx * intx * inty * t * 0.01);
          dot_disturb = sign(dot_disturb * step(max(0.999995, saturate(sign(sin(time)))) , dot_disturb) * 0.5);
    	
          disturb = max(line_disturb, dot_disturb);
          texcoord = float2(fmod(texcoord.x + disturb * 0.2, 1.0), fmod(texcoord.y + disturb * 0.2, 1.0));
    
          diffuse = DiffuseTexture.Sample(DiffuseTexture_Sampler, texcoord);
          float3 shift_color1 = DiffuseTexture.Sample(DiffuseTexture_Sampler, float2(texcoord.x + 0.01, texcoord.y + 0.01));
          float3 shift_color2 = DiffuseTexture.Sample(DiffuseTexture_Sampler, float2(texcoord.x - 0.01, texcoord.y - 0.01));
    
          float3 blend_first_color = float3(diffuse.r, diffuse.g, shift_color1.b);
          float3 blend_3d_color = float3(shift_color2.r, blend_first_color.g, blend_first_color.b);
          float sign_disturb = sign(disturb);
          diffuse.rgb = sign_disturb * blend_3d_color + (1.0 - sign_disturb) * diffuse.rgb;
    
          diffuse *= IN.Color.a;
          return diffuse;
    }
    
  • 相关阅读:
    自动封箱和拆箱
    关于Java的一道内存的题目
    volatile关键字
    阶乘尾零
    Java之final的解析
    从1到n整数中1出现的次数
    最小安装雷达数量
    二叉树重建
    最短路径—Dijkstra算法
    PAT A1063——set的常见用法详解
  • 原文地址:https://www.cnblogs.com/wickedpriest/p/13481357.html
Copyright © 2020-2023  润新知