首页 > 其他分享 >【Unity3D】高斯模糊特效

【Unity3D】高斯模糊特效

时间:2023-08-10 21:24:45浏览次数:49  
标签:Unity3D uv MainTex 特效 卷积 模糊 buffer0 高斯

1 高斯模糊原理

边缘检测特效中使用了卷积运算进行了边缘检测,本文实现的高斯模糊特效同样使用了卷积运算,关于卷积核和卷积运算的概念,读者可以参考边缘检测特效

​ 本文完整资源见→Unity3D高斯模糊特效

​ 我们将用于模糊处理的卷积核称为模糊算子,它一般满足以下条件:

  • 卷积核中权值上下对称、左右对称;
  • 卷积核中每个权值大于或等于 0,小于 1;
  • 卷积核中所有权值之和为 1。

​ 我们将所有权值都为 1 / n(n 为权值个数)的卷积核称为平均模糊算子;将权值随位置变化且符合高斯分布(或正太分布)的卷积核称为高斯模糊算子(或高斯核),它较好地模拟了邻域中每个像素对当前处理像素的影响程度(距离越近,影响越大)。高斯方程如下:

img

​ σ 是标准差,其值越大,高斯分布函数的图像越矮胖,一般取值为 1,x、y 为当前位置到卷积核中心的整数距离。要构建一个高斯核,我们只需要计算高斯核中各个位置对应的高斯值。为了保证模糊处理后的图像不会变暗,我们需要对高斯核中的元素进行归一化,即将所有元素都除以它们的权值和,从而保证归一化后的权值和为 1。因此,高斯函数中 e 前面的系数不会对高斯核产生任何影响,在计算高斯核的过程中可以省去。

​ 高斯核的维数越高,模糊程度越大。使用一个 n * n 的卷积核,需要进行 n * n * w * h 次纹理采样(w、h 分别为图像的宽高),为节省性能,我们将二维高斯核拆分为 2 个一维高斯核,采样次数只需要 2 * n * w * h 次。进一步观察到,2 个高斯核中包含了很多重复权重。对于一个大小为 5 的一维高斯核,实际只需记录 3 个权值即可。

img

2 代码实现

​ GaussianBlur.cs

using UnityEngine;

[ExecuteInEditMode] // 编辑态可以查看脚本运行效果
[RequireComponent(typeof(Camera))] // 需要相机组件
public class GaussianBlur : MonoBehaviour {
    [Range(0, 4)]
    public int iterations = 3; // 高斯模糊迭代次数
    [Range(0.2f, 3.0f)]
    public float blurSpread = 0.6f; // 每次迭代纹理坐标偏移的速度
    [Range(1, 8)]
    public int downSample = 2; // 降采样比率
    private Material material = null; // 材质

    private void Start() {
        material = new Material(Shader.Find("MyShader/GaussianBlur"));
        material.hideFlags = HideFlags.DontSave;
    }

    void OnRenderImage(RenderTexture src, RenderTexture dest) {
        if (material != null) {
            int rtW = src.width / downSample; // 降采样的纹理宽度
            int rtH = src.height / downSample; // 降采样的纹理高度
            RenderTexture buffer0 = RenderTexture.GetTemporary(rtW, rtH, 0);
            buffer0.filterMode = FilterMode.Bilinear; // 滤波模式设置为双线性
            Graphics.Blit(src, buffer0);
            for (int i = 0; i < iterations; i++) {
                material.SetFloat("_BlurSize", 1.0f + i * blurSpread); // 设置模糊尺寸(纹理坐标的偏移量)
                RenderTexture buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
                Graphics.Blit(buffer0, buffer1, material, 0); // 渲染垂直的Pass
                RenderTexture.ReleaseTemporary(buffer0);
                buffer0 = buffer1;
                buffer1 = RenderTexture.GetTemporary(rtW, rtH, 0);
                Graphics.Blit(buffer0, buffer1, material, 1); // 渲染水平的Pass
                RenderTexture.ReleaseTemporary(buffer0);
                buffer0 = buffer1;
            }
            Graphics.Blit(buffer0, dest);
            RenderTexture.ReleaseTemporary(buffer0);
        } else {
            Graphics.Blit(src, dest);
        }
    }
}

​ GaussianBlur.shader

Shader "MyShader/GaussianBlur" { // 高斯模糊
    Properties {
        _MainTex ("Base (RGB)", 2D) = "white" {} // 主纹理
        _BlurSize ("Blur Size", Float) = 1.0 // 模糊尺寸(纹理坐标的偏移量)
    }

    SubShader {
        CGINCLUDE
        
        #include "UnityCG.cginc"
        
        sampler2D _MainTex; // 主纹理
        half4 _MainTex_TexelSize; // _MainTex的像素尺寸大小, float4(1/width, 1/height, width, height)
        float _BlurSize; // 模糊尺寸(纹理坐标的偏移量)
          
        struct v2f {
            float4 pos : SV_POSITION; // 模型空间顶点坐标
            half2 uv[5]: TEXCOORD0; // 5个邻域的纹理坐标
        };
          
        v2f vertBlurVertical(appdata_img v) { // 垂直模糊顶点着色器
            v2f o;
            o.pos = UnityObjectToClipPos(v.vertex); // 模型空间顶点坐标变换到裁剪空间, 等价于: mul(UNITY_MATRIX_MVP, v.vertex)
            half2 uv = v.texcoord;
            o.uv[0] = uv;
            o.uv[1] = uv + float2(0.0, _MainTex_TexelSize.y * 1.0) * _BlurSize;
            o.uv[2] = uv - float2(0.0, _MainTex_TexelSize.y * 1.0) * _BlurSize;
            o.uv[3] = uv + float2(0.0, _MainTex_TexelSize.y * 2.0) * _BlurSize;
            o.uv[4] = uv - float2(0.0, _MainTex_TexelSize.y * 2.0) * _BlurSize;      
            return o;
        }
        
        v2f vertBlurHorizontal(appdata_img v) { // 水平模糊顶点着色器
            v2f o;
            o.pos = UnityObjectToClipPos(v.vertex); // 模型空间顶点坐标变换到裁剪空间, 等价于: mul(UNITY_MATRIX_MVP, v.vertex)
            half2 uv = v.texcoord;
            o.uv[0] = uv;
            o.uv[1] = uv + float2(_MainTex_TexelSize.x * 1.0, 0.0) * _BlurSize;
            o.uv[2] = uv - float2(_MainTex_TexelSize.x * 1.0, 0.0) * _BlurSize;
            o.uv[3] = uv + float2(_MainTex_TexelSize.x * 2.0, 0.0) * _BlurSize;
            o.uv[4] = uv - float2(_MainTex_TexelSize.x * 2.0, 0.0) * _BlurSize;      
            return o;
        }

        fixed4 fragBlur(v2f i) : SV_Target {
            float weight[3] = {0.4026, 0.2442, 0.0545}; // 大小为5的一维高斯核,实际只需记录3个权值
            fixed3 sum = tex2D(_MainTex, i.uv[0]).rgb * weight[0];
            for (int j = 1; j < 3; j++) {
                sum += tex2D(_MainTex, i.uv[j * 2 - 1]).rgb * weight[j]; // 中心右侧或下侧的纹理*权值
                sum += tex2D(_MainTex, i.uv[j * 2]).rgb * weight[j]; // 中心左侧或上侧的纹理*权值
            }
            return fixed4(sum, 1.0);
        }
            
        ENDCG
        
        ZTest Always Cull Off ZWrite Off
        
        Pass {
            NAME "GAUSSIAN_BLUR_VERTICAL"
            
            CGPROGRAM
              
            #pragma vertex vertBlurVertical  
            #pragma fragment fragBlur
              
            ENDCG  
        }
        
        Pass {  
            NAME "GAUSSIAN_BLUR_HORIZONTAL"
            
            CGPROGRAM  
            
            #pragma vertex vertBlurHorizontal  
            #pragma fragment fragBlur
            
            ENDCG
        }
    }

    FallBack "Diffuse"
}

3 运行效果

1)原图

img

2)模糊处理

​ 调整模糊迭代次数 iterations 由 0 ~ 4 变化,效果如下:

img

​ 声明:本文转自【Unity3D】高斯模糊特效

标签:Unity3D,uv,MainTex,特效,卷积,模糊,buffer0,高斯
From: https://www.cnblogs.com/zhyan8/p/17615598.html

相关文章

  • 【Unity3D】边缘检测特效
    1边缘检测原理​边缘检测的原理是:检测每个像素周围的像素亮度差,如果亮度差异较大,就将该像素识别为边缘,并进行边缘着色。​本文完整资源见→Unity3D边缘检测特效。​使用过卷积神经网络(CNN)的人,一定知道卷积运算,笔者之前有写过相关文章(使用CNN实现MNIST数据集分类、......
  • 五百个炫酷文字特效——预设的使用
    需要安装Birdge新建一个文件动画-浏览预设进入到text就是本文特效特别多的动画想使用的话,直接拖动就好了就能做出这样的效果了调一下颜色可以出现这种高端的效果了这里面的效果很多,可以多试一试输出到渲染序列或Me也可以导入到PR里面......
  • 【Unity3D】广告牌特效
    1前言​广告牌特效是指:空间中的一个2D对象始终(或尽可能)面向相机,使得用户能够尽可能看清楚该2D物体。广告牌特效一共有以下3种:正视广告牌:广告牌始终以正视图姿态面向相机,即广告牌的x、y、z轴正方向始终指向相机的x、y、z轴正方向;血条广告牌:游戏中的血条效果广告......
  • 【Unity3D】调整屏幕亮度、饱和度、对比度
    1屏幕后处理流程​调整屏幕亮度、饱和度、对比度,需要使用到屏幕后处理技术。因此,本文将先介绍屏幕后处理流程,再介绍调整屏幕亮度、饱和度、对比度的实现。​本文完整资源见→Unity3D调整屏幕亮度、饱和度、对比度。​屏幕后处理即:渲染完所有对象后,得到一张屏幕图......
  • 高效控制轨道——折叠栅格化特效开
    第一个是折叠按钮我们在发现层太多了,我们不想看到他我们把需要的层先锁定起来,然后选中没用的层然后点上面的总控开关要注意,这里的层没有消失,只是让我们折叠起来了当我们把导入的东西放大后,会出现像素点但是我们选中栅格化后就变得清晰,也就是第二个按钮后面的哪个就......
  • JS中BOM事件,JS样式特效,表格对象和表单操作
    DOM事件1.DOM中的事件可以分为两类1.浏览器行为如:文档加载完成,图片加载完成2.用户行为如:输入框输入数据,点击按钮(2).常见的DOM事件onload浏览器已完成页面的加载支持事件的对象windowimageonchangeHTML元素改变onclick用户点击HTML元素o......
  • 异常检测——无监督、高斯分布模型,需要带标记的样本数据,基本假设:特征符合高斯分布
    给定数据集x(1),x(2),..,x(m),我们假使数据集是正常的,我们希望知道新的数据xtest是不是异常的,即这个测试数据不属于该组数据的几率如何。我们所构建的模型应该能根据该测试数据的位置告诉我们其属于一组数据的可能性p(x)。......
  • jQuery 自学笔记—10 常见特效 (终章)
    隐藏、显示、切换,滑动,淡入淡出,以及动画效果演示点击这里,隐藏/显示面板一寸光阴一寸金,因此,我们为您提供快捷易懂的学习内容。在这里,您可以通过一种易懂的便利的模式获得您需要的任何知识。实例jQueryhide()演示一个简单的jQueryhide()方法。jQueryhid......
  • GOM GEE引擎默认盛大衣服翅膀特效设置办法
     GOM引擎GEE引擎,默认盛大衣服翅膀特效,比如雷霆,火龙这些装备的翅膀特效。这种装备的特效如果你的客户端够新,就可以直接在DBC里改,我们打开DBC,找到你要改的衣服,再找到Anicount这段,这里就是设置默认有服翅膀的,比如3,3就是火龙翅膀,再比如1,1就是雷霆翅膀,改成0就是无特效,大家可以去试下。......
  • After Effects 2023 - 视频特效和动画制作软件mac/win版
    AfterEffects2023是一款功能强大的视频合成和特效制作软件,它被广泛用于电影、电视、广告和网络视频等领域。在这800字的介绍中,我将向您详细说明AfterEffects2023的特点、功能和优势。点击获取AfterEffects2023 首先,AfterEffects2023提供了一个直观而强大的界面,使......