Unity人物残影实现

一.最近学习unity看到一个关于人物残影的实现过程,在这里记一下,大概原理就是
通过获取人物的SkinnedMeshRenderer组件,然后将其中重要的材质和Mesh赋值给新创建的Gameobject物体上,然后设置淡出效果,按生存周期销毁gameobject就好了;
详细的看代码吧;
为人物添加脚本:(脚本中设有注释就不多说了)
<span style="font-size:18px;">using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public class DestroyShadow : MonoBehaviour {
    public float interval = 0.1f;   //残影的时间间隔;
    public float lifeCycle = 2f;     //残影的生存周期
    float lastCombineTime = 0.0f;   //上次组合时间;
    MeshFilter[] meshFilters = null;
    SkinnedMeshRenderer[] skinnedMeshRenderers = null;
    List<GameObject> objs = new List<GameObject>();

 // Use this for initialization
 void Start () {
        meshFilters = gameObject.GetComponentsInChildren<MeshFilter>();
        skinnedMeshRenderers = gameObject.GetComponentsInChildren<SkinnedMeshRenderer>();

 }
    void OnDisable()
    {
        foreach (GameObject go in objs)
        {
            DestroyImmediate(go);
        }
        objs.Clear();
        objs = null;
    }
    // Update is called once per frame
    void Update () {
        if (Time.time - lastCombineTime > interval)
        {
            lastCombineTime = Time.time;
            for (int i = 0; skinnedMeshRenderers != null && i < skinnedMeshRenderers.Length; ++i)//遍历skinedMeshRenderers
            {
                Mesh mesh = new Mesh();
                skinnedMeshRenderers[i].BakeMesh(mesh);       //烘焙到新生成的mesh
                GameObject go = new GameObject();    //生成新的gameobject
                go.hideFlags = HideFlags.HideAndDontSave;   //设置go的属性隐藏不保存
                MeshFilter meshFilter = go.AddComponent<MeshFilter>();   //添加meshFilter组件
                meshFilter.mesh = mesh;  //将新添加的meshFilter设置为Mesh;
                MeshRenderer meshRender = go.AddComponent<MeshRenderer>();  //添加meshRenderer组件;
                meshRender.material = skinnedMeshRenderers[i].material;   //将新添加的MeshRenderer的材质设置为获取到的材质;


                InitFadeInObj(go, skinnedMeshRenderers[i].transform.position,
                    skinnedMeshRenderers[i].transform.rotation, lifeCycle); //淡入淡出
            }
            for (int i = 0; meshFilters != null && meshFilters.Length > 0; ++i)
            {
                GameObject go = Instantiate(meshFilters[i].gameObject) as GameObject;
                InitFadeInObj(go, meshFilters[i].transform.position, 
                    meshFilters[i].transform.rotation, lifeCycle); //新生成GameObject并且将其设置淡入淡出
            }
        }
    }

    private void InitFadeInObj(GameObject go, Vector3 position, Quaternion rotation, float lifeCycle)
    {
        go.hideFlags = HideFlags.HideAndDontSave;   //设置go的属性隐藏不保存;
        go.transform.position = position;
        go.transform.rotation = rotation;
        FindInOut fi = go.AddComponent<FindInOut>();//添加FadInOut脚本
        fi.lifeStytle = lifeCycle;//复制生命周期
        objs.Add(go);//放入列表中
    }

}</span>


二.在写个脚本,此脚本无需绑定;(由于对Shader不太了解,所以用的都是Unity自带的Shader,没有淡出效果,如果需要的话直接改改就好了)
<span style="font-size:18px;">using UnityEngine;
using System.Collections;

public class FindInOut : MonoBehaviour {
    public float lifeStytle = 2f;
    float startTime;
    Material mat = null;

 // Use this for initialization
 void Start () {
        startTime = Time.time;  //得到启动时间

        MeshRenderer meshRender = GetComponent<MeshRenderer>();
        if (!meshRender || !meshRender.material)
        {
            base.enabled = false;  //为空的话禁用;
        }
        else {
            mat = meshRender.material;  //得到材质;
            ReplaceShader();           //替换Shader
        }
 }
 
 // Update is called once per frame
 void Update () {

        float time = Time.time - startTime;  //获取运行时间;
        if (time > lifeStytle)
        {
            DestroyImmediate(gameObject);
        }
        else {
            float remainderTime = lifeStytle - time;    //得到剩余时间
            if (mat)
            {
                    //if(mat.HasProperty("_Color"))   得到mat中是否有这个属性
                    Color col = mat.GetColor("Tint");  //得到材质中的shader中的_Color颜色
                    col.a = remainderTime;//设置Alpha(剩余时间越小 Alpha值越小)
                    mat.SetColor("Tint", col);//将修改后的颜色设置回去

                col = mat.GetColor("Tint");//原理同上
                col.a = remainderTime;
                mat.SetColor("Tint", col);
            }
          }
        }
    private void ReplaceShader()
    {
        if (mat.shader.name.Equals("Unlit/Transparent"))//检查当前shader名字是否是“ ”
        {
            mat.shader = Shader.Find("Particles/Additive");//如果是的话 替换shader
        }
        else if (mat.shader.name.Equals("Sprites/Default"))
        {
            mat.shader = Shader.Find("Particles/Additive(Soft)");
        }
        else
        {
            Debug.LogError("Can't find target shader");
        }
    }
}
</span>

上面的方法太消耗性能了,下面更新下最近新学的简单点的

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

public class ShowShadowTail : MonoBehaviour {
    public float fadeSpeed = 3;
    public float createSpeed = 5;
    private float previousTime = 0;
    private SkinnedMeshRenderer []meshRender;
    private MeshFilter []meshFilter;
	void Awake()
    {
        meshRender = this.GetComponentsInChildren<SkinnedMeshRenderer>();
        meshFilter = this.GetComponentsInChildren<MeshFilter>();
    }
    struct MeshInfo {
        public Mesh mesh;
        public Matrix4x4 _matrix_PR; //存儲位置和旋转角度;
        public Material material;
    };
    List<MeshInfo> meshInfoList = new List<MeshInfo>();
	void Update () {
        foreach(MeshInfo meshInfo in meshInfoList)
        {
            Graphics.DrawMesh(meshInfo.mesh,meshInfo._matrix_PR,meshInfo.material,gameObject.layer);
            float timer= meshInfo.material.GetFloat("_Alpha") - Time.deltaTime* fadeSpeed;
            meshInfo.material.SetFloat("_Alpha",timer>0?timer:0);
            if(meshInfo.material.GetFloat("_Alpha")<0)
            {
                meshInfoList.Remove(meshInfo);
            }
        }
        if(Time.time-previousTime>createSpeed*Time.deltaTime)
        {
            previousTime = Time.time;
            foreach (SkinnedMeshRenderer meshRender in meshRender)
            {
                Mesh mesh = new Mesh();
                meshRender.BakeMesh(mesh);
                MeshInfo meshInfo = new MeshInfo();
                meshInfo.mesh = mesh;
                meshInfo._matrix_PR = meshRender.localToWorldMatrix;
                meshInfo.material = new Material(Shader.Find("Unlit/GrabGlass"));
                meshInfoList.Add(meshInfo);
            }
            foreach (MeshFilter filter in meshFilter)
            {
                MeshInfo meshInfo = new MeshInfo();
                meshInfo.mesh = filter.mesh;
                meshInfo._matrix_PR = filter.transform.localToWorldMatrix;
                meshInfo.material = new Material(Shader.Find("Unlit/GrabGlass"));
                meshInfoList.Add(meshInfo);
            }
        }
        
	}
}


最近人变懒了,只想上代码,多余的字都不想写了,唉!不足之处望指出,大家共同进步!!!

根据提供的引用内容,可以通过使用Unity的Shader来实现物体的残影效果。在后处理阶段,可以通过给残影的Texture乘以一个颜色来修改残影的颜色。这种效果可以由代码控制,但是如果是人物的话,残影将没有动画记录功能,所有的残影都会是相同的形状。 以下是一个示例的Unity Shader代码,用于实现物体的残影效果: ```shader Shader "Custom/TrailShader" { Properties { _MainTex ("Main Texture", 2D) = "white" {} _Color ("Color", Color) = (1,1,1,1) _TrailColor ("Trail Color", Color) = (1,1,1,1) _TrailLength ("Trail Length", Range(0, 1)) = 0.5 } SubShader { Tags { "RenderType"="Opaque" } LOD 200 CGPROGRAM #pragma surface surf Lambert sampler2D _MainTex; fixed4 _Color; fixed4 _TrailColor; float _TrailLength; struct Input { float2 uv_MainTex; }; void surf (Input IN, inout SurfaceOutput o) { fixed4 c = tex2D(_MainTex, IN.uv_MainTex) * _Color; o.Albedo = c.rgb; o.Alpha = c.a; // 计算残影的颜色 fixed4 trailColor = _TrailColor * _Color; // 计算残影的透明度 float trailAlpha = o.Alpha * _TrailLength; // 输出残影颜色和透明度 o.Emission = trailColor.rgb * trailAlpha; o.Alpha = trailAlpha; } ENDCG } FallBack "Diffuse" } ``` 这个Shader使用了_MainTex作为主纹理,_Color作为物体的颜色,_TrailColor作为残影的颜色,_TrailLength控制残影的长度。在surf函数中,通过计算残影的颜色和透明度,并将其输出到Emission和Alpha通道中,实现了物体的残影效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值