下面是详细讲解"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技术站