feat: un-limit on the number of mesh instances
parent
4be56669fb
commit
f1338813ca
|
@ -6,12 +6,13 @@ namespace Coffee.UIParticleExtensions
|
||||||
{
|
{
|
||||||
internal static class MeshHelper
|
internal static class MeshHelper
|
||||||
{
|
{
|
||||||
public static long activeMeshIndices { get; private set; }
|
public static List<bool> activeMeshIndices { get; private set; }
|
||||||
private static readonly List<CombineInstanceEx> s_CachedInstance;
|
private static readonly List<CombineInstanceEx> s_CachedInstance;
|
||||||
private static int count;
|
private static int count;
|
||||||
|
|
||||||
public static void Init()
|
public static void Init()
|
||||||
{
|
{
|
||||||
|
activeMeshIndices = new List<bool>();
|
||||||
}
|
}
|
||||||
|
|
||||||
static MeshHelper()
|
static MeshHelper()
|
||||||
|
@ -64,13 +65,13 @@ namespace Coffee.UIParticleExtensions
|
||||||
inst.Push(mesh, transform);
|
inst.Push(mesh, transform);
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
|
|
||||||
activeMeshIndices |= (long) 1 << inst.index;
|
activeMeshIndices[inst.index] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Clear()
|
public static void Clear()
|
||||||
{
|
{
|
||||||
count = 0;
|
count = 0;
|
||||||
activeMeshIndices = 0;
|
activeMeshIndices.Clear();
|
||||||
foreach (var inst in s_CachedInstance)
|
foreach (var inst in s_CachedInstance)
|
||||||
{
|
{
|
||||||
inst.Clear();
|
inst.Clear();
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Coffee.UIParticleExtensions;
|
using Coffee.UIParticleExtensions;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
@ -44,7 +43,7 @@ namespace Coffee.UIExtensions
|
||||||
private Mesh _bakedMesh;
|
private Mesh _bakedMesh;
|
||||||
private readonly List<Material> _modifiedMaterials = new List<Material>();
|
private readonly List<Material> _modifiedMaterials = new List<Material>();
|
||||||
private readonly List<Material> _maskMaterials = new List<Material>();
|
private readonly List<Material> _maskMaterials = new List<Material>();
|
||||||
private long _activeMeshIndices;
|
private readonly List<bool> _activeMeshIndices = new List<bool>();
|
||||||
private Vector3 _cachedPosition;
|
private Vector3 _cachedPosition;
|
||||||
private static readonly List<Material> s_TempMaterials = new List<Material>(2);
|
private static readonly List<Material> s_TempMaterials = new List<Material>(2);
|
||||||
private static MaterialPropertyBlock s_Mpb;
|
private static MaterialPropertyBlock s_Mpb;
|
||||||
|
@ -117,13 +116,14 @@ namespace Coffee.UIExtensions
|
||||||
get { return _modifiedMaterials; }
|
get { return _modifiedMaterials; }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal long activeMeshIndices
|
public List<bool> activeMeshIndices
|
||||||
{
|
{
|
||||||
get { return _activeMeshIndices; }
|
get { return _activeMeshIndices; }
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (_activeMeshIndices == value) return;
|
if (_activeMeshIndices.SequenceEqualFast(value)) return;
|
||||||
_activeMeshIndices = value;
|
_activeMeshIndices.Clear();
|
||||||
|
_activeMeshIndices.AddRange(value);
|
||||||
UpdateMaterial();
|
UpdateMaterial();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -228,9 +228,9 @@ namespace Coffee.UIExtensions
|
||||||
}
|
}
|
||||||
|
|
||||||
// No mesh to render.
|
// No mesh to render.
|
||||||
if (activeMeshIndices == 0 || !isActiveAndEnabled || particles.Count == 0)
|
var count = activeMeshIndices.CountFast();
|
||||||
|
if (count == 0 || !isActiveAndEnabled || particles.Count == 0)
|
||||||
{
|
{
|
||||||
_activeMeshIndices = 0;
|
|
||||||
canvasRenderer.Clear();
|
canvasRenderer.Clear();
|
||||||
|
|
||||||
foreach (var m in s_PrevMaskMaterials)
|
foreach (var m in s_PrevMaskMaterials)
|
||||||
|
@ -242,7 +242,7 @@ namespace Coffee.UIExtensions
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
var materialCount = Mathf.Max(8, activeMeshIndices.BitCount());
|
var materialCount = Mathf.Max(8, count);
|
||||||
canvasRenderer.materialCount = materialCount;
|
canvasRenderer.materialCount = materialCount;
|
||||||
var j = 0;
|
var j = 0;
|
||||||
for (var i = 0; i < particles.Count; i++)
|
for (var i = 0; i < particles.Count; i++)
|
||||||
|
@ -255,8 +255,8 @@ namespace Coffee.UIExtensions
|
||||||
r.GetSharedMaterials(s_TempMaterials);
|
r.GetSharedMaterials(s_TempMaterials);
|
||||||
|
|
||||||
// Main
|
// Main
|
||||||
var bit = (long) 1 << (i * 2);
|
var index = i * 2;
|
||||||
if (0 < (activeMeshIndices & bit) && 0 < s_TempMaterials.Count)
|
if (activeMeshIndices[index] && 0 < s_TempMaterials.Count)
|
||||||
{
|
{
|
||||||
var mat = GetModifiedMaterial(s_TempMaterials[0], ps.GetTextureForSprite());
|
var mat = GetModifiedMaterial(s_TempMaterials[0], ps.GetTextureForSprite());
|
||||||
canvasRenderer.SetMaterial(mat, j);
|
canvasRenderer.SetMaterial(mat, j);
|
||||||
|
@ -265,9 +265,9 @@ namespace Coffee.UIExtensions
|
||||||
}
|
}
|
||||||
|
|
||||||
// Trails
|
// Trails
|
||||||
|
index++;
|
||||||
if (materialCount <= j) break;
|
if (materialCount <= j) break;
|
||||||
bit <<= 1;
|
if (activeMeshIndices[index] && 1 < s_TempMaterials.Count)
|
||||||
if (0 < (activeMeshIndices & bit) && 1 < s_TempMaterials.Count)
|
|
||||||
{
|
{
|
||||||
var mat = GetModifiedMaterial(s_TempMaterials[1], null);
|
var mat = GetModifiedMaterial(s_TempMaterials[1], null);
|
||||||
canvasRenderer.SetMaterial(mat, j++);
|
canvasRenderer.SetMaterial(mat, j++);
|
||||||
|
@ -303,7 +303,8 @@ namespace Coffee.UIExtensions
|
||||||
if (m_AnimatableProperties.Length == 0) return;
|
if (m_AnimatableProperties.Length == 0) return;
|
||||||
|
|
||||||
//
|
//
|
||||||
var materialCount = Mathf.Max(8, activeMeshIndices.BitCount());
|
var count = activeMeshIndices.CountFast();
|
||||||
|
var materialCount = Mathf.Max(8, count);
|
||||||
canvasRenderer.materialCount = materialCount;
|
canvasRenderer.materialCount = materialCount;
|
||||||
var j = 0;
|
var j = 0;
|
||||||
for (var i = 0; i < particles.Count; i++)
|
for (var i = 0; i < particles.Count; i++)
|
||||||
|
@ -316,8 +317,7 @@ namespace Coffee.UIExtensions
|
||||||
r.GetSharedMaterials(s_TempMaterials);
|
r.GetSharedMaterials(s_TempMaterials);
|
||||||
|
|
||||||
// Main
|
// Main
|
||||||
var bit = (long) 1 << (i * 2);
|
if (activeMeshIndices[i * 2] && 0 < s_TempMaterials.Count)
|
||||||
if (0 < (activeMeshIndices & bit) && 0 < s_TempMaterials.Count)
|
|
||||||
{
|
{
|
||||||
UpdateMaterialProperties(r, j);
|
UpdateMaterialProperties(r, j);
|
||||||
j++;
|
j++;
|
||||||
|
@ -350,7 +350,7 @@ namespace Coffee.UIExtensions
|
||||||
protected override void OnEnable()
|
protected override void OnEnable()
|
||||||
{
|
{
|
||||||
_cachedPosition = transform.localPosition;
|
_cachedPosition = transform.localPosition;
|
||||||
_activeMeshIndices = 0;
|
activeMeshIndices.Clear();
|
||||||
|
|
||||||
UIParticleUpdater.Register(this);
|
UIParticleUpdater.Register(this);
|
||||||
particles.Exec(p => p.GetComponent<ParticleSystemRenderer>().enabled = false);
|
particles.Exec(p => p.GetComponent<ParticleSystemRenderer>().enabled = false);
|
||||||
|
@ -418,7 +418,7 @@ namespace Coffee.UIExtensions
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this || particles.Any(x => x)) return;
|
if (!this || particles.AnyFast()) return;
|
||||||
|
|
||||||
// refresh.
|
// refresh.
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
|
|
|
@ -129,8 +129,10 @@ namespace Coffee.UIExtensions
|
||||||
private static void BakeMesh(UIParticle particle)
|
private static void BakeMesh(UIParticle particle)
|
||||||
{
|
{
|
||||||
// Clear mesh before bake.
|
// Clear mesh before bake.
|
||||||
|
Profiler.BeginSample("[UIParticle] Bake Mesh > Clear mesh before bake");
|
||||||
MeshHelper.Clear();
|
MeshHelper.Clear();
|
||||||
particle.bakedMesh.Clear(false);
|
particle.bakedMesh.Clear(false);
|
||||||
|
Profiler.EndSample();
|
||||||
|
|
||||||
// Get camera for baking mesh.
|
// Get camera for baking mesh.
|
||||||
var camera = BakingCamera.GetCamera(particle.canvas);
|
var camera = BakingCamera.GetCamera(particle.canvas);
|
||||||
|
@ -153,11 +155,17 @@ namespace Coffee.UIExtensions
|
||||||
|
|
||||||
for (var i = 0; i < particle.particles.Count; i++)
|
for (var i = 0; i < particle.particles.Count; i++)
|
||||||
{
|
{
|
||||||
|
Profiler.BeginSample("[UIParticle] Bake Mesh > Push index");
|
||||||
|
MeshHelper.activeMeshIndices.Add(false);
|
||||||
|
MeshHelper.activeMeshIndices.Add(false);
|
||||||
|
Profiler.EndSample();
|
||||||
|
|
||||||
// No particle to render.
|
// No particle to render.
|
||||||
var currentPs = particle.particles[i];
|
var currentPs = particle.particles[i];
|
||||||
if (!currentPs || !currentPs.IsAlive() || currentPs.particleCount == 0) continue;
|
if (!currentPs || !currentPs.IsAlive() || currentPs.particleCount == 0) continue;
|
||||||
|
|
||||||
// Calc matrix.
|
// Calc matrix.
|
||||||
|
Profiler.BeginSample("[UIParticle] Bake Mesh > Calc matrix");
|
||||||
var matrix = rootMatrix;
|
var matrix = rootMatrix;
|
||||||
if (currentPs.transform != root)
|
if (currentPs.transform != root)
|
||||||
{
|
{
|
||||||
|
@ -177,6 +185,7 @@ namespace Coffee.UIExtensions
|
||||||
}
|
}
|
||||||
|
|
||||||
matrix = scaleMatrix * matrix;
|
matrix = scaleMatrix * matrix;
|
||||||
|
Profiler.EndSample();
|
||||||
|
|
||||||
// Extra world simulation.
|
// Extra world simulation.
|
||||||
if (currentPs.main.simulationSpace == ParticleSystemSimulationSpace.World && 0 < diff.sqrMagnitude)
|
if (currentPs.main.simulationSpace == ParticleSystemSimulationSpace.World && 0 < diff.sqrMagnitude)
|
||||||
|
@ -245,7 +254,9 @@ namespace Coffee.UIExtensions
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set active indices.
|
// Set active indices.
|
||||||
|
Profiler.BeginSample("[UIParticle] Bake Mesh > Set active indices");
|
||||||
particle.activeMeshIndices = MeshHelper.activeMeshIndices;
|
particle.activeMeshIndices = MeshHelper.activeMeshIndices;
|
||||||
|
Profiler.EndSample();
|
||||||
|
|
||||||
// Combine
|
// Combine
|
||||||
Profiler.BeginSample("[UIParticle] Bake Mesh > CombineMesh");
|
Profiler.BeginSample("[UIParticle] Bake Mesh > CombineMesh");
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
|
|
||||||
namespace Coffee.UIParticleExtensions
|
namespace Coffee.UIParticleExtensions
|
||||||
{
|
{
|
||||||
|
@ -30,13 +31,38 @@ namespace Coffee.UIParticleExtensions
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static class LongExtensions
|
internal static class ListExtensions
|
||||||
{
|
{
|
||||||
public static int BitCount(this long self)
|
public static bool SequenceEqualFast(this List<bool> self, List<bool> value)
|
||||||
{
|
{
|
||||||
self = self - ((self >> 1) & 0x5555555555555555L);
|
if (self.Count != value.Count) return false;
|
||||||
self = (self & 0x3333333333333333L) + ((self >> 2) & 0x3333333333333333L);
|
for (var i = 0; i < self.Count; ++i)
|
||||||
return (int) (unchecked(((self + (self >> 4)) & 0xF0F0F0F0F0F0F0FL) * 0x101010101010101L) >> 56);
|
{
|
||||||
|
if (self[i] != value[i]) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int CountFast(this List<bool> self)
|
||||||
|
{
|
||||||
|
var count = 0;
|
||||||
|
for (var i = 0; i < self.Count; ++i)
|
||||||
|
{
|
||||||
|
if (self[i]) count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool AnyFast<T>(this List<T> self) where T : Object
|
||||||
|
{
|
||||||
|
for (var i = 0; i < self.Count; ++i)
|
||||||
|
{
|
||||||
|
if (self[i]) return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,24 +133,28 @@ namespace Coffee.UIParticleExtensions
|
||||||
|
|
||||||
internal static class CombineInstanceArrayPool
|
internal static class CombineInstanceArrayPool
|
||||||
{
|
{
|
||||||
private static readonly List<CombineInstance[]> s_Pool;
|
private static readonly Dictionary<int, CombineInstance[]> s_Pool;
|
||||||
|
|
||||||
public static void Init()
|
public static void Init()
|
||||||
{
|
{
|
||||||
|
s_Pool.Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
static CombineInstanceArrayPool()
|
static CombineInstanceArrayPool()
|
||||||
{
|
{
|
||||||
s_Pool = new List<CombineInstance[]>(32);
|
s_Pool = new Dictionary<int, CombineInstance[]>();
|
||||||
for (var i = 0; i < 32; i++)
|
|
||||||
{
|
|
||||||
s_Pool.Add(new CombineInstance[i]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CombineInstance[] Get(List<CombineInstance> src)
|
public static CombineInstance[] Get(List<CombineInstance> src)
|
||||||
{
|
{
|
||||||
var dst = s_Pool[src.Count];
|
CombineInstance[] dst;
|
||||||
|
var count = src.Count;
|
||||||
|
if (!s_Pool.TryGetValue(count, out dst))
|
||||||
|
{
|
||||||
|
dst = new CombineInstance[count];
|
||||||
|
s_Pool.Add(count, dst);
|
||||||
|
}
|
||||||
|
|
||||||
for (var i = 0; i < src.Count; i++)
|
for (var i = 0; i < src.Count; i++)
|
||||||
{
|
{
|
||||||
dst[i].mesh = src[i].mesh;
|
dst[i].mesh = src[i].mesh;
|
||||||
|
@ -136,7 +166,13 @@ namespace Coffee.UIParticleExtensions
|
||||||
|
|
||||||
public static CombineInstance[] Get(List<CombineInstanceEx> src, int count)
|
public static CombineInstance[] Get(List<CombineInstanceEx> src, int count)
|
||||||
{
|
{
|
||||||
var dst = s_Pool[count];
|
CombineInstance[] dst;
|
||||||
|
if (!s_Pool.TryGetValue(count, out dst))
|
||||||
|
{
|
||||||
|
dst = new CombineInstance[count];
|
||||||
|
s_Pool.Add(count, dst);
|
||||||
|
}
|
||||||
|
|
||||||
for (var i = 0; i < count; i++)
|
for (var i = 0; i < count; i++)
|
||||||
{
|
{
|
||||||
dst[i].mesh = src[i].mesh;
|
dst[i].mesh = src[i].mesh;
|
||||||
|
|
Loading…
Reference in New Issue