Shader教程:如何实现运动模糊
发表于2018-03-28
在一些游戏项目中有时候需要通过shader实现运动模糊效果,考虑到有些新手缺乏这方面的开发技巧,下面本篇文章主要是和大家分享下运动模糊的实现,并将实现代码一起奉上。
代码如下:
using UnityEngine;
using System.Collections;
[ExecuteInEditMode]
[RequireComponent (typeof(Camera))]
public class PostEffectsBase : MonoBehaviour {
protected void Start() {
CheckResources();
}
// Called when start
protected void CheckResources() {
bool isSupported = CheckSupport();
if (isSupported == false) {
NotSupported();
}
}
// Called in CheckResources to check support on this platform
protected bool CheckSupport() {
if (SystemInfo.supportsImageEffects == false || SystemInfo.supportsRenderTextures == false) {
Debug.LogWarning("This platform does not support image effects or render textures.");
return false;
}
return true;
}
// Called when the platform doesn't support this effect
protected void NotSupported() {
enabled = false;
}
// Called when need to create the material used by this effect
protected Material CheckShaderAndCreateMaterial(Shader shader, Material material) {
if (shader == null) {
return null;
}
if (shader.isSupported && material && material.shader == shader)
return material;
if (!shader.isSupported) {
return null;
}
else {
material = new Material(shader);
material.hideFlags = HideFlags.DontSave;
if (material)
return material;
else
return null;
}
}
}
using UnityEngine;
using System.Collections;
public class MotionBlur : PostEffectsBase {
public Shader motionBlurShader;
private Material motionBlurMaterial = null;
public Material material {
get {
motionBlurMaterial = CheckShaderAndCreateMaterial(motionBlurShader, motionBlurMaterial);
return motionBlurMaterial;
}
}
[Range(0.0f, 0.9f)]
public float blurAmount = 0.5f;
private RenderTexture accumulationTexture;
void OnDisable() {
DestroyImmediate(accumulationTexture);
}
void OnRenderImage (RenderTexture src, RenderTexture dest) {
if (material != null) {
if (accumulationTexture == null || accumulationTexture.width != src.width || accumulationTexture.height != src.height) {
DestroyImmediate(accumulationTexture);
accumulationTexture = new RenderTexture(src.width, src.height, 0);
// 不显示到面板上也不会保存
accumulationTexture.hideFlags = HideFlags.HideAndDontSave;
// 当前src
Graphics.Blit(src, accumulationTexture);
}
// 表示需要进行渲染纹理恢复操作
// 发生在渲染到渲染纹理而该纹理又没有被提前清空或者销毁的情况下
accumulationTexture.MarkRestoreExpected();
material.SetFloat("_BlurAmount", 1.0f - blurAmount);
Graphics.Blit (src, accumulationTexture, material);
Graphics.Blit (accumulationTexture, dest);
} else {
Graphics.Blit(src, dest);
}
}
}
Shader "Motion Blur" {
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 = mul(UNITY_MATRIX_MVP, v.vertex);
// uv坐标
o.uv = v.texcoord;
return o;
}
ENDCG
// 避免对后面的渲染造成影响
ZTest Always
Cull Off
ZWrite Off
// RGB 通道
Pass {
Blend SrcAlpha OneMinusSrcAlpha
ColorMask RGB
CGPROGRAM
#pragma vertex vert
#pragma fragment fragRGB
fixed4 fragRGB (v2f i) : SV_Target {
return fixed4(tex2D(_MainTex, i.uv).rgb, _BlurAmount);
}
ENDCG
}
// A 通道
Pass {
Blend One Zero
ColorMask A
CGPROGRAM
#pragma vertex vert
#pragma fragment fragA
half4 fragA (v2f i) : SV_Target {
return tex2D(_MainTex, i.uv);
}
ENDCG
}
}
FallBack Off
}
