[Unity]树的动态合批

2019/12 31 12:12
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

class UwPlantInsDatas
{
    private List<Matrix4x4> mMat44 = new List<Matrix4x4>();
    public List<Matrix4x4[]> mTransData = new List<Matrix4x4[]>();
	public Mesh mMesh;
	public Material mMaterial;

    public int Init(string assetPath)
    {
        GameObject template = ResourceMgr.Load(assetPath, "plants") as GameObject;
        if (template == null)
        {
            return -1;
        }

        var mrs = template.GetComponentsInChildren<MeshRenderer>();
        if (mrs == null || mrs.Length == 0)
        {
            return -2;
        }

        var mr= mrs[0];
        if (mr == null)
        {
            return -3;
        }

        if (!mr.sharedMaterial.enableInstancing)
        {
            return -4;
        }

        var mf = mr.gameObject.GetComponent<MeshFilter>();
        if (mf == null)
        {
            return -5; 
        }

        if (mf.sharedMesh == null)
        {
            return -6;
        }

        mMaterial = mr.sharedMaterial;
        mMesh = mf.sharedMesh;

        return 0;
    }

    public void Clear()
    {
        mTransData.Clear();
        mMat44.Clear();
    }

    public void Add(Clp_Transform trans, Vector3 pos)
    {
        Matrix4x4 mt = Matrix4x4.TRS(pos, Quaternion.Euler(trans.rotation), trans.scale);
        mMat44.Add(mt);
    }

    public void Submit()
    {
        var source = mMat44.ToArray();
        var sourceLen = source.Length;
        for(int i=0; i<100 && sourceLen > 0; ++i)
        {
            int len = sourceLen > 1023 ? 1023 : sourceLen;
            Matrix4x4[] dst = new Matrix4x4[len];
            System.Array.Copy(source, i*1023, dst, 0, len);
            sourceLen -= len;
            mTransData.Add(dst);
        }
    }

    public void Render()
    {
        for(int i=0; i<mTransData.Count; ++i)
        {
            Graphics.DrawMeshInstanced(mMesh, 0, mMaterial, mTransData[i]);
        }
    }
};

public class UwPlantInsManager
{
    private Dictionary<string, UwPlantInsDatas> mPlants = new Dictionary<string, UwPlantInsDatas>();

    public bool AddPlant(string assetPath, Clp_Transform data, Vector3 pos)
    {
        UwPlantInsDatas pid;
        if (!mPlants.TryGetValue(assetPath, out pid))
        {
            pid = new UwPlantInsDatas();
            var ret = pid.Init(assetPath);

            if (ret == 0)
            {
                mPlants.Add( assetPath, pid);
            }
            else
            {
                mPlants.Add( assetPath, null);
                pid = null;
            }
        }

        if (pid != null)
        {
            pid.Add(data, pos);
            return true;
        }

        return false;
    }

    public void RenderPlants()
    {
        foreach(var kv in mPlants)
        {
            var plant = kv.Value;
            if (plant != null)
            {
                plant.Render();
            }
        } 
    }

    public void SubmitPlants()
    {
        foreach(var kv in mPlants)
        {
            var plant = kv.Value;
            if (plant != null)
            {
                plant.Submit();
            }
        }
    }

    public void ClearPlants()
    {
        foreach(var kv in mPlants)
        {
            var plant = kv.Value;
            if (plant != null)
            {
                plant.Clear();
            }
        }
    }
};