2018-12-26 16:37:25 PangNanGua 阅读数 141

高斯模糊可以实现模糊效果,可用于眩晕,场景动画等效果

高斯模糊利用了卷积计算,把每个像素和周围的像素混合

 

见代码实现

c#代码 ImageEffectBase

using UnityEngine;

namespace GameBase.Effect
{
    [RequireComponent(typeof (Camera))]
    [AddComponentMenu("")]
    public class ImageEffectBase : MonoBehaviour
    {
        /// Provides a shader property that is set in the inspector
        /// and a material instantiated from the shader
        public Shader shader;

        private Material m_Material;


        protected virtual void Start()
        {
            // Disable if we don't support image effects
            if (!SystemInfo.supportsImageEffects)
            {
                enabled = false;
                return;
            }

            // Disable the image effect if the shader can't
            // run on the users graphics card
            if (!shader || !shader.isSupported)
                enabled = false;
        }


        protected Material material
        {
            get
            {
                if (m_Material == null)
                {
                    m_Material = new Material(shader);
                    m_Material.hideFlags = HideFlags.HideAndDontSave;
                }
                return m_Material;
            }
        }


        protected virtual void OnDisable()
        {
            if (m_Material)
            {
                DestroyImmediate(m_Material);
            }
        }
    }
}

c#代码 BlurEffect

using UnityEngine;

namespace GameBase.Effect
{
    public class BlurEffect : ImageEffectBase
    {

        [Range(0, 10)]
        [SerializeField]
        private int _downSample = 1;//分辨率降低值

        [SerializeField]
        [Range(0, 8)]
        private float _blurSize = 1;//取周围多远的像素

        [SerializeField]
        [Range(1, 10)]
        private int _filterCount = 1;//滤波次数(越大性能越差)

        private int ID_BlurSize;

        private void OnEnable()
        {
            ID_BlurSize = Shader.PropertyToID("_BlurSize");
        }

        void OnRenderImage(RenderTexture source, RenderTexture destination)
        {
            if(_blurSize <= 0 )
            {
                Graphics.Blit(source, destination);
                return;
            }
            int width = source.width >> _downSample;
            int height = source.height >> _downSample;
            if (width <= 0)
                width = 1;
            if (height <= 0)
                height = 1;

            if (_filterCount == 1)
            {
                RenderTexture bufferRT = RenderTexture.GetTemporary(width, height, 0, source.format);
                if (material.HasProperty(ID_BlurSize))
                {
                    material.SetFloat(ID_BlurSize, _blurSize);
                }
                Graphics.Blit(source, bufferRT, material, 0);
                Graphics.Blit(bufferRT, destination, material, 1);
                RenderTexture.ReleaseTemporary(bufferRT);
            }
            else
            {
                RenderTexture bufferRT1 = RenderTexture.GetTemporary(width, height, 0, source.format);
                RenderTexture bufferRT2 = RenderTexture.GetTemporary(width, height, 0, source.format);
               
                if (material.HasProperty(ID_BlurSize))
                {
                    material.SetFloat(ID_BlurSize, _blurSize);
                }
                Graphics.Blit(source, bufferRT1, material, 0);
                for (int i = 1; i < _filterCount; i++)
                {
                    Graphics.Blit(bufferRT1, bufferRT2, material, 1);
                    Graphics.Blit(bufferRT2, bufferRT1, material, 0);
                }

                Graphics.Blit(bufferRT1, destination, material, 1);

                RenderTexture.ReleaseTemporary(bufferRT1);
                RenderTexture.ReleaseTemporary(bufferRT2);
            }

        }
    }
}

shader代码 

 

Shader "mgo/blur" 
{
    Properties
    {
        _MainTex("Texture", 2D) = "white" {}
        _BlurSize("_BlurSize", range(0, 300)) = 1
    }

    SubShader
    {
        Tags{ "RenderType" = "Opaque" }
        
        ZTest Off
        cull Off
        ZWrite Off

        Pass
        {
            Name "Horizontal"
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata {
                float4 vertex:POSITION;
                float2 uv:TEXCOORD0;
            };

            struct v2f
            {
                float4 pos:SV_POSITION;
                float2 uv[5]:TEXCOORD0;
            };

            uniform sampler2D _MainTex;
            //xxx_TexelSize 是用来访问xxx纹理对应的每个文素的大小 ,如一张512*512的图该值大小为1/512≈0.001953125
            uniform float4 _MainTex_TexelSize;
            uniform half _BlurSize;

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                half2 uv = v.uv;
                o.uv[0] = uv;
                o.uv[1] = uv + _MainTex_TexelSize.xy * half2(_BlurSize, 0);
                o.uv[2] = uv + _MainTex_TexelSize.xy * half2(-_BlurSize, 0);
                o.uv[3] = uv + _MainTex_TexelSize.xy * half2(_BlurSize * 2, 0);
                o.uv[4] = uv + _MainTex_TexelSize.xy * half2(-_BlurSize * 2, 0);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                fixed4 col = 0.4 * tex2D(_MainTex,i.uv[0]);
                col += 0.24 * tex2D(_MainTex, i.uv[1]);
                col += 0.24 * tex2D(_MainTex, i.uv[2]);
                col += 0.06 * tex2D(_MainTex, i.uv[3]);
                col += 0.06 * tex2D(_MainTex, i.uv[4]);
                return col;
            }
            ENDCG
        }

        Pass
        {
            Name "Vertical"
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag

            #include "UnityCG.cginc"

            struct appdata {
                float4 vertex:POSITION;
                float2 uv:TEXCOORD0;
            };

            struct v2f
            {
                float4 pos:SV_POSITION;
                float2 uv[5]:TEXCOORD0;
            };

            uniform sampler2D _MainTex;
            uniform float4 _MainTex_TexelSize;
            uniform half _BlurSize;

            v2f vert(appdata v)
            {
                v2f o;
                o.pos = UnityObjectToClipPos(v.vertex);
                half2 uv = v.uv;
                o.uv[0] = uv;
                o.uv[1] = uv + _MainTex_TexelSize.xy * half2(0, _BlurSize);
                o.uv[2] = uv + _MainTex_TexelSize.xy * half2(0, -_BlurSize);
                o.uv[3] = uv + _MainTex_TexelSize.xy * half2(0, _BlurSize * 2);
                o.uv[4] = uv + _MainTex_TexelSize.xy * half2(0, -_BlurSize * 2);
                return o;
            }

            fixed4 frag(v2f i) : SV_Target
            {
                fixed4 col = 0.4 * tex2D(_MainTex,i.uv[0]);
                col += 0.24 * tex2D(_MainTex, i.uv[1]);
                col += 0.24 * tex2D(_MainTex, i.uv[2]);
                col += 0.06 * tex2D(_MainTex, i.uv[3]);
                col += 0.06 * tex2D(_MainTex, i.uv[4]);
                return col;
            }
            ENDCG
        }

        
    }
}


 

 

2019-05-08 19:20:30 liu18255603500 阅读数 235

如果你当前工程Canvas使用的是Screen Space - Overlay 模式,那么直接可以使用

但是使用 Screen Space - Camera 模式,如果模糊效果没有实现话,你可能得到在Scene窗口下能看到模糊效果,但是在Game窗口并没效果,此时你要检查Canvas Plane Distance是不是离的太远造成的!

 

 

 

// Upgrade NOTE: replaced 'mul(UNITY_MATRIX_MVP,*)' with 'UnityObjectToClipPos(*)'

Shader "Custom/BackBlur"
{
	Properties
	{
        [PerRendererData] _MainTex ("Sprite Texture", 2D) = "white" {}
		_Color ("Main Color", Color) = (1,1,1,1)
        _Size ("Size", Range(0, 20)) = 1
	}
	Category {  
  
        // We must be transparent, so other objects are drawn before this one.  
        Tags { 
			"Queue"="Transparent" 
			"IgnoreProjector"="True" 
			"RenderType"="Transparent"
			"PreviewType" = "Plane"
			"CanUseSpriteAtlas" = "True"
		}  
  
  
        SubShader {  
  
            // Horizontal blur  
            GrabPass {                      
                Tags { "LightMode" = "Always" }  
            }  
            Pass {
                Tags { "LightMode" = "Always" }  

                Name "BackBlurHor"
                CGPROGRAM  
                #pragma vertex vert  
                #pragma fragment frag  
                #pragma fragmentoption ARB_precision_hint_fastest  
                #include "UnityCG.cginc"  
  
                struct appdata_t {  
                    float4 vertex : POSITION;  
                    float2 texcoord : TEXCOORD0;
					float4 color    : COLOR;
                };  
  
                struct v2f {  
                    float4 vertex : POSITION;  
                    float4 uvgrab : TEXCOORD0;
					float4 color    : COLOR;
                };
  
                v2f vert (appdata_t v) {  
                    v2f o; 
                    o.vertex = UnityObjectToClipPos(v.vertex);  
                    #if UNITY_UV_STARTS_AT_TOP  
                    float scale = -1.0;  
                    #else  
                    float scale = 1.0;  
                    #endif  
                    o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5;  
                    o.uvgrab.zw = o.vertex.zw;  

					o.color = v.color;
                    return o;  
                }  
  
                sampler2D _GrabTexture;  
                float4 _GrabTexture_TexelSize;
			    float4 _MainTex_TexelSize;
                float _Size;
                uniform float4 _Color;

                // static float GaussianKernel[9] = {
                //     0.05, 0.09, 0.12,
                //     0.15, 0.18, 0.15,
                //     0.12, 0.09, 0.05
                // };

                // static float GaussianKernel[19] = {
                //     0.01, 0.02, 0.03, 0.04, 0.05, 0.06, 0.07, 0.08, 0.09,
                //     0.1,
                //     0.09, 0.08, 0.07, 0.06, 0.05, 0.04, 0.03, 0.02, 0.01,
                // };
                // static float GaussianKernelD[19] = {
                //     -9.0, -8.0, -7.0, -6.0, -5.0, -4.0, -3.0, -2.0, -1.0,
                //     0.0,
                //     +1.0, +2.0, +3.0, +4.0, +5.0, +6.0, +7.0, +8.0, +9.0,
                // };

                half4 GrabPixel(v2f i, float weight, float kernelx){
                    if (i.uvgrab.x == 0 && i.uvgrab.y == 0){
                        kernelx = 0;
                    }
                    return tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x + _GrabTexture_TexelSize.x*kernelx*_Size, i.uvgrab.y, i.uvgrab.z, i.uvgrab.w))) * weight;
                }
                half4 frag( v2f i ) : COLOR {  
                 	half4 sum = half4(0,0,0,0);
                    // #define GRABPIXEL(weight, kernelx) tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x + _GrabTexture_TexelSize.x * kernelx*_Size, i.uvgrab.y, i.uvgrab.z, i.uvgrab.w))) * weight
                    
                    sum += GrabPixel(i, 0.05, -4.0);
                    sum += GrabPixel(i, 0.09, -3.0);
                    sum += GrabPixel(i, 0.12, -2.0);
                    sum += GrabPixel(i, 0.15, -1.0);
                    sum += GrabPixel(i, 0.18,  0.0);
                    sum += GrabPixel(i, 0.15, +1.0);
                    sum += GrabPixel(i, 0.12, +2.0);
                    sum += GrabPixel(i, 0.09, +3.0);
                    sum += GrabPixel(i, 0.05, +4.0);

                    // sum += GrabPixel(i, 0.01, -9.0);
                    // sum += GrabPixel(i, 0.02, -8.0);
                    // sum += GrabPixel(i, 0.03, -7.0);
                    // sum += GrabPixel(i, 0.04, -6.0);
                    // sum += GrabPixel(i, 0.05, -5.0);
                    // sum += GrabPixel(i, 0.06, -4.0);
                    // sum += GrabPixel(i, 0.07, -3.0);
                    // sum += GrabPixel(i, 0.08, -2.0);
                    // sum += GrabPixel(i, 0.09, -1.0);
                    // sum += GrabPixel(i, 0.10,  0.0);
                    // sum += GrabPixel(i, 0.09, +1.0);
                    // sum += GrabPixel(i, 0.08, +2.0);
                    // sum += GrabPixel(i, 0.07, +3.0);
                    // sum += GrabPixel(i, 0.06, +4.0);
                    // sum += GrabPixel(i, 0.05, +5.0);
                    // sum += GrabPixel(i, 0.04, +6.0);
                    // sum += GrabPixel(i, 0.03, +7.0);
                    // sum += GrabPixel(i, 0.02, +8.0);
                    // sum += GrabPixel(i, 0.01, +9.0);

                    float4 col5 = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(i.uvgrab));
					float decayFactor = 1.0f;
					if (i.uvgrab.x == 0 && i.uvgrab.y == 0){
						decayFactor = 0;
					}
					sum = lerp(col5, sum, decayFactor) * i.color * _Color;
  
                    return sum;  
                }  
                ENDCG  
            }  
            // Vertical blur  
            GrabPass {                          
                Tags { "LightMode" = "Always" }  
            }  
            Pass {  
                Tags { "LightMode" = "Always" }

                Name "BackBlurVer"
                CGPROGRAM  
                #pragma vertex vert  
                #pragma fragment frag  
                #pragma fragmentoption ARB_precision_hint_fastest  
                #include "UnityCG.cginc"  
  
                struct appdata_t {  
                    float4 vertex : POSITION;  
                    float2 texcoord: TEXCOORD0;  
					float4 color    : COLOR;
                };  
  
                struct v2f {  
                    float4 vertex : POSITION;  
                    float4 uvgrab : TEXCOORD0;  
					float4 color    : COLOR;
                };  
  
                v2f vert (appdata_t v) {  
                    v2f o;  
                    o.vertex = UnityObjectToClipPos(v.vertex);  
                    #if UNITY_UV_STARTS_AT_TOP  
                    float scale = -1.0;  
                    #else  
                    float scale = 1.0;  
                    #endif  
                    o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y*scale) + o.vertex.w) * 0.5;  
                    o.uvgrab.zw = o.vertex.zw;  

					o.color = v.color;
                    return o;  
                }  
  
                sampler2D _GrabTexture;  
                float4 _GrabTexture_TexelSize;  
                float _Size;
                uniform float4 _Color;

                half4 GrabPixel(v2f i, float weight, float kernely){
                    if (i.uvgrab.x == 0 && i.uvgrab.y == 0){
                        kernely = 0;
                    }
                    return tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x, i.uvgrab.y + _GrabTexture_TexelSize.y*kernely*_Size, i.uvgrab.z, i.uvgrab.w))) * weight;
                }
  
                half4 frag( v2f i ) : COLOR {
                    half4 sum = half4(0,0,0,0);  
                    // #define GRABPIXEL(weight,kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x, i.uvgrab.y + _GrabTexture_TexelSize.y * kernely*_Size, i.uvgrab.z, i.uvgrab.w))) * weight  
  
                    sum += GrabPixel(i, 0.05, -4.0);
                    sum += GrabPixel(i, 0.09, -3.0);
                    sum += GrabPixel(i, 0.12, -2.0);
                    sum += GrabPixel(i, 0.15, -1.0);
                    sum += GrabPixel(i, 0.18,  0.0);
                    sum += GrabPixel(i, 0.15, +1.0);
                    sum += GrabPixel(i, 0.12, +2.0);
                    sum += GrabPixel(i, 0.09, +3.0);
                    sum += GrabPixel(i, 0.05, +4.0);

                    // sum += GrabPixel(i, 0.01, -9.0);
                    // sum += GrabPixel(i, 0.02, -8.0);
                    // sum += GrabPixel(i, 0.03, -7.0);
                    // sum += GrabPixel(i, 0.04, -6.0);
                    // sum += GrabPixel(i, 0.05, -5.0);
                    // sum += GrabPixel(i, 0.06, -4.0);
                    // sum += GrabPixel(i, 0.07, -3.0);
                    // sum += GrabPixel(i, 0.08, -2.0);
                    // sum += GrabPixel(i, 0.09, -1.0);
                    // sum += GrabPixel(i, 0.10,  0.0);
                    // sum += GrabPixel(i, 0.09, +1.0);
                    // sum += GrabPixel(i, 0.08, +2.0);
                    // sum += GrabPixel(i, 0.07, +3.0);
                    // sum += GrabPixel(i, 0.06, +4.0);
                    // sum += GrabPixel(i, 0.05, +5.0);
                    // sum += GrabPixel(i, 0.04, +6.0);
                    // sum += GrabPixel(i, 0.03, +7.0);
                    // sum += GrabPixel(i, 0.02, +8.0);
                    // sum += GrabPixel(i, 0.01, +9.0);

					float4 col5 = tex2Dproj(_GrabTexture, UNITY_PROJ_COORD(i.uvgrab));
					float decayFactor = 1.0f;
					if (i.uvgrab.x == 0 && i.uvgrab.y == 0){
						decayFactor = 0;
					}
					sum = lerp(col5, sum, decayFactor) * i.color * _Color;
  
                    return sum;  
                }  
                ENDCG  
            }
        }  
    } 


}

 

2018-07-16 14:33:19 weixin_42452001 阅读数 225

C#代码:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;


public class GaoSiMouHu : MonoBehaviour {
    //高斯模糊 正态分布
    public Material mat;


    public float radio=1f;//半径


    public int downSample = 1;//分辨率进行缩放


    public int iteration = 1;//迭代次数


    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        RenderTexture rt1 = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0, source.format);
        RenderTexture rt2 = RenderTexture.GetTemporary(source.width >> downSample, source.height >> downSample, 0, source.format);
        Graphics.Blit(source, rt1);


        for (int i = 0; i < iteration; i++)
        {
            mat.SetVector("_Offset", new Vector4(0, radio, 0, 0));
            Graphics.Blit(rt1, rt2, mat);


            mat.SetVector("_Offset", new Vector4(radio, 0, 0, 0));
            Graphics.Blit(rt2, rt1, mat);


        }
        Graphics.Blit(rt1, destination);


        RenderTexture.ReleaseTemporary(rt1);
        RenderTexture.ReleaseTemporary(rt2);
    }

}

Shader代码:

Shader "Unlit/Test"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
}
SubShader
{
Tags { "RenderType"="Opaque" }
LOD 100


Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag


#include "UnityCG.cginc"


struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};


struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
float4 uv01:TEXCOORD1;
float4 uv23:TEXCOORD2;
float4 uv45:TEXCOORD3;
};


sampler2D _MainTex;
float4 _MainTex_TexelSize;
float4 _Offset;


v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
o.uv =v.vertex.xy;
_Offset*=_MainTex_TexelSize.xyxy;
o.uv01=v.vertex.xyxy+_Offset.xyxy*float4(1,1,-1,-1);
o.uv23=v.vertex.xyxy+_Offset.xyxy*float4(1,1,-1,-1)*2.0;
o.uv45=v.vertex.xyxy+_Offset.xyxy*float4(1,1,-1,-1)*3.0;
return o;
}

fixed4 frag (v2f i) : SV_Target
{
// sample the texture
fixed4 col =fixed4(0,0,0,0);//正态分布,权值线性变化
col+=0.4*tex2D(_MainTex,i.uv);
col+=0.15*tex2D(_MainTex,i.uv01.xy);
col+=0.15*tex2D(_MainTex,i.uv01.zw);
col+=0.10*tex2D(_MainTex,i.uv23.xy);
col+=0.10*tex2D(_MainTex,i.uv23.zw);
col+=0.05*tex2D(_MainTex,i.uv45.xy);
col+=0.05*tex2D(_MainTex,i.uv45.zw);


return col;
}
ENDCG
}
}

}

2019-11-08 19:15:23 qq_39162826 阅读数 94

前言

高斯模糊是非常常用的一种特效,比如说营造景深或者毛玻璃等效果都可以使用。下面介绍一下镜头和UI上的使用。

1.Camera上的镜头特效

摄像机上可以通过两款特效插件非常方便的实现这种效果。第一款插件就是经典的ImageEffect,可以在镜头下添加BlurOptimized组件轻松的实现,具体的效果可以通过改变参数调节。第二款插件是PostProcess,它是第一款插件的升级版,功能也更加丰富。安装好插件后首先给Camera下添加PostProcessingBehaviour组件,然后在Project面板下右键创建一个PostProcess拖拽给相机下的PostProcessingBehaviour组件,之后在PostProcess里调节效果就可以了。高斯模糊特效只是这两个插件的一小部分功能,还有很多好用的效果,例如bloom、噪点等等,大家可以自己研究一下。
不过有个坑就是移动端最好使用ImageEffect更加稳定一些,我在项目中最开始时使用PostProcess实现的效果,结果在低端机上测试出现花屏现象。查了一下好像是低端机的GPU不支持新的shader api造成的。下面是两种插件的链接。
1.ImageEffect
2.PostProcess

2.UGUI中给image添加shader实现

因为要实现模糊对话面板后面背景的效果,所以就不能通过直接给相机添加特效实现,而是要做成类似遮罩划分出层级。在网上试了好多种shader,下面是我试过其中最好用的。

使用方法:先把image的透明度设置为0,然后把加有shader的material赋给image就可以了。具体效果可以通过改变material上的参数调节。

Shader "Custom/MaskedUIBlur" {
    Properties {
        _Size ("Blur", Range(0, 30)) = 1
        [HideInInspector] _MainTex ("Masking Texture", 2D) = "white" {}
        _AdditiveColor ("Additive Tint color", Color) = (0, 0, 0, 0)
        _MultiplyColor ("Multiply Tint color", Color) = (1, 1, 1, 1)
    }

    Category {

        // We must be transparent, so other objects are drawn before this one.
        Tags { "Queue"="Transparent" "IgnoreProjector"="True" "RenderType"="Opaque" }


        SubShader
        {
            // Horizontal blur
            GrabPass
            {
                "_HBlur"
            }
            /*
            ZTest Off
            Blend SrcAlpha OneMinusSrcAlpha
            */

            Cull Off
            Lighting Off
            ZWrite Off
            ZTest [unity_GUIZTestMode]
            Blend SrcAlpha OneMinusSrcAlpha

            Pass
            {          
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #pragma fragmentoption ARB_precision_hint_fastest
                #include "UnityCG.cginc"

                struct appdata_t {
                    float4 vertex : POSITION;
                    float2 texcoord : TEXCOORD0;
                };

                struct v2f {
                    float4 vertex : POSITION;
                    float4 uvgrab : TEXCOORD0;
                    float2 uvmain : TEXCOORD1;
                };

                sampler2D _MainTex;
                float4 _MainTex_ST;

                v2f vert (appdata_t v)
                {
                    v2f o;
                    o.vertex = UnityObjectToClipPos(v.vertex);

                    #if UNITY_UV_STARTS_AT_TOP
                    float scale = -1.0;
                    #else
                    float scale = 1.0;
                    #endif

                    o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y * scale) + o.vertex.w) * 0.5;
                    o.uvgrab.zw = o.vertex.zw;

                    o.uvmain = TRANSFORM_TEX(v.texcoord, _MainTex);
                    return o;
                }

                sampler2D _HBlur;
                float4 _HBlur_TexelSize;
                float _Size;
                float4 _AdditiveColor;
                float4 _MultiplyColor;

                half4 frag( v2f i ) : COLOR
                {   
                    half4 sum = half4(0,0,0,0);

                    #define GRABPIXEL(weight,kernelx) tex2Dproj( _HBlur, UNITY_PROJ_COORD(float4(i.uvgrab.x + _HBlur_TexelSize.x * kernelx * _Size, i.uvgrab.y, i.uvgrab.z, i.uvgrab.w))) * weight

                    sum += GRABPIXEL(0.05, -4.0);
                    sum += GRABPIXEL(0.09, -3.0);
                    sum += GRABPIXEL(0.12, -2.0);
                    sum += GRABPIXEL(0.15, -1.0);
                    sum += GRABPIXEL(0.18,  0.0);
                    sum += GRABPIXEL(0.15, +1.0);
                    sum += GRABPIXEL(0.12, +2.0);
                    sum += GRABPIXEL(0.09, +3.0);
                    sum += GRABPIXEL(0.05, +4.0);


                    half4 result = half4(sum.r * _MultiplyColor.r + _AdditiveColor.r, 
                                        sum.g * _MultiplyColor.g + _AdditiveColor.g, 
                                        sum.b * _MultiplyColor.b + _AdditiveColor.b, 
                                        tex2D(_MainTex, i.uvmain).a);
                    return result;
                }
                ENDCG
            }

            // Vertical blur
            GrabPass
            {
                "_VBlur"
            }

            Pass
            {          
                CGPROGRAM
                #pragma vertex vert
                #pragma fragment frag
                #pragma fragmentoption ARB_precision_hint_fastest
                #include "UnityCG.cginc"

                struct appdata_t {
                    float4 vertex : POSITION;
                    float2 texcoord: TEXCOORD0;
                };

                struct v2f {
                    float4 vertex : POSITION;
                    float4 uvgrab : TEXCOORD0;
                    float2 uvmain : TEXCOORD1;
                };

                sampler2D _MainTex;
                float4 _MainTex_ST;

                v2f vert (appdata_t v) {
                    v2f o;
                    o.vertex = UnityObjectToClipPos(v.vertex);

                    #if UNITY_UV_STARTS_AT_TOP
                    float scale = -1.0;
                    #else
                    float scale = 1.0;
                    #endif

                    o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y * scale) + o.vertex.w) * 0.5;
                    o.uvgrab.zw = o.vertex.zw;

                    o.uvmain = TRANSFORM_TEX(v.texcoord, _MainTex);

                    return o;
                }

                sampler2D _VBlur;
                float4 _VBlur_TexelSize;
                float _Size;
                float4 _AdditiveColor;
                float4 _MultiplyColor;

                half4 frag( v2f i ) : COLOR
                {
                    half4 sum = half4(0,0,0,0);

                    #define GRABPIXEL(weight,kernely) tex2Dproj( _VBlur, UNITY_PROJ_COORD(float4(i.uvgrab.x, i.uvgrab.y + _VBlur_TexelSize.y * kernely * _Size, i.uvgrab.z, i.uvgrab.w))) * weight

                    sum += GRABPIXEL(0.05, -4.0);
                    sum += GRABPIXEL(0.09, -3.0);
                    sum += GRABPIXEL(0.12, -2.0);
                    sum += GRABPIXEL(0.15, -1.0);
                    sum += GRABPIXEL(0.18,  0.0);
                    sum += GRABPIXEL(0.15, +1.0);
                    sum += GRABPIXEL(0.12, +2.0);
                    sum += GRABPIXEL(0.09, +3.0);
                    sum += GRABPIXEL(0.05, +4.0);

                    half4 result = half4(sum.r * _MultiplyColor.r + _AdditiveColor.r, 
                                        sum.g * _MultiplyColor.g + _AdditiveColor.g, 
                                        sum.b * _MultiplyColor.b + _AdditiveColor.b, 
                                        tex2D(_MainTex, i.uvmain).a);
                    return result;
                }
                ENDCG
            }
        }
    }
}
2019-05-08 12:29:23 pz789as 阅读数 141

之前一直想使用Shader去做高斯模糊特效,后面发现图片过大的话,效率真的是相当的不理想。

后来在网上看到说iOS本身是有将图片处理成高斯模糊的功能的,想想也确实,苹果设备的背景经常会出现模糊特效,那他们的算法应该很快速的,于是突发奇想,如果将要做模糊处理的图片,传到原生端然后处理成模糊图片之后,再传回来使用,不就可以达到这个目的了么!

首先要知道这个的局限性,不能实时的去做,这是什么意思呢,如果截图这一下也是会有一点卡的,如果实时处理的话,肯定会不流畅。

还有一个,图片的格式,不能是Unity的压缩格式,因为我没法解压缩图片,那穿过去的图片就没法生成正常图片了。

最后,图片要是可读写的,否则拿不到图片的二进制数据,也没法做;

那么怎么做呢,关于Unity桥接原生的我在之前的文章说过了,可以参考这里:Unity和iOS互通

原生代码:

- (void) imageToBlurImage:(NSString *)media radius:(float)radius {
    if(media.length != 0) {// 1、创建输入图像,CIImage类型,这里使用从外部传过来的图片。
        NSData *imageData = [[NSData alloc]initWithBase64EncodedString:media options:0];
        CIImage* inputImage = [CIImage imageWithData:imageData];
        
        // 2、构建一个滤镜图表
//        CIColor* sepiaColor = [CIColor colorWithRed:0.76 green:0.65 blue:0.54];
//        // 2.1 先构建一个 CIColorMonochrome 滤镜,并配置输入图像与滤镜参数
//        CIFilter* monochromeFilter = [CIFilter filterWithName:@"CIColorMonochrome" withInputParameters:@{@"inputColor":sepiaColor,@"inputIntensity":@1.0}];
//        [monochromeFilter setValue:inputImage forKey:@"inputImage"];
//        // 2.2 先构建一个 CIVignette 滤镜
//        CIFilter* vignetteFilter = [CIFilter filterWithName:@"CIVignette" withInputParameters:@{@"inputRadius":@1.0, @"inputIntensity":@1.0}];
//        [vignetteFilter setValue:monochromeFilter.outputImage forKey:@"inputImage"];
        NSNumber* numRad = [NSNumber numberWithFloat:radius];
        CIFilter* gaussianFilter = [CIFilter filterWithName:@"CIGaussianBlur" withInputParameters:@{@"inputRadius":numRad}];
        [gaussianFilter setValue:inputImage forKey:@"inputImage"];
        
        // 3、得到一个滤镜处理后的图片,并转换至 UIImage
        // 创建一个 CIContext
        CIContext* ciContext = [CIContext contextWithOptions:nil];
        // 将 CIImage 过渡到 CGImageRef 类型
        CGImageRef cgImage = [ciContext createCGImage:gaussianFilter.outputImage fromRect:inputImage.extent];
        // 最后转换为 UIImage 类型
        UIImage* uiImage = [UIImage imageWithCGImage:cgImage];
        
        // 将得到的图片转化成图片数据,通过SendMessage传送到Unity端
        NSData *imgData = UIImagePNGRepresentation(uiImage);
        NSString *_encodeImageStr = [imgData base64EncodedStringWithOptions:NSDataBase64DecodingIgnoreUnknownCharacters];
        if (_encodeImageStr == nil){
            UnitySendMessage( "GJCNativeShare", "ToBlurImageFailed", [GJC_DataConvertor NSStringToChar:@"iamge change error! the image format is not support!"]);
        }else{
            UnitySendMessage( "GJCNativeShare", "ToBlurImageSuccess", _encodeImageStr.UTF8String);
        }
    }else{
        UnitySendMessage( "GJCNativeShare", "ToBlurImageFailed", [GJC_DataConvertor NSStringToChar:@"iamge data is null!"]);
    }
}
extern "C" {
    void _GJC_ToBlurImage(char* encodedMedia, float radius){
        NSString *media = [GJC_DataConvertor charToNSString:encodedMedia];
        [[GJCSocialShare sharedInstance] imageToBlurImage:media radius:radius];
    }
}

然后Unity这边:

[DllImport ("__Internal")]
	private static extern bool _GJC_ToBlurImage(string encodedMedia, float radius);
/// <summary>
	/// 调用原生的高斯模糊处理,传递一张图片过去,得到处理之后的图片
	/// </summary>
	/// <param name="texture">分享的图片</param>
	public void TextureToBlur(Texture2D texture, float radius) {
		Debug.Log("TextureToBlur");
		#if UNITY_IPHONE && !UNITY_EDITOR
			if(texture != null) {
				Debug.Log("TextureToBlur: Texture");
				string bytesString = System.Convert.ToBase64String (texture.EncodeToPNG());
				// string bytesString = System.Convert.ToBase64String (texture.GetRawTextureData());
				_GJC_ToBlurImage(bytesString, radius);
			}else{
				ToBlurImageFailed("texture is null!");
			}
		#else
			// string bytesString = System.Convert.ToBase64String (texture.EncodeToEXR());
			// Texture2D newTexture = new Texture2D(1,1);
			// newTexture.LoadRawTextureData(texture.GetRawTextureData());
			// string bytesString = System.Convert.ToBase64String (texture.EncodeToPNG());
			ToBlurImageFailed("this platform is not support!");
		#endif
	}

从原生的回调:

/// <summary>
	/// 图片转换成Blur效果之后,回调的结果
	/// </summary>
	/// <param name="base64">Base64.</param>
	private void ToBlurImageSuccess(string base64)	  
	{
		Debug.Log ("Native To ToBlurImageSuccess");
		if(onToBlurImage != null)
		{
			onToBlurImage("Success", base64);
		}
	}
	private void ToBlurImageFailed(string error){
		Debug.Log ("Native To ToBlurImageFailed: " + error);
		if(onToBlurImage != null)
		{
			onToBlurImage("Failed", error);
		}
	}

将iOS传递过来的数据,转换成图片

/// <summary>
	/// 将ios传过的string转成u3d中的texture
	/// </summary>
	/// <param name="base64"></param>
	/// <returns></returns>
	public static Texture2D Base64StringToTexture2D(string base64)
	{
		Debug.Log ("Run Base64StringToTexture2d");
		Texture2D tex = new Texture2D(1,1);
		try
		{			
			byte[] bytes = System.Convert.FromBase64String(base64);
			tex.LoadImage(bytes);
			tex.hideFlags = HideFlags.DontSave;
			tex.filterMode = FilterMode.Point;
			tex.wrapMode = TextureWrapMode.Clamp;
		}
		catch(System.Exception ex)
		{
			Debug.Log ("Create Texture2D Failed!!");
			Debug.LogError(ex.Message);
		}
		return tex;
	}

自己使用了之后,速度还是蛮快的,目前这个用在一些固定大背景模糊的位置,实时的话,还是想想如何优化Shader去做吧。

没有更多推荐了,返回首页