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日

相关文章

  • C# 实现winform软件最小化到系统托盘,开机自启动

    C# 实现winform软件最小化到系统托盘,开机自启动   问题描述   用户的电脑是win7系统,应用系统在用户电脑上运行时部分功能需要访问注册表,但是使用这些功能时会提示用户没有权限访问注册表。原因分析   win7及后续高版本系统对用户的权限控制比较严,就算用户的权限较高,但用户启动程序时默认还是以普通用户的权限启动,因此造成应用程序访问操作系统相关…

    C# 2023年5月11日
    00
  • C#异步编程由浅入深(一)

    下面是“C#异步编程由浅入深(一)”完整攻略的讲解: 异步编程的定义 异步编程(Asynchronous Programming)是指在执行耗时操作时,允许其他操作同时执行的编程方式。它可以让主程序不被阻塞,提高程序的并发能力和响应性能。 异步编程的模型 C#中的异步编程采用任务(Task)模型,它由以下几部分组成: Task的定义 Task是一个基本的异步…

    C# 2023年6月6日
    00
  • C# Console.WriteLine()方法: 在控制台输出一行文本

    Console.WriteLine()的作用与使用方法 Console.WriteLine() 是 C# 语言中用来将数据输出到控制台窗口并自动换行的函数。它接收一个或多个参数,参数之间可以用逗号(,)分隔。该函数将每个参数转化为字符串并将它们输出到控制台窗口,并在其后面添加一个换行符(\n)。 使用方法 调用 Console.WriteLine() 函数有…

    C# 2023年4月19日
    00
  • C# SQLite事务操作方法分析

    C# SQLite事务操作方法分析 SQLite是一种轻型且功能强大的关系型数据库,它广泛应用于各种类型的应用程序开发中。在C#中操作SQLite数据库,我们通常会使用SQLite.Net这个开源库,它提供了很多便捷的操作方法。 在SQLite数据库中,事务(Transaction)是一组操作的集合,它们同步进行且被看作为一个单个的工作单元,要么都成功,要么…

    C# 2023年5月31日
    00
  • 总结C#处理异常的方式

    总结C#处理异常的方式有以下几种: 1. 使用try-catch块 try-catch块是最常用的处理异常的方式。这里是一个示例: try { int a = 10; int b = 0; int c = a / b; } catch (Exception ex) { Console.WriteLine("发生了异常:" + ex.Mes…

    C# 2023年5月15日
    00
  • C#引用类型转换的常见方式总结

    下面是关于C#引用类型转换的常见方式总结的攻略: 标题 C#引用类型转换的常见方式总结 简介 在C#中,我们经常需要进行引用类型的转换。本篇攻略将介绍引用类型转换的几种常见方式,并提供相应的示例,以便读者更好地理解和掌握。 显式类型转换 显式类型转换是指我们在代码中明确地将一个引用类型转换成另一个引用类型。常用的显式类型转换操作符为(type),其中type…

    C# 2023年5月15日
    00
  • C#请求http向网页发送接收数据的方法

    下面是“C#请求http向网页发送接收数据的方法”的完整攻略。 使用HttpClient发送HTTP请求 C#中可以使用HttpClient对象发送HTTP请求,该对象位于System.Net.Http命名空间中。 首先需要在C#项目中引入System.Net.Http命名空间: using System.Net.Http; 然后创建HttpClient对象…

    C# 2023年5月31日
    00
  • C# File.GetCreationTime(string path):获取指定文件的创建时间

    C#中的File.GetCreationTime(string path)方法可以用来获取指定文件或目录的创建时间。下面是这个方法的完整攻略: 方法签名 public static DateTime GetCreationTime(string path); 该方法的返回值为一个DateTime类型的对象,代表指定文件或目录的创建时间。 参数说明 path:…

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