运动模糊【Unity Shader入门精要12.6】

实现方法:

【1】利用一块 累积缓存(accumulation buffer)来混合多张连续的图像。当物体快速移动产生多张连续的图像后,去取他们之间的平均值作为最后的运动模糊图像,然而这种办法消耗很大

【2】创建和使用 速度缓存(Velocity buffer)这个缓存中存储了各个像素当前的运动速度,然后利用该值来决定模糊的方向和大小

本节使用的是第一种,不过不需要再一帧中把场景渲染多次,但需要保存之前的渲染结果,不断把当前的渲染图像叠加到之前的渲染图像中,从而产生一种运动轨迹的视觉效果,这种方法与原始 的利用累积缓存的方法相比性能更好,但模糊效果可能会略有影响

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

//12.6 运动模糊
public class MotionBlur : PostEffectsBase {
    public Shader motionBlurShader;  //声明shader
    private Material motionBlurMaterial = null;//声明材质

    public  Material material//创建材质
    {
        get
        {
            motionBlurMaterial = CheckShaderAndCreateMaterial(motionBlurShader, motionBlurMaterial);//把shader给新建的材质
            return motionBlurMaterial;//返回材质
        }
    }
    //定义运动模糊在混合图像时使用的迷糊参数
    [Range(0.0f, 0.9f)]//为了防止拖尾效果完全替代前帧的渲染结果,所以把值控制在0到0.9范围内
    public float blurAmount = 0.5f;

    private RenderTexture accumulationTexture;//定义一个RenderTexture类型的变量,保存之前图像叠加的结果

    //在该脚本不运行时,即调用OnDiable时,立即销毁accumulationTexture,这是因为希望在下一次开始应用运动模糊时重新叠加图像
    private void OnDisable()
    {
        DestroyImmediate(accumulationTexture);
    }
    //定义迷糊使用的OnRenderImage函数
    private void OnRenderImage(RenderTexture src, RenderTexture dest)
    {
        //确认材质可用
        if (material !=null)
        {
            //判断用于混合图像的accumationTexture是否为空,是否与当前分辨率不相等,
            if (accumulationTexture ==null ||accumulationTexture .width !=src .width||accumulationTexture .height !=src .height )
            {
                //立即销毁
                DestroyImmediate(accumulationTexture);
                //创建一个符合大小的得变量
                accumulationTexture = new RenderTexture(src.width, src.height, 0);
                //HideAndDontSave:保留对象到新场景,与DontSave类似,但不会显示在Hierarchy面板中
                accumulationTexture.hideFlags = HideFlags.HideAndDontSave;
                Graphics.Blit(src, accumulationTexture);//使用当前的帧图像初始化accumulationTexture
            }
            //恢复操作(restore operation):发生在渲染到纹理而该纹理又没有被提前清空或销毁的情况下

            //调用函数 【accumulationTexture.MarkRestoreExpected】来表明需要进行一个渲染纹理的恢复操作
            accumulationTexture.MarkRestoreExpected();

            //每次调用OnRenderImage时都需要把当前的帧图像和accumulationTexture中的图像混合,accumulationTexture纹理不需要提前清空,因为她保存了我们之前的混合结果
            
            material.SetFloat("_BlurAmount", 1.0f - blurAmount);//将参数传给材质

            Graphics.Blit(src, accumulationTexture, material);//把当前屏幕图像src叠加到accumulationTexture中
            Graphics.Blit(accumulationTexture, dest);//把结果显示到屏幕上
        }else
        {
            Graphics.Blit(src, dest);
        }
    }

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

//12.6运动模糊
Shader "Unlit/Chapter12-MotionBlur"
{
	Properties
	{//对应输入的渲染纹理
		_MainTex ("Base(RGB)", 2D) = "white" {}
	//混合系数
		_BlurAmount("Blur Amount" , Float) = 1.0
	}
	SubShader
	{
			CGINCLUDE
	#include "UnityCG.cginc"

			sampler2D  _MainTex;
			fixed _BlurAmount;

			struct v2f{
				float4 pos:SV_POSITION;
				half2 uv:TEXCOORD0;
			};

			v2f vert (appdata_img v){
				v2f o;
				o.pos = UnityObjectToClipPos(v.vertex);
				o.uv = v.texcoord;
				return o;
			}

			//定义两个片元着色器,为了保护A通道不受到混合的影响
			//渲染rgb通道
			fixed4 fragRGB(v2f i) : SV_Target{
				//对图像进行采样,把A通道的值设置为_BlurAmount,以便在后面混合时可以使用它的透明通道进行混合
			return fixed4(tex2D(_MainTex,i.uv).rgb,_BlurAmount); 
			}
			//渲染A通道
			half4 fragA(v2f i) : SV_Target{
				//直接返回采样结果
					return tex2D(_MainTex,i.uv);
			}

				ENDCG

				ZTest Always Cull Off ZWrite Off

	//之所以把把A通道和RGB通道分开,是因为在更新RGB时我们需要设置它的A通道的来混合图像,但又不希望A通道的值写入渲染纹理中

				//用来更新渲染RGB通道
			Pass
			{
				//混合 A 1-A
				Blend SrcAlpha OneMinusSrcAlpha
					//颜色遮罩 RGB
					ColorMask RGB


					CGPROGRAM
#pragma vertex vert
#pragma fragment fragRGB
					ENDCG 
			}

			//用来更新渲染A通道
			Pass {
				//混合 1 0
				Blend One Zero
					//颜色遮罩 A
				ColorMask A

				CGPROGRAM
#pragma vertex vert
#pragma fragment fragA
				ENDCG
			}
	}
			Fallback Off
}

关于shader的Blend参考:https://blog.csdn.net/baicaishisan/article/details/79072127

关于C#的HideFlags类参考:https://blog.csdn.net/Dylan_Day/article/details/80350420

不得不说,当个小白也挺好,学习资源不愁找,哈哈~

猜你喜欢

转载自blog.csdn.net/ABigDeal/article/details/84071424