屏幕高斯模糊(Gaussian Blur)后期特效的实现

本文介绍了一个Unity中的实时模糊效果实现方案,通过自定义着色器和脚本来控制模糊程度、迭代次数等参数,实现了高效的屏幕特效。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

转自: http://www.manew.com/thread-91560-1-1.html

效果图:
这里写图片描述

将下面脚步挂载到相机下面
RapidBlurEffect .cs

//设置在编辑模式下也执行该脚本

using UnityEngine;

[ExecuteInEditMode]
//添加选项到菜单中
[AddComponentMenu("Learning Unity Shader/Lecture 15/RapidBlurEffect")]
public class RapidBlurEffect : MonoBehaviour
{
    //-------------------变量声明部分-------------------
    #region Variables

    //指定Shader名称
    private string ShaderName = "Learning Unity Shader/Lecture 15/RapidBlurEffect";

    //着色器和材质实例
    public Shader CurShader;
    private Material CurMaterial;

    //几个用于调节参数的中间变量
    public static int ChangeValue;
    public static float ChangeValue2;
    public static int ChangeValue3;

    //降采样次数
    [Range(0, 6), Tooltip("[降采样次数]向下采样的次数。此值越大,则采样间隔越大,需要处理的像素点越少,运行速度越快。")]
    public int DownSampleNum = 2;
    //模糊扩散度
    [Range(0.0f, 20.0f), Tooltip("[模糊扩散度]进行高斯模糊时,相邻像素点的间隔。此值越大相邻像素间隔越远,图像越模糊。但过大的值会导致失真。")]
    public float BlurSpreadSize = 3.0f;
    //迭代次数
    [Range(0, 8), Tooltip("[迭代次数]此值越大,则模糊操作的迭代次数越多,模糊效果越好,但消耗越大。")]
    public int BlurIterations = 3;

    #endregion

    //-------------------------材质的get&set----------------------------
    #region MaterialGetAndSet
    Material material
    {
        get
        {
            if (CurMaterial == null)
            {
                CurMaterial = new Material(CurShader);
                CurMaterial.hideFlags = HideFlags.HideAndDontSave;
            }
            return CurMaterial;
        }
    }
    #endregion

    #region Functions
    //-----------------------------------------【Start()函数】--------------------------------------------- 
    // 说明:此函数仅在Update函数第一次被调用前被调用
    //--------------------------------------------------------------------------------------------------------
    void Start()
    {
        //依次赋值
        ChangeValue = DownSampleNum;
        ChangeValue2 = BlurSpreadSize;
        ChangeValue3 = BlurIterations;

        //找到当前的Shader文件
        CurShader = Shader.Find(ShaderName);

        //判断当前设备是否支持屏幕特效
        if (!SystemInfo.supportsImageEffects)
        {
            enabled = false;
            return;
        }
    }

    //-------------------------------------【OnRenderImage()函数】------------------------------------ 
    // 说明:此函数在当完成所有渲染图片后被调用,用来渲染图片后期效果
    //--------------------------------------------------------------------------------------------------------
    public void OnRenderImage(RenderTexture sourceTexture, RenderTexture destTexture)
    {
        //着色器实例不为空,就进行参数设置
        if (CurShader != null)
        {
            //【0】参数准备
            //根据向下采样的次数确定宽度系数。用于控制降采样后相邻像素的间隔
            float widthMod = 1.0f / (1.0f * (1 << DownSampleNum));
            //Shader的降采样参数赋值
            material.SetFloat("_DownSampleValue", BlurSpreadSize * widthMod);
            //设置渲染模式:双线性
            sourceTexture.filterMode = FilterMode.Bilinear;
            //通过右移,准备长、宽参数值
            int renderWidth = sourceTexture.width >> DownSampleNum;
            int renderHeight = sourceTexture.height >> DownSampleNum;

            // 【1】处理Shader的通道0,用于降采样 ||Pass 0,for down sample
            //准备一个缓存renderBuffer,用于准备存放最终数据
            RenderTexture renderBuffer = RenderTexture.GetTemporary(renderWidth, renderHeight, 0, sourceTexture.format);
            //设置渲染模式:双线性
            renderBuffer.filterMode = FilterMode.Bilinear;
            //拷贝sourceTexture中的渲染数据到renderBuffer,并仅绘制指定的pass0的纹理数据
            Graphics.Blit(sourceTexture, renderBuffer, material, 0);

            //【2】根据BlurIterations(迭代次数),来进行指定次数的迭代操作
            for (int i = 0; i < BlurIterations; i++)
            {
                //【2.1】Shader参数赋值
                //迭代偏移量参数
                float iterationOffs = (i * 1.0f);
                //Shader的降采样参数赋值
                material.SetFloat("_DownSampleValue", BlurSpreadSize * widthMod + iterationOffs);

                // 【2.2】处理Shader的通道1,垂直方向模糊处理 || Pass1,for vertical blur
                // 定义一个临时渲染的缓存tempBuffer
                RenderTexture tempBuffer = RenderTexture.GetTemporary(renderWidth, renderHeight, 0, sourceTexture.format);
                // 拷贝renderBuffer中的渲染数据到tempBuffer,并仅绘制指定的pass1的纹理数据
                Graphics.Blit(renderBuffer, tempBuffer, material, 1);
                //  清空renderBuffer
                RenderTexture.ReleaseTemporary(renderBuffer);
                // 将tempBuffer赋给renderBuffer,此时renderBuffer里面pass0和pass1的数据已经准备好
                renderBuffer = tempBuffer;

                // 【2.3】处理Shader的通道2,竖直方向模糊处理 || Pass2,for horizontal blur
                // 获取临时渲染纹理
                tempBuffer = RenderTexture.GetTemporary(renderWidth, renderHeight, 0, sourceTexture.format);
                // 拷贝renderBuffer中的渲染数据到tempBuffer,并仅绘制指定的pass2的纹理数据
                Graphics.Blit(renderBuffer, tempBuffer, CurMaterial, 2);

                //【2.4】得到pass0、pass1和pass2的数据都已经准备好的renderBuffer
                // 再次清空renderBuffer
                RenderTexture.ReleaseTemporary(renderBuffer);
                // 再次将tempBuffer赋给renderBuffer,此时renderBuffer里面pass0、pass1和pass2的数据都已经准备好
                renderBuffer = tempBuffer;
            }

            //拷贝最终的renderBuffer到目标纹理,并绘制所有通道的纹理到屏幕
            Graphics.Blit(renderBuffer, destTexture);
            //清空renderBuffer
            RenderTexture.ReleaseTemporary(renderBuffer);

        }

        //着色器实例为空,直接拷贝屏幕上的效果。此情况下是没有实现屏幕特效的
        else
        {
            //直接拷贝源纹理到目标渲染纹理
            Graphics.Blit(sourceTexture, destTexture);
        }
    }


    //-----------------------------------------【OnValidate()函数】-------------------------------------- 
    // 说明:此函数在编辑器中该脚本的某个值发生了改变后被调用
    //--------------------------------------------------------------------------------------------------------
    void OnValidate()
    {
        //将编辑器中的值赋值回来,确保在编辑器中值的改变立刻让结果生效
        ChangeValue = DownSampleNum;
        ChangeValue2 = BlurSpreadSize;
        ChangeValue3 = BlurIterations;
    }

    //-----------------------------------------【Update()函数】-------------------------------------- 
    // 说明:此函数每帧都会被调用
    //--------------------------------------------------------------------------------------------------------
    void Update()
    {
        //若程序在运行,进行赋值
        if (Application.isPlaying)
        {
            //赋值
            DownSampleNum = ChangeValue;
            BlurSpreadSize = ChangeValue2;
            BlurIterations = ChangeValue3;
        }
        //若程序没有在运行,去寻找对应的Shader文件
#if UNITY_EDITOR
        if (Application.isPlaying != true)
        {
            CurShader = Shader.Find(ShaderName);
        }
#endif

    }

    //-----------------------------------------【OnDisable()函数】--------------------------------------- 
    // 说明:当对象变为不可用或非激活状态时此函数便被调用 
    //--------------------------------------------------------------------------------------------------------
    void OnDisable()
    {
        if (CurMaterial)
        {
            //立即销毁材质实例
            DestroyImmediate(CurMaterial);
        }

    }

    #endregion

}

RapidBlurEffect.shader

Shader "Learning Unity Shader/Lecture 15/RapidBlurEffect"
{
    //-----------------------------------【属性 || Properties】------------------------------------------    
    Properties
    {
        //主纹理  
        _MainTex("Base (RGB)", 2D) = "white" {}
    }

        //----------------------------------【子着色器 || SubShader】---------------------------------------    
        SubShader
    {
        ZWrite Off
        Blend Off

        //---------------------------------------【通道0 || Pass 0】------------------------------------  
        //通道0:降采样通道 ||Pass 0: Down Sample Pass  
        Pass
    {
        ZTest Off
        Cull Off

        CGPROGRAM

        //指定此通道的顶点着色器为vert_DownSmpl  
#pragma vertex vert_DownSmpl  
        //指定此通道的像素着色器为frag_DownSmpl  
#pragma fragment frag_DownSmpl  

        ENDCG

    }

        //---------------------------------------【通道1 || Pass 1】------------------------------------  
        //通道1:垂直方向模糊处理通道 ||Pass 1: Vertical Pass  
        Pass
    {
        ZTest Always
        Cull Off

        CGPROGRAM

        //指定此通道的顶点着色器为vert_BlurVertical  
#pragma vertex vert_BlurVertical  
        //指定此通道的像素着色器为frag_Blur  
#pragma fragment frag_Blur  

        ENDCG
    }

        //---------------------------------------【通道2 || Pass 2】------------------------------------  
        //通道2:水平方向模糊处理通道 ||Pass 2: Horizontal Pass  
        Pass
    {
        ZTest Always
        Cull Off

        CGPROGRAM

        //指定此通道的顶点着色器为vert_BlurHorizontal  
#pragma vertex vert_BlurHorizontal  
        //指定此通道的像素着色器为frag_Blur  
#pragma fragment frag_Blur  

        ENDCG
    }
    }


        //-------------------------CG着色语言声明部分 || Begin CG Include Part----------------------    
        CGINCLUDE

        //【1】头文件包含 || include  
#include "UnityCG.cginc"  

        //【2】变量声明 || Variable Declaration  
        sampler2D _MainTex;
    //UnityCG.cginc中内置的变量,纹理中的单像素尺寸|| it is the size of a texel of the texture  
    uniform half4 _MainTex_TexelSize;
    //C#脚本控制的变量 || Parameter  
    uniform half _DownSampleValue;

    //【3】顶点输入结构体 || Vertex Input Struct  
    struct VertexInput
    {
        //顶点位置坐标  
        float4 vertex : POSITION;
        //一级纹理坐标  
        half2 texcoord : TEXCOORD0;
    };

    //【4】降采样输出结构体 || Vertex Input Struct  
    struct VertexOutput_DownSmpl
    {
        //像素位置坐标  
        float4 pos : SV_POSITION;
        //一级纹理坐标(右上)  
        half2 uv20 : TEXCOORD0;
        //二级纹理坐标(左下)  
        half2 uv21 : TEXCOORD1;
        //三级纹理坐标(右下)  
        half2 uv22 : TEXCOORD2;
        //四级纹理坐标(左上)  
        half2 uv23 : TEXCOORD3;
    };


    //【5】准备高斯模糊权重矩阵参数7x4的矩阵 ||  Gauss Weight  
    static const half4 GaussWeight[7] =
    {
        half4(0.0205,0.0205,0.0205,0),
        half4(0.0855,0.0855,0.0855,0),
        half4(0.232,0.232,0.232,0),
        half4(0.324,0.324,0.324,1),
        half4(0.232,0.232,0.232,0),
        half4(0.0855,0.0855,0.0855,0),
        half4(0.0205,0.0205,0.0205,0)
    };


    //【6】顶点着色函数 || Vertex Shader Function  
    VertexOutput_DownSmpl vert_DownSmpl(VertexInput v)
    {
        //【6.1】实例化一个降采样输出结构  
        VertexOutput_DownSmpl o;

        //【6.2】填充输出结构  
        //将三维空间中的坐标投影到二维窗口    
        o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
        //对图像的降采样:取像素上下左右周围的点,分别存于四级纹理坐标中  
        o.uv20 = v.texcoord + _MainTex_TexelSize.xy* half2(0.5h, 0.5h);;
        o.uv21 = v.texcoord + _MainTex_TexelSize.xy * half2(-0.5h, -0.5h);
        o.uv22 = v.texcoord + _MainTex_TexelSize.xy * half2(0.5h, -0.5h);
        o.uv23 = v.texcoord + _MainTex_TexelSize.xy * half2(-0.5h, 0.5h);

        //【6.3】返回最终的输出结果  
        return o;
    }

    //【7】片段着色函数 || Fragment Shader Function  
    fixed4 frag_DownSmpl(VertexOutput_DownSmpl i) : SV_Target
    {
        //【7.1】定义一个临时的颜色值  
        fixed4 color = (0,0,0,0);

    //【7.2】四个相邻像素点处的纹理值相加  
    color += tex2D(_MainTex, i.uv20);
    color += tex2D(_MainTex, i.uv21);
    color += tex2D(_MainTex, i.uv22);
    color += tex2D(_MainTex, i.uv23);

    //【7.3】返回最终的平均值  
    return color / 4;
    }

        //【8】顶点输入结构体 || Vertex Input Struct  
        struct VertexOutput_Blur
    {
        //像素坐标  
        float4 pos : SV_POSITION;
        //一级纹理(纹理坐标)  
        half4 uv : TEXCOORD0;
        //二级纹理(偏移量)  
        half2 offset : TEXCOORD1;
    };

    //【9】顶点着色函数 || Vertex Shader Function  
    VertexOutput_Blur vert_BlurHorizontal(VertexInput v)
    {
        //【9.1】实例化一个输出结构  
        VertexOutput_Blur o;

        //【9.2】填充输出结构  
        //将三维空间中的坐标投影到二维窗口    
        o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
        //纹理坐标  
        o.uv = half4(v.texcoord.xy, 1, 1);
        //计算X方向的偏移量  
        o.offset = _MainTex_TexelSize.xy * half2(1.0, 0.0) * _DownSampleValue;

        //【9.3】返回最终的输出结果  
        return o;
    }

    //【10】顶点着色函数 || Vertex Shader Function  
    VertexOutput_Blur vert_BlurVertical(VertexInput v)
    {
        //【10.1】实例化一个输出结构  
        VertexOutput_Blur o;

        //【10.2】填充输出结构  
        //将三维空间中的坐标投影到二维窗口    
        o.pos = mul(UNITY_MATRIX_MVP, v.vertex);
        //纹理坐标  
        o.uv = half4(v.texcoord.xy, 1, 1);
        //计算Y方向的偏移量  
        o.offset = _MainTex_TexelSize.xy * half2(0.0, 1.0) * _DownSampleValue;

        //【10.3】返回最终的输出结果  
        return o;
    }

    //【11】片段着色函数 || Fragment Shader Function  
    half4 frag_Blur(VertexOutput_Blur i) : SV_Target
    {
        //【11.1】获取原始的uv坐标  
        half2 uv = i.uv.xy;

        //【11.2】获取偏移量  
        half2 OffsetWidth = i.offset;
        //从中心点偏移3个间隔,从最左或最上开始加权累加  
        half2 uv_withOffset = uv - OffsetWidth * 3.0;

        //【11.3】循环获取加权后的颜色值  
        half4 color = 0;
        for (int j = 0; j< 7; j++)
        {
            //偏移后的像素纹理值  
            half4 texCol = tex2D(_MainTex, uv_withOffset);
            //待输出颜色值+=偏移后的像素纹理值 x 高斯权重  
            color += texCol * GaussWeight[j];
            //移到下一个像素处,准备下一次循环加权  
            uv_withOffset += OffsetWidth;
        }

        //【11.4】返回最终的颜色值  
        return color;
    }

        //-------------------结束CG着色语言声明部分  || End CG Programming Part------------------               
        ENDCG

        FallBack Off
}
安装Docker安装插件,可以按照以下步骤进行操作: 1. 首先,安装Docker。可以按照官方文档提供的步骤进行安装,或者使用适合您操作系统的包管理器进行安装。 2. 安装Docker Compose插件。可以使用以下方法安装: 2.1 下载指定版本的docker-compose文件: curl -L https://github.com/docker/compose/releases/download/1.21.2/docker-compose-`uname -s`-`uname -m` -o /usr/local/bin/docker-compose 2.2 赋予docker-compose文件执行权限: chmod +x /usr/local/bin/docker-compose 2.3 验证安装是否成功: docker-compose --version 3. 在安装插件之前,可以测试端口是否已被占用,以避免编排过程中出错。可以使用以下命令安装netstat并查看端口号是否被占用: yum -y install net-tools netstat -npl | grep 3306 现在,您已经安装Docker安装Docker Compose插件,可以继续进行其他操作,例如上传docker-compose.yml文件到服务器,并在服务器上安装MySQL容器。可以参考Docker的官方文档或其他资源来了解如何使用DockerDocker Compose进行容器的安装和配置。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Docker安装docker-compose插件](https://blog.csdn.net/qq_50661854/article/details/124453329)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [Docker安装MySQL docker安装mysql 完整详细教程](https://blog.csdn.net/qq_40739917/article/details/130891879)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值