feat: un-limit on the number of mesh instances

pull/120/head
mob-sakai 2020-10-28 00:39:22 +09:00
parent 4be56669fb
commit f1338813ca
4 changed files with 81 additions and 33 deletions

View File

@ -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();

View File

@ -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

View File

@ -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");

View File

@ -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;