【Unity】基於SpriteRenderer的殘影/幻影

借鑑了這位dalao的方案

通過Sprite渲染meshhttp://tsubakit1.hateblo.jp/entry/2018/04/18/234424

 

思路:

獲取遊戲對象下的所有Sprite

通過Sprite渲染mesh

 

用到的繪製API

//緩衝命令實例

CommandBuffer

//在transform.position下繪製一個mesh,mat:材質

commandBuffer.DrawMesh(mseh, Matrix4x4.TRS(transform.position, Quaternion.identity, Vector3.one),mat)

 

API

//清空攝像機的所有Buffers ,簡單來所就是清空所有使用AddCommandBuffer繪製

Camera.main.RemoveAllCommandBuffers();

//添加一個緩衝Buffer

Camera.main.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, buffer,0, 0, propertyBlock);

 

最後上代碼:

Afterimage.cs

using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using UnityEngine.Rendering;


[Serializable]
public struct AfterimageMatrix4x4
{
    public Vector3 position;
    public Quaternion rotation;
    public Vector3 localScale;

    public Sprite sprite;
    public Material material;

    public AfterimageMatrix4x4(Vector3 position, Quaternion rotation, Vector3 localScale, Sprite sprite, Material material)
    {
        this.position = position;
        this.rotation = rotation;
        this.localScale = localScale;
        this.sprite = sprite;
        this.material = material;
    }


}

/// <summary>
/// 一個幻影的數據
/// </summary>
public class AfterimageData
{
    public List<AfterimageMatrix4x4> AM4x4List = new List<AfterimageMatrix4x4>();
    public Color color = Color.white;
    public float live;
}


/// <summary>
/// 基於SpriteRenderer的幻影插件,可以用於2D幻影
/// </summary>
public class Afterimage : MonoBehaviour
{

    List<SpriteRenderer> spriteList;



    private CommandBuffer buffer;

    private List<AfterimageData> AfterimageDataList = new List<AfterimageData>();

    private static int idMainTex = Shader.PropertyToID("_MainTex");

    private static int idColor = Shader.PropertyToID("_Color");


    private Vector3 lastPosition;

    public float spacing = 1;
    public float live = 0.2f;
    public Color color = Color.white;

    private void Awake()
    {
        SpriteRenderer[] collection = GetComponentsInChildren<SpriteRenderer>();
        spriteList = new List<SpriteRenderer>(collection);

        spriteList.Sort((x, y) =>
        {
            return x.sortingOrder - y.sortingOrder;
        });

    }

    private void Start()
    {
        lastPosition = transform.position;
    }



    private void Update()
    {

        for (int i = 0; i < AfterimageDataList.Count; i++)
        {
            AfterimageDataList[i].live -= Time.deltaTime;
            AfterimageDataList[i].color = new Color(AfterimageDataList[i].color.r, AfterimageDataList[i].color.g, AfterimageDataList[i].color.b, AfterimageDataList[i].live / live);
            if (AfterimageDataList[i].live < 0)
            {
                AfterimageDataList.RemoveAt(i);
                break;
            }

        }

        //數據刷新
        DataUptate();

        if (buffer != null)
        {
            Camera.main.RemoveCommandBuffer(CameraEvent.BeforeForwardAlpha, buffer);
        }



        //設置繪製數據
        DrawAfterimage(AfterimageDataList);

        if (buffer != null)
        {
            Camera.main.AddCommandBuffer(CameraEvent.BeforeForwardAlpha, buffer);
        }
    }

    /// <summary>
    /// 幻影數據刷新
    /// </summary>
    private void DataUptate()
    {

        if ((transform.position - lastPosition).magnitude < spacing)
        {
            return;
        }




        lastPosition = transform.position;


        AfterimageData afterimageData = new AfterimageData();
        //設置時間
        afterimageData.live = live;

        afterimageData.color = color;

        //遍歷所有精靈創建一個幻影
        for (int i = 0; i < spriteList.Count; i++)
        {
            var item = spriteList[i];
            //獲得當前精靈的信息
            AfterimageMatrix4x4 afterimageMatrix4X4 = new AfterimageMatrix4x4(
                item.transform.position,
                item.transform.rotation,
                item.transform.lossyScale,
                item.sprite,
                item.material);
            //添加當前精靈到幻影中
            afterimageData.AM4x4List.Add(afterimageMatrix4X4);


        }
        //將新的幻影添加到數據中
        AfterimageDataList.Add(afterimageData);

    }

    /// <summary>
    /// 繪製所有幻影
    /// </summary>
    /// <param name="afterimageDatas"></param>
    private void DrawAfterimage(List<AfterimageData> afterimageDatas)
    {
        buffer = new CommandBuffer();
        var propertyBlock = new MaterialPropertyBlock();


        for (int i = 0; i < afterimageDatas.Count; i++)
        {
            AfterimageData item = afterimageDatas[i];

            //繪製一張幻影
            //設置顏色
            propertyBlock.SetColor(idColor, item.color);
            //設置繪製數據
            DrawAfterimageItem(propertyBlock, item);
        }
    }

    /// <summary>
    /// 繪製一個幻影
    /// </summary>
    /// <param name="propertyBlock"></param>
    /// <param name="afterimageData"></param>
    private void DrawAfterimageItem(MaterialPropertyBlock propertyBlock, AfterimageData afterimageData)
    {
        for (int i = 0; i < afterimageData.AM4x4List.Count; i++)
        {
            AfterimageMatrix4x4 item = afterimageData.AM4x4List[i];

            //設置貼圖
            propertyBlock.SetTexture(idMainTex, item.sprite.texture);
            //獲得網格
            var mesh = SpriteToMesh(item.sprite);


            buffer.DrawMesh(mesh, Matrix4x4.TRS(item.position, item.rotation, item.localScale), item.material, 0, 0, propertyBlock);
        }
    }

    private Mesh SpriteToMesh(Sprite sprite)
    {
        var mesh = new Mesh();
        mesh.SetVertices(Array.ConvertAll(sprite.vertices, c => (Vector3)c).ToList());
        mesh.SetUVs(0, sprite.uv.ToList());
        mesh.SetTriangles(Array.ConvertAll(sprite.triangles, c => (int)c), 0);

        return mesh;
    }
}

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章