【Unity3D Shader】学习笔记-卷积核

简介: 上两个图就是卷积核,左侧就是简单模糊的卷积核,右侧则是高斯模糊的卷积核。针对左侧的卷积核最终结果想要保持在1的范围内,就必须去平均值。而右侧是已经计算好确保和在1的范围内(超过1之后最终效果就会很亮)。在进行纹理采样时,中间的点为当前的(u,v)坐标,周围的格子坐标就是在当前的坐标上进行偏移“N个单位”。将采样的结果乘以格子中的对应值然后相加,即可得到结果(左侧形式需要除以5)。

【Unity3D Shader】学习笔记-卷积核


前言


   在纹理采样中已经介绍了简单的模糊效果是如何制作的,本篇通过卷积核来介绍其原理,能制作的效果不仅限于下面的两种,还有更多的效果可以去搜一下。

[声明:本笔记系列文章的图片资源都源自百度图片搜索,如有问题联系我]

一、卷积核


微信图片_20220424215946.png微信图片_20220424215951.png


   上两个图就是卷积核,左侧就是简单模糊的卷积核,右侧则是高斯模糊的卷积核。针对左侧的卷积核最终结果想要保持在1的范围内,就必须去平均值。而右侧是已经计算好确保和在1的范围内(超过1之后最终效果就会很亮)。在进行纹理采样时,中间的点为当前的(u,v)坐标,周围的格子坐标就是在当前的坐标上进行偏移“N个单位”。将采样的结果乘以格子中的对应值然后相加,即可得到结果(左侧形式需要除以5)。


https://www.jianshu.com/p/8d2d93c4229b

这里说的比较详细


二、高斯模糊


微信图片_20220424220052.png


   高斯模糊就需要说到正态分布,具体的资料请百度了解,下面是二维的计算公式,其中σ(西格玛)是参数取值,(x,y)这里就可以是uv坐标。高斯模糊在很多效果制作中需要,因此可以定义成公共的函数方法,以提供不同效果快速调用。


                                      微信图片_20220424220153.png


static const float TWO_PI = 6.28319;
static const float E = 2.71828;
// 套用上面的公式
float gaussian(int x, int y, float sigma)
{
   return (1 / sqrt(TWO_PI * sigma)) * pow(E, -((x * x) + (y * y)) / (2 * sigma));
}
// uv坐标, lower和upper是模糊的格子3x3(-1,1) 5x5(-2,2), sigma外部提供
fixed3 gaussian_blur(fixed2 uv, int lower, int upper, float sigma)
{
     fixed3 col = fixed3(0,0,0);
     float kernelSum = 0;
     for (int x = lower; x <= upper; ++x)
     {
         for (int y = lower; y <= upper; ++y)
         {
             float gauss = gaussian(x, y, sigma);
             kernelSum += gauss;
             fixed2 offset = fixed2(_MainTex_TexelSize.x * x, _MainTex_TexelSize.y * y);
             col += gauss * tex2D(_MainTex, uv + offset);
          }
       }
       col /= kernelSum;
       return col;
}


  还可以使用已经计算好的卷积核算子进行,下面是某一个sigma生成的3x3卷积核。


fixed4 gaussian_blur_3v3(fixed2 uv)
{
    /*
       0.0947416 | 0.118318 | 0.0947416
       0.118318  | 0.147761 | 0.118318
       0.0947416 | 0.118318 | 0.0947416
    */
    float2 texelSize = _MainTex_TexelSize * _Blur; //模糊程度
    fixed4 color = fixed4(0,0,0,0);
    color += tex2D(_MainTex, uv + float2(-texelSize.x, -texelSize.y)) * 0.0947416;
    color += tex2D(_MainTex, uv + float2(-texelSize.x,            0)) * 0.118318;
    color += tex2D(_MainTex, uv + float2(-texelSize.x,  texelSize.y)) * 0.0947416;
    color += tex2D(_MainTex, uv + float2(           0, -texelSize.y)) * 0.118318;
    color += tex2D(_MainTex, uv + float2(           0,            0)) * 0.147761;
    color += tex2D(_MainTex, uv + float2(           0,  texelSize.y)) * 0.118318;
    color += tex2D(_MainTex, uv + float2( texelSize.x, -texelSize.y)) * 0.0947416;
    color += tex2D(_MainTex, uv + float2( texelSize.x,            0)) * 0.118318;
    color += tex2D(_MainTex, uv + float2( texelSize.x,  texelSize.y)) * 0.0947416;
    return color;
}


上图只使用了3x3的卷积核计算,还可以使用5x5或者更高,出于性能考虑越高影响越大。


三、边缘检测


https://www.cnblogs.com/ninghechuan/p/9529936.html

Sobel边缘检测


                           微信图片_20220424220442.png


fixed luminance(fixed4 color)
{
    return 0.2125 * color.r + 0.7154 * color.g + 0.0721 * color.b;
}
fixed sobel_3v3(fixed2 uv)
{
    /* -1, 0, 1,    1, 2, 1
       -2, 0, 2,    0, 0, 0,
       -1, 0, 1    -1,-2,-1 */
    float2 texelSize = _MainTex_TexelSize;
    fixed gcol = 0;
    fixed gx = 0;
    fixed gy = 0;
    gcol = luminance(tex2D(_MainTex, uv + float2(-texelSize.x, -texelSize.y)));
    gx += gcol * -1;
    gy += gcol * 1;
    gcol = luminance(tex2D(_MainTex, uv + float2(-texelSize.x,            0)));
    gx += gcol * -2;
    gcol = luminance(tex2D(_MainTex, uv + float2(-texelSize.x,  texelSize.y)));
    gx += gcol * -1;
    gy += gcol * -1;
    gcol = luminance(tex2D(_MainTex, uv + float2(           0, -texelSize.y)));
    gy += gcol * 2;
    //gcol = luminance(tex2D(_MainTex, uv + float2(           0,            0)));
    gcol = luminance(tex2D(_MainTex, uv + float2(           0,  texelSize.y)));
    gy += gcol * -2;
    gcol = luminance(tex2D(_MainTex, uv + float2( texelSize.x, -texelSize.y)));
    gx += gcol * 1;
    gy += gcol * 1;
    gcol = luminance(tex2D(_MainTex, uv + float2( texelSize.x,            0)));
    gx += gcol * 2;
    gcol = luminance(tex2D(_MainTex, uv + float2( texelSize.x,  texelSize.y)));
    gx += gcol * 1;
    gy += gcol * -1;
    return abs(gx) + abs(gy);
}
fixed4 frag (v2f i) : SV_Target
{
    fixed gv = sobel_3v3(i.uv);
    fixed4 col = tex2D(_MainTex, i.uv);
    fixed4 edge = fixed4(1,0,0,1);
    fixed4 final_col = lerp(edge, col, gv);
    return final_col;
}


相关文章
|
3月前
|
图形学 数据可视化 开发者
超实用Unity Shader Graph教程:从零开始打造令人惊叹的游戏视觉特效,让你的作品瞬间高大上,附带示例代码与详细步骤解析!
【8月更文挑战第31天】Unity Shader Graph 是 Unity 引擎中的强大工具,通过可视化编程帮助开发者轻松创建复杂且炫酷的视觉效果。本文将指导你使用 Shader Graph 实现三种效果:彩虹色渐变着色器、动态光效和水波纹效果。首先确保安装最新版 Unity 并启用 Shader Graph。创建新材质和着色器图谱后,利用节点库中的预定义节点,在编辑区连接节点定义着色器行为。
244 0
|
3月前
|
缓存 图形学
Unity3D学习笔记12——渲染纹理
Unity3D学习笔记12——渲染纹理
39 2
|
3月前
|
API C# 图形学
Unity3D学习笔记9——加载纹理
Unity3D学习笔记9——加载纹理
39 2
|
3月前
|
API 图形学 异构计算
Unity3D学习笔记7——GPU实例化(2)
Unity3D学习笔记7——GPU实例化(2)
24 2
|
3月前
|
存储 缓存 图形学
Unity3D学习笔记11——后处理
Unity3D学习笔记11——后处理
56 1
|
3月前
|
测试技术 C# 图形学
Unity3D学习笔记10——纹理数组
Unity3D学习笔记10——纹理数组
50 0
|
3月前
|
图形学 异构计算
Unity3D学习笔记8——GPU实例化(3)
Unity3D学习笔记8——GPU实例化(3)
41 0
|
3月前
|
存储 API 图形学
Unity3D学习笔记6——GPU实例化(1)
Unity3D学习笔记6——GPU实例化(1)
53 0
|
3月前
|
API 图形学 索引
Unity3D学习笔记5——创建子Mesh
Unity3D学习笔记5——创建子Mesh
28 0
|
3月前
|
API C# 图形学
Unity3D学习笔记4——创建Mesh高级接口
Unity3D学习笔记4——创建Mesh高级接口
39 0