Unity-残影效果实现

     以下使用Unity2017.4.10 + VS2017

==================================================================================================     角色资源包为Asset Store -> Unity Chan的角色包,接下来我们会使用这个Modle来进行操作

为了方便查看,我们首先进入FaceUpdate 这个脚本,把OnGUI全部注释,

================================================================================================    首先,我们来了解一下什么是网格:网格其实就是一堆顶点,按照不同的连接方式所组成大小,旋转各不相同的三角面,而将这些三角面组合在一起,我们才可以看到各种各样的模型,而网格在Unity中的组件名称为 MeshRenderer

而在我们做出动画的时候,网格是在不断改变绘制的,所以,我们可以在代码中保存动画特定帧数的网格数据,将其渲染到一个空物体上,之后我们动态生成的网格材质随时间渐变为透明。

================================================================================================

public class SkinMeshT : MonoBehaviour
{
    // 定义一个蒙皮网格数组,蒙皮网格继承自MeshRenderer的
    private SkinnedMeshRenderer[] skinMesh; 

    void Start()
    {
        // 通过Unity自带的方法 递归获取物体及其子物体上的网格实例
        skinMesh = transform.GetComponentsInChildren<SkinnedMeshRenderer>(); 
    }
     void Update()
    {
        // 这个很长的语句是 UnityChanControlScriptWithRgidBody 里面的轴控制 
        IsRunning = (transform.parent.GetComponent<UnityChanControlScriptWithRgidBody>().h == 0 ? false : true) || (transform.parent.GetComponent<UnityChanControlScriptWithRgidBody>().v == 0 ? false : true) ? true : false;
        if (IsRunning)
        {
            Plays();
        }    
    }
}

/////

    private void Plays()
    {
        for (int i = 0; i < skinMesh.Length; i++)
        {
            Mesh mesh = new Mesh();
            skinMesh[i].BakeMesh(mesh); // 烘焙网格数据到我们创建的空Mesh中
            GameObject t = new GameObject();
            MeshFilter mesh_ = t.AddComponent<MeshFilter>();
            MeshRenderer meshRenderer = t.AddComponent<MeshRenderer>();
            t.hideFlags = HideFlags.HideAndDontSave; // 我们创建的GameObject不会显示在Hierarchy面板上
            meshRenderer.material = skinMesh[i].material; // 给与材质
            t.AddComponent<DesT>(); // 这个是随时间消失 下面会介绍到
            mesh_.mesh = mesh;
            t.transform.position = skinMesh[i].transform.position; // 使网格坐标和旋转对其
            t.transform.rotation = skinMesh[i].transform.rotation;
        }
    }

/////

class DesT:MonoBehaviour{
    private float timer, rate = 0.50f;
    void Update()
    {
        timer += Time.deltaTime;
        if (timer > rate)
        {
             Destroy(this.gameobject);  
        }
    }
}

这样,当你把SkinMeshT挂载到UnityChan下面时,运行就会出现残影了,但是看一下我们上面的代码,貌似在IsRunning为True时,我们每帧需要都需要创建很多东西啊,所以,在着手写个对象池

SkinMeshT全部代码如下:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SkinMeshT : MonoBehaviour
{

    private SkinnedMeshRenderer[] skinMesh;

    void Start()
    {
        skinMesh = transform.GetComponentsInChildren<SkinnedMeshRenderer>();
    }
    bool IsRunning = false;
    public float timer, rate = 0.3f;
    void Update()
    {

        IsRunning = (transform.parent.GetComponent<UnityChanControlScriptWithRgidBody>().h == 0 ? false : true) || (transform.parent.GetComponent<UnityChanControlScriptWithRgidBody>().v == 0 ? false : true) ? true : false;
        if (IsRunning)
        {
            timer += Time.deltaTime;
            if (timer > rate)
            {
                timer = 0;
                Plays();
            }
        }
        else
        {
            timer = 0.3f;
        }

    }


    private void Plays()
    {
        for (int i = 0; i < skinMesh.Length; i++)
        {
            Mesh mesh = new Mesh();
            skinMesh[i].BakeMesh(mesh);
            GameObject t = ObjPool.Instance.TackOut("SkinMesh");
            MeshFilter mesh_ = null;
            MeshRenderer meshRenderer = null;
            if (t == null)
            {
                t = new GameObject();
                t.hideFlags = HideFlags.HideAndDontSave;
                mesh_ = t.AddComponent<MeshFilter>();
                meshRenderer = t.AddComponent<MeshRenderer>();
                meshRenderer.material = skinMesh[i].material;
                t.AddComponent<DesT>();
            }
            else
            {
                t.SetActive(true);
                mesh_ = t.GetComponent<MeshFilter>();
            }
            mesh_.mesh = mesh;
            t.transform.position = skinMesh[i].transform.position;
            t.transform.rotation = skinMesh[i].transform.rotation;
        }
    }
}

public class ObjPool
{
    private Dictionary<string, List<GameObject>> pool;
    private static ObjPool instance;
    public static ObjPool Instance
    {
        get
        {
            if (instance == null)
                instance = new ObjPool();
            return instance;
        }
    }
    private ObjPool()
    {
        pool = new Dictionary<string, List<GameObject>>();
    }

    public void Add(string name, GameObject o)
    {
        if (pool.ContainsKey(name))
        {
            pool[name].Add(o);
            return;
        }
        pool.Add(name, new List<GameObject>());
        pool[name].Add(o);
    }

    public GameObject TackOut(string name)
    {
        GameObject o = null;
        if (!pool.ContainsKey(name))
        {
            pool.Add(name, new List<GameObject>());
            return o;
        }
        if (pool[name].Count == 0)
        {
            return o;
        }
        o = pool[name][0];
        pool[name].RemoveAt(0);
        return o;
    }

}

---------------------------------------------------------------销毁(压入对象池)的全部代码----------------------------------------------------------------

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class DesT : MonoBehaviour
{
    private float alphaValue = 150;
    void Start()
    {
        
    }

    private void OnEnable()
    {
        GetComponent<MeshRenderer>().material.shader = Shader.Find("First Fantasy/Water/Water Diffuse");
        GetComponent<MeshRenderer>().material.SetFloat("_IsPlay", 1);
        GetComponent<MeshRenderer>().material.SetColor("_MainTexColor", new Color(1, 0, 0, alphaValue / 255));
        GetComponent<MeshRenderer>().material.SetFloat("_MainTexMultiply", 3.21f);
        gameObject.layer = LayerMask.NameToLayer("Temp");
        alphaValue = 150;
        timer = 0;
        GetComponent<MeshRenderer>().material.SetTexture("_MainTex", Resources.Load<Texture2D>("Mask"));
    }

    private float timer, rate = 0.50f;
    void Update()
    {
        timer += Time.deltaTime;
        alphaValue -= Time.deltaTime * 300;
        GetComponent<MeshRenderer>().material.SetColor("_MainTexColor", new Color(1, 0, 0,  alphaValue/ 255));
        if (timer > rate)
        {
            GetComponent<MeshRenderer>().material.SetFloat("_MainTexMultiply", 0);
            GetComponent<MeshRenderer>().material.SetColor("_MainTexColor", new Color(0, 0, 0, 0));
            gameObject.SetActive(false);
            ObjPool.Instance.Add("SkinMesh",this.gameObject);
            return;
        }
    }
}

-------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Shader代码如下,(PS:这个Shader忘记是从哪个包里面找到的了,我魔改了一下,加了个Alpha和UV流转控制)

Shader "First Fantasy/Water/Water Diffuse" {
	Properties {
		_MainTex ("Base (RGB)", 2D) = "white" {}
		_MainTexColor ("Diffuse", Color) = (1,1,1,0.55)  
		_MainTexMultiply ("Multiply", Range(0,5)) = 1
		_MainTexMoveSpeedU ("U Move Speed", Range(-10,10)) = 0.5
		_MainTexMoveSpeedV ("V Move Speed", Range(-10,10)) = 0.5
		_IsPlay("Is Play A",Range(0,1)) = 0
		_LightStrength("Light Strength",Range(-1,1)) = 0
	}
	SubShader {
		Tags {"IgnoreProjector"="True" "Queue"="Transparent"} 
		ZWrite Off
		Alphatest Greater 0
		Blend SrcAlpha OneMinusSrcAlpha 
		LOD 200

		CGPROGRAM
		#pragma surface surf Lambert alpha

		sampler2D _MainTex;
		fixed4 _MainTexColor; 
		fixed _MainTexMultiply;
		fixed _MainTexMoveSpeedU;
		fixed _MainTexMoveSpeedV;
		float _IsPlay;
		float _LightStrength;
		struct Input {
			float2 uv_MainTex;
		};

		void surf (Input IN, inout SurfaceOutput o) { 
		
			fixed2 MainTexMoveScrolledUV = IN.uv_MainTex;

			fixed MainTexMoveU = _MainTexMoveSpeedU * _Time * _IsPlay;
			fixed MainTexMoveV = _MainTexMoveSpeedV * _Time * _IsPlay;

			MainTexMoveScrolledUV += fixed2(MainTexMoveU, MainTexMoveV);
		
			half4 c = tex2D (_MainTex, MainTexMoveScrolledUV);
			o.Albedo = c.rgb * _MainTexColor * _MainTexMultiply + _LightStrength;
			o.Alpha = _MainTexColor.a;
		}
		ENDCG
	} 
	FallBack "Diffuse" 
}

其实Shader的话,Unity自带的Diffuse有Fade,所以应该也可以使用(PS:我没有实验)

效果如下,:

参考Blog : https://blog.csdn.net/x__dream/article/details/50571427

全部资源包下载:https://download.csdn.net/download/mikulingsss/10671859

猜你喜欢

转载自blog.csdn.net/MikuLingSSS/article/details/82738229