123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472 |
- using System.Collections;
- using System.Collections.Generic;
- using UnityEngine;
- namespace XftWeapon {
- public class XWeaponTrail : MonoBehaviour {
- public class Element {
- public Vector3 PointStart;
- public Vector3 PointEnd;
- public Vector3 Pos {
- get {
- return (PointStart + PointEnd) / 2f;
- }
- }
- public Element(Vector3 start, Vector3 end) {
- PointStart = start;
- PointEnd = end;
- }
- public Element() {
- }
- }
- public class ElementPool {
- private readonly Stack<Element> _stack = new Stack<Element>();
- public int CountAll { get; private set; }
- public int CountActive { get { return CountAll - CountInactive; } }
- public int CountInactive { get { return _stack.Count; } }
- public ElementPool(int preCount) {
- for (int i = 0; i < preCount; i++) {
- Element element = new Element();
- _stack.Push(element);
- CountAll++;
- }
- }
- public Element Get() {
- Element element;
- if (_stack.Count == 0) {
- element = new Element();
- CountAll++;
- } else {
- element = _stack.Pop();
- }
- return element;
- }
- public void Release(Element element) {
- if (_stack.Count > 0 && ReferenceEquals(_stack.Peek(), element)) {
- Debug.LogError("Internal error. Trying to destroy object that is already released to pool.");
- }
- _stack.Push(element);
- }
- }
- #region public members
- public static string Version = "1.4.3";
- public bool UseWith2D = false;
- public bool UseWithSRP = false;
- public string SortingLayerName;
- public int SortingOrder;
- public Transform PointStart;
- public Transform PointEnd;
- public int MaxFrame = 14;
- public int Granularity = 60;
- public float Fps = 60f;
- public Color MyColor = Color.white;
- public Material MyMaterial;
- #endregion
- #region protected members
- protected float mTrailWidth = 0f;
- protected Element mHeadElem = new Element();
- protected List<Element> mSnapshotList = new List<Element>();
- protected ElementPool mElemPool;
- protected Spline mSpline = new Spline();
- protected float mFadeT = 1f;
- protected bool mIsFading = false;
- protected float mFadeTime = 1f;
- protected float mElapsedTime = 0f;
- protected float mFadeElapsedime = 0f;
- protected GameObject mMeshObj;
- protected VertexPool mVertexPool;
- protected VertexPool.VertexSegment mVertexSegment;
- protected bool mInited = false;
- protected bool mActivated = false;
- #endregion
- #region property
- public float UpdateInterval {
- get {
- return 1f / Fps;
- }
- }
- public Vector3 CurHeadPos {
- get { return (PointStart.position + PointEnd.position) / 2f; }
- }
- public float TrailWidth {
- get {
- return mTrailWidth;
- }
- }
- protected Camera _myCamera;
- public Camera MyCamera {
- get {
- if (_myCamera == null) {
- _myCamera = FindMyCamera();
- }
- return _myCamera;
- }
- }
- protected Camera FindMyCamera() {
- int layerMask = 1 << gameObject.layer;
- //Camera[] cameras = GameObject.FindObjectsOfType(typeof(Camera)) as Camera[];
- Camera[] cameras = Camera.allCameras;
- for (int i = 0, imax = cameras.Length; i < imax; ++i) {
- Camera cam = cameras[i];
- if ((cam.cullingMask & layerMask) != 0) {
- return cam;
- }
- }
- Debug.LogError("can't find proper camera for layer:" + gameObject.layer);
- return null;
- }
- #endregion
- #region API
- //you may pre-init the trail to save some performance.
- public void Init() {
- if (mInited)
- return;
- mElemPool = new ElementPool(MaxFrame);
- mTrailWidth = (PointStart.position - PointEnd.position).magnitude;
- InitMeshObj();
- InitOriginalElements();
- InitSpline();
- mInited = true;
- }
- public void Activate() {
- if (mActivated) {
- return;
- }
- Init();
- mActivated = true;
- gameObject.SetActive(true);
- //mVertexPool.SetMeshObjectActive(true);
- mFadeT = 1f;
- mIsFading = false;
- mFadeTime = 1f;
- mFadeElapsedime = 0f;
- mElapsedTime = 0f;
- //reset all elemts to head pos.
- for (int i = 0; i < mSnapshotList.Count; i++) {
- mSnapshotList[i].PointStart = PointStart.position;
- mSnapshotList[i].PointEnd = PointEnd.position;
- mSpline.ControlPoints[i].Position = mSnapshotList[i].Pos;
- mSpline.ControlPoints[i].Normal = mSnapshotList[i].PointEnd - mSnapshotList[i].PointStart;
- }
- //reset vertex too.
- RefreshSpline();
- UpdateVertex();
- RefreshShader();
- }
- public void RefreshShader()
- {
- MyMaterial.shader = Shader.Find(MyMaterial.shader.name);
- }
- public void Deactivate() {
- mActivated = false;
- gameObject.SetActive(false);
- mVertexPool.SetMeshObjectActive(false);
- }
- public void StopSmoothly(float fadeTime) {
- mIsFading = true;
- mFadeTime = fadeTime;
- }
- #endregion
- #region unity methods
- void OnEnable() {
- Activate();
- if (!UseWithSRP) {
- Camera.onPostRender += MyPostRender;
- Camera.onPreRender += MyPreRender;
- }
- }
- void OnDisable() {
- // Deactivate();
- if (!UseWithSRP) {
- Camera.onPostRender -= MyPostRender;
- Camera.onPreRender -= MyPreRender;
- }
- }
- // void Update() {
- // if (!UseWithSRP) {
- // return;
- // }
- // MyPreRender(MyCamera);
- // }
- void LateUpdate() {
- if (!UseWithSRP) {
- return;
- }
- MyPreRender(MyCamera);
- MyPostRender(MyCamera);
- }
- public void MyPreRender(Camera cam) {
- if (!mInited)
- return;
- if (cam != MyCamera) {
- return;
- }
- UpdateHeadElem();
- mElapsedTime += Time.deltaTime;
- if (mElapsedTime > UpdateInterval) {
- mElapsedTime = 0f;
- RecordCurElem();
- }
- RefreshSpline();
- UpdateFade();
- UpdateVertex();
- }
- public void MyPostRender(Camera cam) {
- if (!mInited)
- return;
- if (cam != MyCamera) {
- return;
- }
- mVertexPool.SetMeshObjectActive(true);
- mVertexPool.LateUpdate();
- }
- void OnDestroy() {
- if (!mInited || mVertexPool == null) {
- return;
- }
- mVertexPool.Destroy();
- }
- void Start() {
- mInited = false;
- Init();
- }
- void OnDrawGizmos() {
- if (PointEnd == null || PointStart == null) {
- return;
- }
- float dist = (PointStart.position - PointEnd.position).magnitude;
- if (dist < Mathf.Epsilon)
- return;
- Gizmos.color = Color.red;
- Gizmos.DrawSphere(PointStart.position, dist * 0.04f);
- Gizmos.color = Color.blue;
- Gizmos.DrawSphere(PointEnd.position, dist * 0.04f);
- }
- #endregion
- #region local methods
- void InitSpline() {
- mSpline.Granularity = Granularity;
- mSpline.Clear();
- for (int i = 0; i < MaxFrame; i++) {
- mSpline.AddControlPoint(CurHeadPos, PointStart.position - PointEnd.position);
- }
- }
- void RefreshSpline() {
- for (int i = 0; i < mSnapshotList.Count; i++) {
- mSpline.ControlPoints[i].Position = mSnapshotList[i].Pos;
- mSpline.ControlPoints[i].Normal = mSnapshotList[i].PointEnd - mSnapshotList[i].PointStart;
- }
- mSpline.RefreshSpline();
- }
- void UpdateVertex() {
- VertexPool pool = mVertexSegment.Pool;
- for (int i = 0; i < Granularity; i++) {
- int baseIdx = mVertexSegment.VertStart + i * 3;
- float uvSegment = (float) i / Granularity;
- float fadeT = uvSegment * mFadeT;
- Vector2 uvCoord = Vector2.zero;
- Vector3 pos = mSpline.InterpolateByLen(fadeT);
- //Debug.DrawRay(pos, Vector3.up, Color.red);
- Vector3 up = mSpline.InterpolateNormalByLen(fadeT);
- Vector3 pos0 = pos + (up.normalized * mTrailWidth * 0.5f);
- Vector3 pos1 = pos - (up.normalized * mTrailWidth * 0.5f);
- // pos0
- pool.Vertices[baseIdx] = pos0;
- pool.Colors[baseIdx] = MyColor;
- uvCoord.x = 0f;
- uvCoord.y = uvSegment;
- pool.UVs[baseIdx] = uvCoord;
- //pos
- pool.Vertices[baseIdx + 1] = pos;
- pool.Colors[baseIdx + 1] = MyColor;
- uvCoord.x = 0.5f;
- uvCoord.y = uvSegment;
- pool.UVs[baseIdx + 1] = uvCoord;
- //pos1
- pool.Vertices[baseIdx + 2] = pos1;
- pool.Colors[baseIdx + 2] = MyColor;
- uvCoord.x = 1f;
- uvCoord.y = uvSegment;
- pool.UVs[baseIdx + 2] = uvCoord;
- }
- mVertexSegment.Pool.UVChanged = true;
- mVertexSegment.Pool.VertChanged = true;
- mVertexSegment.Pool.ColorChanged = true;
- }
- void UpdateIndices() {
- VertexPool pool = mVertexSegment.Pool;
- for (int i = 0; i < Granularity - 1; i++) {
- int baseIdx = mVertexSegment.VertStart + i * 3;
- int nextBaseIdx = mVertexSegment.VertStart + (i + 1) * 3;
- int iidx = mVertexSegment.IndexStart + i * 12;
- //triangle left
- pool.Indices[iidx + 0] = nextBaseIdx;
- pool.Indices[iidx + 1] = nextBaseIdx + 1;
- pool.Indices[iidx + 2] = baseIdx;
- pool.Indices[iidx + 3] = nextBaseIdx + 1;
- pool.Indices[iidx + 4] = baseIdx + 1;
- pool.Indices[iidx + 5] = baseIdx;
- //triangle right
- pool.Indices[iidx + 6] = nextBaseIdx + 1;
- pool.Indices[iidx + 7] = nextBaseIdx + 2;
- pool.Indices[iidx + 8] = baseIdx + 1;
- pool.Indices[iidx + 9] = nextBaseIdx + 2;
- pool.Indices[iidx + 10] = baseIdx + 2;
- pool.Indices[iidx + 11] = baseIdx + 1;
- }
- pool.IndiceChanged = true;
- }
- void UpdateHeadElem() {
- mSnapshotList[0].PointStart = PointStart.position;
- mSnapshotList[0].PointEnd = PointEnd.position;
- }
- void UpdateFade() {
- if (!mIsFading)
- return;
- mFadeElapsedime += Time.deltaTime;
- float t = mFadeElapsedime / mFadeTime;
- mFadeT = 1f - t;
- if (mFadeT < 0f) {
- Deactivate();
- }
- }
- void RecordCurElem() {
- //TODO: use element pool to avoid gc alloc.
- //Element elem = new Element(PointStart.position, PointEnd.position);
- Element elem = mElemPool.Get();
- elem.PointStart = PointStart.position;
- elem.PointEnd = PointEnd.position;
- if (mSnapshotList.Count < MaxFrame) {
- mSnapshotList.Insert(1, elem);
- } else {
- mElemPool.Release(mSnapshotList[mSnapshotList.Count - 1]);
- mSnapshotList.RemoveAt(mSnapshotList.Count - 1);
- mSnapshotList.Insert(1, elem);
- }
- }
- void InitOriginalElements() {
- mSnapshotList.Clear();
- //at least add 2 original elements
- mSnapshotList.Add(new Element(PointStart.position, PointEnd.position));
- mSnapshotList.Add(new Element(PointStart.position, PointEnd.position));
- }
- void InitMeshObj() {
- //init vertexpool
- mVertexPool = new VertexPool(MyMaterial, this);
- mVertexSegment = mVertexPool.GetVertices(Granularity * 3, (Granularity - 1) * 12);
- UpdateIndices();
- }
- #endregion
- }
- }
|