Unity 残影

直接上代码吧:

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上,然后在面板上填入各种参数即可,本质上是添加动画事件到特定时间点上,创建残影。

猜你喜欢

转载自blog.csdn.net/qweewqpkn/article/details/79274659