UnityShader使用图像叠加实现运动模糊

下面是详细讲解"Unity Shader使用图像叠加实现运动模糊"的攻略。

一、前言

在实现游戏视觉效果时,运动模糊是一种非常实用的手段。运动模糊使用了相邻的帧并取平均值以模拟运动物体的模糊效果,使动作看起来更加连续、自然。

二、实现思路

运动模糊的实现思路是将相邻的帧的图像进行叠加处理,最后再进行取平均。具体实现时,需要使用相机的 RenderTexture 功能,将当前相机的图像渲染到 RenderTexture 上,并保存上一帧的 RenderTexture,再将当前帧的 RenderTexture 与上一帧的 RenderTexture 进行叠加,然后再将其取平均值并输出。

三、基础代码

下面是实现运动模糊的基础代码:

Shader "Custom/MotionBlurShader" {
    Properties {
        _MainTex ("Texture", 2D) = "white" {}
        _BlurAmount ("Blur Amount", Range(0.0, 1.0)) = 0.5
    }
    SubShader {
        Tags {"Queue"="Transparent" "RenderType"="Transparent"}
        Pass{
            RenderGrabScreenTex {
                Tags { "GrabType"="BeforeRender" }
            }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _BlurAmount;
            uniform float4 _ScreenParams;
            uniform sampler2D _GrabTexture;
            float4 _GrabTexture_TexelSize;

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

            struct v2f {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v) {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            float4 frag (v2f i) : SV_Target {
                float4 col = tex2D(_MainTex, i.uv);
                float4 previousCol = tex2D(_GrabTexture, i.uv);
                return col * (1 - _BlurAmount) + previousCol * _BlurAmount;
            }
            ENDCG
        }
        Pass{
            RenderGrabScreenTex {
                Tags { "GrabType"="BeforeRender" }
            }
            CGPROGRAM
            #pragma vertex vert
            #pragma fragment frag
            #include "UnityCG.cginc"

            sampler2D _MainTex;
            float4 _MainTex_ST;
            float _BlurAmount;
            uniform float4 _ScreenParams;
            uniform sampler2D _GrabTexture;
            float4 _GrabTexture_TexelSize;

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

            struct v2f {
                float2 uv : TEXCOORD0;
                float4 vertex : SV_POSITION;
            };

            v2f vert (appdata v) {
                v2f o;
                o.vertex = UnityObjectToClipPos(v.vertex);
                o.uv = TRANSFORM_TEX(v.uv, _MainTex);
                return o;
            }

            float4 frag (v2f i) : SV_Target {
                float4 col = tex2D(_MainTex, i.uv);
                float4 previousCol = tex2D(_GrabTexture, i.uv);
                float4 blurCol = col * (1 - _BlurAmount) + previousCol * _BlurAmount;
                float2 vel = float2(0, 0);
                vel.y = tex2D(_GrabTexture, i.uv + float2(0, 0.001)).a - previousCol.a;
                vel.x = tex2D(_GrabTexture, i.uv + float2(0.001, 0)).a - previousCol.a;
                return blurCol;
            }
            ENDCG
        }
    }
    GrabPass{}
}

在代码中,我们定义了_MainTex作为需要处理的图像,_BlurAmount作为模糊处理的强度参数。在SubShader中,我们定义了两个Pass,第一个用于将当前帧的图像保存到 RenderTexture 上,第二个Pass用于实现运动模糊的实际处理。同时,还添加了一个GrabPass,用于保存当前帧的图像。

四、示例代码

下面是一个实际的示例代码,用于实现一个简单的运动模糊效果:

Camera m_Camera;
RenderTexture m_PrevFrameTexture;
RenderTexture m_CurrentFrameTexture;
Shader m_MotionShader;

private void Start() {
    m_Camera = GetComponent<Camera>();
    m_PrevFrameTexture = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.ARGB32);
    m_CurrentFrameTexture = new RenderTexture(Screen.width, Screen.height, 0, RenderTextureFormat.ARGB32);
    m_Camera.targetTexture = m_CurrentFrameTexture;
    m_MotionShader = Shader.Find("Custom/MotionBlurShader");
}

private void OnRenderImage(RenderTexture src, RenderTexture dest) {
    m_MotionShader.SetFloat("_BlurAmount", 0.9f);
    Graphics.Blit(src, m_PrevFrameTexture);
    Graphics.Blit(m_CurrentFrameTexture, m_CurrentFrameTexture, m_MotionShader);
    Graphics.Blit(m_CurrentFrameTexture, dest);
}

在代码中,我们首先定义了需要使用的Camera对象、前一帧和当前帧的RenderTexture对象、运动模糊所需的 Shader 对象。在Start()中,我们对前一帧和当前帧的RenderTexture对象进行初始化,并将其绑定到Camera的 targetTexture 上,避免影响到其它渲染内容。在OnRenderImage()回调函数中,我们通过Graphics.Blit()函数进行渲染处理。具体来说,我们首先使用Graphics.Blit()函数对图像进行复制(第一次用),然后再使用Graphics.Blit()函数将当前帧图像绘制到RenderTexture上,并应用运动模糊 m_MotionShader。最后我们将处理结果输出。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:UnityShader使用图像叠加实现运动模糊 - Python技术站

(0)
上一篇 2023年6月3日
下一篇 2023年6月3日

相关文章

  • .NET Core跨平台串口通讯使用SerialPortStream基础类库问题解决

    .NET Core跨平台串口通讯使用SerialPortStream基础类库问题解决 串口通讯在很多行业应用中都有着重要的地位,而串口通讯的跨平台解决方案在.NET Core 3.0之后,就有了更好的支持。本文将介绍如何使用SerialPortStream基础类库进行.NET Core跨平台串口通讯,并解决其中的常见问题。 安装SerialPortStrea…

    C# 2023年6月3日
    00
  • C#多线程TPL常见操作误区与异常处理

    C#多线程TPL常见操作误区与异常处理 前言 随着计算机硬件性能的不断提升,多线程编程已经成为了现代程序设计的重要组成部分。而C#作为现代编程语言之一,它自身所提供的多线程处理库TPL(Task Parallel Library)也变得越来越重要。 然而,TPL虽然极为强大且易于使用,但在使用过程中仍存在一些常见的操作误区和异常情况,如果不注意会给系统带来严…

    C# 2023年5月15日
    00
  • 浅谈Java多线程实现及同步互斥通讯

    浅谈Java多线程实现及同步互斥通讯 引言 多线程是指一种多个线程执行完毕后可以得到更好的系统性能的机制。Java多线程的实现是通过创建Thread实例或者继承Thread类并重写它的run()方法来完成的。Java也提供了一个Java.util.concurrent包,它为Java多线程编程提供了更多的助力。在多线程编程中,同步互斥是一种非常重要的问题,它…

    C# 2023年6月7日
    00
  • C#短时间内产生大量不重复的随机数

    产生大量不重复的随机数需要满足两个条件:随机性和不重复性,下面就使用C#语言,给出一种实现这个目标的攻略。 第一步:定义一个列表 在产生随机数时,需要先定义一个列表,用来存储已经产生过的随机数。因为需要保证随机数不重复,这个列表会存储已经被产生的随机数,每次产生一个新的随机数时,需要和这个列表中的所有元素进行比较,以确保不重复。具体实现代码如下: List&…

    C# 2023年6月1日
    00
  • WPF实现图片合成或加水印的方法【2种方法】

    WPF实现图片合成或加水印的方法【2种方法】 在WPF中实现图片合成或加水印可以通过以下两种方法: 利用DrawImage方法进行图片合成; 通过混合模式来实现水印效果。 一、利用DrawImage方法进行图片合成 在WPF中,可以使用DrawImage方法将一张图片绘制到另一张图片上,实现图片的合成。具体步骤如下: 在XAML中添加一个Image控件,指定…

    C# 2023年6月7日
    00
  • C#设置与获取环境变量的方法详解

    C#设置与获取环境变量的方法详解 什么是环境变量 在计算机系统中,操作系统和应用程序都需要使用很多参数和选项,例如文件路径、可执行文件路径、系统配置参数等。管理这些参数和选项的重要方式之一就是通过环境变量。环境变量可以看作是全局的键值对,每个键值对都由一个名称和一个值组成,其中名称称为变量名,值则称为变量值。 设置与获取环境变量 设置环境变量 在C#中,可以…

    C# 2023年6月8日
    00
  • c#中WebService的介绍及调用方式小结

    当我们需要实现分布式计算、跨平台通信、不同语言之间的数据交换和信息共享等功能时,可以使用Web服务。Web服务是通过网络进行通信的应用程序组件,它使用标准的HTTP协议进行交互,通常是跨语言和跨平台的。本文将介绍C#中Web服务的概念、使用方法和调用方式。 什么是Web服务 Web服务(Web Service)是一种基于Web的应用程序组件,是独立于操作系统…

    C# 2023年6月7日
    00
  • C# 禁止应用程序多次启动的实例

    C#应用程序在默认情况下可以被多次启动的实例。但有些应用程序需要保证只能启动一个实例,可以通过以下两种方式来实现该需求。 方法一:使用 Mutex 对象控制应用程序启动 Mutex 对象是一种操作系统原语,可控制多个进程或线程执行特定代码的互斥访问。应用程序可以使用 Mutex 类来创建一个已命名的 Mutex 对象,并在不同进程之间共享该对象。当有一个进程…

    C# 2023年5月15日
    00
合作推广
合作推广
分享本页
返回顶部