直接上代码吧:
GhostShadowCreator.cs
using System.Collections.Generic;
using UnityEngine;
public class GhostShadowCreator : MonoBehaviour
{
[System.Serializable]
public class GhostShadowData
{
public string mAnimationName; //动画名字
public float mStartTime; //创建残影的开始时间,注意是动画的真实时间
public float mEndTime; //创建残影的结束时间
public float mHoldTime; //残影持续时间
public float mFreneselIntensity; //残影从中间到边缘的透明程度
public int mGhostShadowNum; //在开始和结束时间内创建多少个残影
public Color mBeginColor; //残影的起始颜色,注意alpha值一般设置为1
public Color mEndColor; //残影的结束颜色,alpha值设置为0
[System.NonSerialized]
public float mTiming;
public float createDelta
{
get
{
float differTime = mEndTime - mStartTime;
if(differTime > 0)
{
return differTime / mGhostShadowNum;
}
return 0;
}
}
}
public List<GhostShadowData> mGhostShadowAnimationList;
private Animation mAnimation;
void Start()
{
mAnimation = GetComponent<Animation>();
for (int i = 0; i < mGhostShadowAnimationList.Count; i++)
{
GhostShadowData data = mGhostShadowAnimationList[i];
AnimationEvent[] animationEvents = new AnimationEvent[data.mGhostShadowNum];
for(int j = 0; j < animationEvents.Length; j++)
{
animationEvents[j] = new AnimationEvent();
animationEvents[j].functionName = "CreateGhostShadow";
animationEvents[j].time = data.mStartTime + j * data.createDelta;
animationEvents[j].stringParameter = string.Format("chixushijian(s):{0};bianyuankuandu:{1};kaishiyanse(RGBA):{2},{3},{4},{5};jieshuyanse(RGBA):{6},{7},{8},{9}",
data.mHoldTime, data.mFreneselIntensity,
data.mBeginColor.r, data.mBeginColor.g, data.mBeginColor.b, data.mBeginColor.a,
data.mEndColor.r, data.mEndColor.g, data.mEndColor.b, data.mEndColor.a);
}
mAnimation[data.mAnimationName].clip.events = animationEvents;
}
}
public void CreateGhostShadow(string s)
{
//解析数据
float holdTime = 0;
float freneselIntensity = 0;
Vector4 beginColor = Vector4.zero;
Vector4 endColor = Vector4.zero;
string[] paramsList = s.Split(';');
for (int i = 0; i < paramsList.Length; i++)
{
string[] nameValueList = paramsList[i].Split(':');
switch (nameValueList[0])
{
case "chixushijian(s)":
{
holdTime = float.Parse(nameValueList[1]);
}
break;
case "bianyuankuandu":
{
freneselIntensity = float.Parse(nameValueList[1]);
}
break;
case "kaishiyanse(RGBA)":
{
beginColor = ParaseVector4(nameValueList[1]);
}
break;
case "jieshuyanse(RGBA)":
{
endColor = ParaseVector4(nameValueList[1]);
}
break;
}
}
GhostShadow.CreateGhostShadow(gameObject, holdTime, freneselIntensity, beginColor, endColor);
}
private static Vector4 ParaseVector4(string s)
{
//s格式:x,x,x,x
float x = 0;
float y = 0;
float z = 0;
float w = 0;
string[] valueList = s.Split(',');
if (valueList.Length == 4)
{
x = float.Parse(valueList[0]);
y = float.Parse(valueList[1]);
z = float.Parse(valueList[2]);
w = float.Parse(valueList[3]);
}
return new Vector4(x, y, z, w);
}
}
GhostShadow.cs
using System.Collections.Generic;
using UnityEngine;
public class GhostShadow : MonoBehaviour {
private List<Material> mMaterialList = new List<Material>();
private List<GameObject> mGhostShadowRemoveList = new List<GameObject>();
private float mHoldTime = 0.0f; //残影持续时间
private float mTotalTime = 0.0f;
private Vector4 mBeginColor = Vector4.zero;
private Vector4 mEndColor = Vector4.zero;
private float mFreneselIntensity = 0.0f;
private static AnimationState GetCurPlayAnimation(Animation animation)
{
foreach (AnimationState state in animation)
{
if (animation.IsPlaying(state.name))
{
return state;
}
}
return null;
}
public static void CreateGhostShadow(GameObject obj, float holdTime, float freneselIntensity, Vector4 beginColor, Vector4 endColor)
{
Animation animation = obj.GetComponentInChildren<Animation>();
if(animation == null)
{
return;
}
AnimationState curState = GetCurPlayAnimation(animation);
if (curState != null)
{
//clone对象
GameObject gsObj = Instantiate(obj);
gsObj.transform.parent = null;
gsObj.transform.name = obj.transform.name + "(GhostShadow)";
gsObj.transform.position = obj.transform.position;
gsObj.transform.rotation = obj.transform.rotation;
GhostShadowCreator gsc = gsObj.GetComponentInChildren<GhostShadowCreator>();
if(gsc != null)
{
gsc.enabled = false;
}
//初始化残影数据
GhostShadow gsScrpit = gsObj.AddComponent<GhostShadow>();
gsScrpit.SetHoldTime(holdTime);
gsScrpit.SetFreneselIntensity(freneselIntensity);
gsScrpit.SetBeginColor(beginColor);
gsScrpit.SetEndColor(endColor);
//定格动画
Animation gsAnimation = gsObj.GetComponentInChildren<Animation>();
if (gsAnimation != null)
{
gsAnimation[curState.name].time = curState.time;
gsAnimation[curState.name].speed = 0;
gsAnimation.Play(curState.name);
}
}
}
// Use this for initialization
void Start () {
//改变残影对象的shader
Renderer[] gsRenderList = GetComponentsInChildren<Renderer>();
if(gsRenderList != null)
{
for (int i = 0; i < gsRenderList.Length; i++)
{
Material material = new Material(Shader.Find("Custom/GhostShadow"));
gsRenderList[i].material = material;
material.SetFloat("_freneselIntensity", mFreneselIntensity);
mMaterialList.Add(material);
}
}
}
//设置残影持续时间
void SetHoldTime(float holdTime)
{
mHoldTime = holdTime;
}
//设置起始颜色
void SetBeginColor(Vector4 color)
{
mBeginColor = color;
}
//设置结束颜色
void SetEndColor(Vector4 color)
{
mEndColor = color;
}
//设置菲尼尔的强度
void SetFreneselIntensity(float intensity)
{
mFreneselIntensity = intensity;
}
// Update is called once per frame
void Update () {
mTotalTime += Time.deltaTime;
for (int i = 0; i < mMaterialList.Count; i++)
{
Vector4 color = Vector4.Lerp(mBeginColor, mEndColor, Mathf.Min(mTotalTime / mHoldTime, 1.0f));
mMaterialList[i].SetVector("_color", color);
if(mTotalTime >= mHoldTime)
{
mGhostShadowRemoveList.Add(gameObject);
}
}
int removeNum = mGhostShadowRemoveList.Count;
if (removeNum > 0)
{
for (int i = 0; i < removeNum; i++)
{
GameObject.DestroyImmediate(mGhostShadowRemoveList[i]);
}
mGhostShadowRemoveList.Clear();
}
}
}
GhostShadow.shader
// Upgrade NOTE: replaced '_World2Object' with 'unity_WorldToObject'
Shader "Custom/GhostShadow"
{
Properties
{
_color("_color", Color) = (0.0, 0.0, 0.0, 0.0)
_freneselIntensity("freneselIntensity", float) = 1.0
}
SubShader
{
Tags
{
"Queue" = "Transparent"
"RenderType" = "Transparent"
"IngoreProjector" = "True"
}
Pass
{
ZTest On
ZWrite Off
Blend SrcAlpha OneMinusSrcAlpha
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct a2v
{
float4 pos : POSITION;
float3 normal : NORMAL;
};
struct v2f
{
float4 pos : SV_POSITION;
float3 normal : TEXCOORD0;
float3 viewDir : TEXCOORD1;
};
float4 _color;
float _freneselIntensity;
v2f vert(a2v i )
{
v2f o;
o.pos = UnityObjectToClipPos(i.pos);
o.normal = mul(i.normal, (float3x3)unity_WorldToObject);
o.viewDir = WorldSpaceViewDir(i.pos);
return o;
}
fixed4 frag(v2f i) : SV_Target
{
float fresnel = 1 - dot(normalize(i.normal), normalize(i.viewDir));
_color.a = _color.a * pow(fresnel, _freneselIntensity);
return _color;
}
ENDCG
}
}
}
说明: 把GhostShadowCreator.cs 脚本挂在人物上有Animation的组件的obj上,然后在面板上填入各种参数即可,本质上是添加动画事件到特定时间点上,创建残影。