3.0.0-preview.28

# [3.0.0-preview.28](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v3.0.0-preview.27...v3.0.0-preview.28) (2020-09-01)

### Features

* support AnimatableProperty for multiple materials ([062d988](062d9887fb))
pull/120/head
semantic-release-bot 2020-09-01 17:39:05 +00:00
parent 2b9e8ecd73
commit 7f36ca15dd
11 changed files with 352 additions and 175 deletions

View File

@ -1,3 +1,10 @@
# [3.0.0-preview.28](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v3.0.0-preview.27...v3.0.0-preview.28) (2020-09-01)
### Features
* support AnimatableProperty for multiple materials ([062d988](https://github.com/mob-sakai/ParticleEffectForUGUI/commit/062d9887fb8b096250ec3b43d9aa82637940a8bb))
# [3.0.0-preview.27](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v3.0.0-preview.26...v3.0.0-preview.27) (2020-09-01) # [3.0.0-preview.27](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v3.0.0-preview.26...v3.0.0-preview.27) (2020-09-01)

View File

@ -45,7 +45,7 @@ namespace Coffee.UIExtensions
} }
private Camera _camera; private Camera _camera;
private int _refCount; // private int _refCount;
private static BakingCamera Create() private static BakingCamera Create()
{ {
@ -70,26 +70,6 @@ namespace Coffee.UIExtensions
DontDestroyOnLoad(gameObject); DontDestroyOnLoad(gameObject);
} }
public static void Register()
{
Instance._refCount++;
}
public static void Unregister()
{
if (s_Instance == null) return;
Instance._refCount--;
if (0 < Instance._refCount) return;
if (Application.isPlaying)
Destroy(Instance.gameObject);
else
DestroyImmediate(Instance.gameObject);
s_Instance = null;
}
public static Camera GetCamera(Canvas canvas) public static Camera GetCamera(Canvas canvas)
{ {
if (!canvas) return Camera.main; if (!canvas) return Camera.main;

View File

@ -0,0 +1,64 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace Coffee.UIExtensions
{
internal class CombineInstanceEx
{
private int count;
public long hash = -1;
public int index = -1;
private readonly List<CombineInstance> combineInstances = new List<CombineInstance>(32);
public Mesh mesh;
public Matrix4x4 transform;
public void Combine()
{
switch (count)
{
case 0:
return;
case 1:
mesh = combineInstances[0].mesh;
transform = combineInstances[0].transform;
return;
default:
{
var cis = CombineInstanceArrayPool.Get(combineInstances);
mesh = MeshPool.Rent();
mesh.CombineMeshes(cis, true, true);
transform = Matrix4x4.identity;
cis.Clear();
return;
}
}
}
public void Clear()
{
for (var i = 0; i < combineInstances.Count; i++)
{
var inst = combineInstances[i];
MeshPool.Return(inst.mesh);
inst.mesh = null;
combineInstances[i] = inst;
}
combineInstances.Clear();
MeshPool.Return(mesh);
mesh = null;
count = 0;
hash = -1;
index = -1;
}
public void Push(Mesh mesh, Matrix4x4 transform)
{
combineInstances.Add(new CombineInstance {mesh = mesh, transform = transform});
count++;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0328b9fb8360e4f8e8a842f87d330466
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -1,3 +1,4 @@
using System;
using UnityEditor; using UnityEditor;
using UnityEngine; using UnityEngine;
using System.Collections.Generic; using System.Collections.Generic;
@ -8,8 +9,9 @@ namespace Coffee.UIExtensions
{ {
internal class AnimatedPropertiesEditor internal class AnimatedPropertiesEditor
{ {
static readonly List<string> s_ActiveNames = new List<string>(); private static readonly List<string> s_ActiveNames = new List<string>();
static readonly System.Text.StringBuilder s_Sb = new System.Text.StringBuilder(); private static readonly System.Text.StringBuilder s_Sb = new System.Text.StringBuilder();
private static readonly HashSet<string> s_Names = new HashSet<string>();
private string _name; private string _name;
private ShaderPropertyType _type; private ShaderPropertyType _type;
@ -39,10 +41,8 @@ namespace Coffee.UIExtensions
return s_Sb.ToString(); return s_Sb.ToString();
} }
public static void DrawAnimatableProperties(SerializedProperty sp, Material mat) public static void DrawAnimatableProperties(SerializedProperty sp, Material[] mats)
{ {
if (!mat || !mat.shader) return;
bool isClicked; bool isClicked;
using (new EditorGUILayout.HorizontalScope(GUILayout.ExpandWidth(false))) using (new EditorGUILayout.HorizontalScope(GUILayout.ExpandWidth(false)))
{ {
@ -72,17 +72,27 @@ namespace Coffee.UIExtensions
} }
} }
for (var i = 0; i < ShaderUtil.GetPropertyCount(mat.shader); i++) s_Names.Clear();
foreach (var mat in mats)
{ {
var pName = ShaderUtil.GetPropertyName(mat.shader, i); if (!mat || !mat.shader) continue;
var type = (ShaderPropertyType) ShaderUtil.GetPropertyType(mat.shader, i);
AddMenu(gm, sp, new AnimatedPropertiesEditor {_name = pName, _type = type}, true);
if (type != ShaderPropertyType.Texture) continue; for (var i = 0; i < ShaderUtil.GetPropertyCount(mat.shader); i++)
{
var pName = ShaderUtil.GetPropertyName(mat.shader, i);
var type = (ShaderPropertyType) ShaderUtil.GetPropertyType(mat.shader, i);
var name = string.Format("{0} ({1})", pName, type);
if (s_Names.Contains(name)) continue;
s_Names.Add(name);
AddMenu(gm, sp, new AnimatedPropertiesEditor {_name = pName + "_ST", _type = ShaderPropertyType.Vector}, true); AddMenu(gm, sp, new AnimatedPropertiesEditor {_name = pName, _type = type}, true);
AddMenu(gm, sp, new AnimatedPropertiesEditor {_name = pName + "_HDR", _type = ShaderPropertyType.Vector}, true);
AddMenu(gm, sp, new AnimatedPropertiesEditor {_name = pName + "_TexelSize", _type = ShaderPropertyType.Vector}, true); if (type != ShaderPropertyType.Texture) continue;
AddMenu(gm, sp, new AnimatedPropertiesEditor {_name = pName + "_ST", _type = ShaderPropertyType.Vector}, true);
AddMenu(gm, sp, new AnimatedPropertiesEditor {_name = pName + "_HDR", _type = ShaderPropertyType.Vector}, true);
AddMenu(gm, sp, new AnimatedPropertiesEditor {_name = pName + "_TexelSize", _type = ShaderPropertyType.Vector}, true);
}
} }
gm.ShowAsContext(); gm.ShowAsContext();

View File

@ -2,6 +2,7 @@ using UnityEditor;
using UnityEditor.UI; using UnityEditor.UI;
using UnityEngine; using UnityEngine;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using UnityEditorInternal; using UnityEditorInternal;
using UnityEngine.UI; using UnityEngine.UI;
@ -100,7 +101,12 @@ namespace Coffee.UIExtensions
EditorGUILayout.PropertyField(_spScale); EditorGUILayout.PropertyField(_spScale);
// AnimatableProperties // AnimatableProperties
AnimatedPropertiesEditor.DrawAnimatableProperties(_spAnimatableProperties, current.material); var mats = current.particles
.Where(x => x)
.Select(x => x.GetComponent<ParticleSystemRenderer>().sharedMaterial)
.Where(x => x)
.ToArray();
AnimatedPropertiesEditor.DrawAnimatableProperties(_spAnimatableProperties, mats);
_ro.DoLayoutList(); _ro.DoLayoutList();
@ -125,19 +131,21 @@ namespace Coffee.UIExtensions
// Does the shader support UI masks? // Does the shader support UI masks?
if (FixButton(current.m_IsTrail,"This UIParticle component should be removed. The UIParticle for trails is no longer needed.")) if (FixButton(current.m_IsTrail, "This UIParticle component should be removed. The UIParticle for trails is no longer needed."))
{ {
DestroyUIParticle(current); DestroyUIParticle(current);
return; return;
} }
current.GetComponentsInParent(true, s_TempParents); current.GetComponentsInParent(true, s_TempParents);
if (FixButton(1 < s_TempParents.Count,"This UIParticle component should be removed. The parent UIParticle exists.")) if (FixButton(1 < s_TempParents.Count, "This UIParticle component should be removed. The parent UIParticle exists."))
{ {
DestroyUIParticle(current); DestroyUIParticle(current);
return; return;
} }
current.GetComponentsInChildren(true, s_TempChildren); current.GetComponentsInChildren(true, s_TempChildren);
if (FixButton(1 < s_TempChildren.Count,"The children UIParticle component should be removed.")) if (FixButton(1 < s_TempChildren.Count, "The children UIParticle component should be removed."))
{ {
s_TempChildren.ForEach(child => DestroyUIParticle(child, true)); s_TempChildren.ForEach(child => DestroyUIParticle(child, true));
} }

View File

@ -1,104 +1,106 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using UnityEngine.Profiling;
namespace Coffee.UIExtensions namespace Coffee.UIExtensions
{ {
internal static class MeshHelper internal static class MeshHelper
{ {
private static CombineInstance[] s_CombineInstances; public static long activeMeshIndices { get; private set; }
private static int s_TempIndex; private static readonly List<CombineInstanceEx> s_CachedInstance;
private static int s_CurrentIndex; private static int count;
static readonly List<Color32> s_Colors = new List<Color32>();
private static int s_RefCount;
private static Matrix4x4 s_Transform;
public static uint activeMeshIndices { get; private set; }
public static void Register() public static void Init()
{ {
if (0 < s_RefCount++) return;
s_CombineInstances = new CombineInstance[8];
} }
public static void Unregister() static MeshHelper()
{ {
s_RefCount--; s_CachedInstance = new List<CombineInstanceEx>(8);
for (var i = 0; i < 8; i++)
if (0 < s_RefCount || s_CombineInstances == null) return;
for (var i = 0; i < s_CombineInstances.Length; i++)
{ {
#if UNITY_EDITOR s_CachedInstance.Add(new CombineInstanceEx());
if (!Application.isPlaying) }
Object.DestroyImmediate(s_CombineInstances[i].mesh); }
else
#endif private static CombineInstanceEx Get(int index, long hash)
{ {
Object.Destroy(s_CombineInstances[i].mesh); if (0 < count && s_CachedInstance[count - 1].hash == hash)
} return s_CachedInstance[count - 1];
if (s_CachedInstance.Count <= count)
{
var newInst = new CombineInstanceEx();
s_CachedInstance.Add(newInst);
} }
s_CombineInstances = null; var inst = s_CachedInstance[count];
inst.hash = hash;
if (inst.index != -1) return inst;
inst.index = index;
count++;
return inst;
} }
public static Mesh GetTemporaryMesh(int index) public static Mesh GetTemporaryMesh()
{ {
if (s_CombineInstances.Length <= s_TempIndex) s_TempIndex = s_CombineInstances.Length - 1; return MeshPool.Rent();
s_CurrentIndex = index;
activeMeshIndices += (uint)(1 << s_CurrentIndex);
s_CombineInstances[s_TempIndex].transform = s_Transform;
return s_CombineInstances[s_TempIndex++].mesh;
} }
public static void DiscardTemporaryMesh() public static void Push(int index, long hash, Mesh mesh, Matrix4x4 transform)
{ {
if (s_TempIndex == 0) return; if (mesh.vertexCount <= 0)
s_TempIndex--; {
activeMeshIndices -= (uint)(1 << s_CurrentIndex); DiscardTemporaryMesh(mesh);
} return;
}
public static void SetTransform(Matrix4x4 transform) Profiler.BeginSample("[UIParticle] MeshHelper > Get CombineInstanceEx");
{ var inst = Get(index, hash);
s_Transform = transform; Profiler.EndSample();
Profiler.BeginSample("[UIParticle] MeshHelper > Push To Mesh Helper");
inst.Push(mesh, transform);
Profiler.EndSample();
activeMeshIndices |= (long) 1 << inst.index;
} }
public static void Clear() public static void Clear()
{ {
if (s_CombineInstances == null) return; count = 0;
s_CurrentIndex = 0;
activeMeshIndices = 0; activeMeshIndices = 0;
s_TempIndex = 0; foreach (var inst in s_CachedInstance)
for (var i = 0; i < s_CombineInstances.Length; i++)
{ {
if (!s_CombineInstances[i].mesh) inst.Clear();
{
var mesh = new Mesh();
mesh.MarkDynamic();
s_CombineInstances[i].mesh = mesh;
}
else
{
s_CombineInstances[i].mesh.Clear(false);
}
} }
} }
public static void CombineMesh(Mesh result) public static void CombineMesh(Mesh result)
{ {
if (!result || s_TempIndex == 0) return; if (count == 0) return;
for (var i = 0; i < count; i++)
{
Profiler.BeginSample("[UIParticle] MeshHelper > Combine Mesh Internal");
s_CachedInstance[i].Combine();
Profiler.EndSample();
}
Profiler.BeginSample("[UIParticle] MeshHelper > Combine Mesh");
var cis = CombineInstanceArrayPool.Get(s_CachedInstance, count);
result.CombineMeshes(cis, false, true);
cis.Clear();
Profiler.EndSample();
result.CombineMeshes(s_CombineInstances, false, true);
result.RecalculateBounds(); result.RecalculateBounds();
} }
public static void ModifyColorSpaceToLinear(this Mesh self) public static void DiscardTemporaryMesh(Mesh mesh)
{ {
self.GetColors(s_Colors); MeshPool.Return(mesh);
for (var i = 0; i < s_Colors.Count; i++)
s_Colors[i] = ((Color) s_Colors[i]).gamma;
self.SetColors(s_Colors);
s_Colors.Clear();
} }
} }
} }

View File

@ -39,7 +39,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 uint _activeMeshIndices; private long _activeMeshIndices;
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;
@ -91,7 +91,7 @@ namespace Coffee.UIExtensions
get { return _modifiedMaterials; } get { return _modifiedMaterials; }
} }
internal uint activeMeshIndices internal long activeMeshIndices
{ {
get { return _activeMeshIndices; } get { return _activeMeshIndices; }
set set
@ -190,7 +190,7 @@ namespace Coffee.UIExtensions
r.GetSharedMaterials(s_TempMaterials); r.GetSharedMaterials(s_TempMaterials);
// Main // Main
var bit = 1 << (i * 2); var bit = (long) 1 << (i * 2);
if (0 < (activeMeshIndices & bit) && 0 < s_TempMaterials.Count) if (0 < (activeMeshIndices & bit) && 0 < s_TempMaterials.Count)
{ {
var mat = GetModifiedMaterial(s_TempMaterials[0], ps.GetTextureForSprite()); var mat = GetModifiedMaterial(s_TempMaterials[0], ps.GetTextureForSprite());
@ -264,8 +264,7 @@ namespace Coffee.UIExtensions
} }
// Create objects. // Create objects.
_bakedMesh = new Mesh(); _bakedMesh = MeshPool.Rent();
_bakedMesh.MarkDynamic();
base.OnEnable(); base.OnEnable();
@ -283,7 +282,7 @@ namespace Coffee.UIExtensions
_tracker.Clear(); _tracker.Clear();
// Destroy object. // Destroy object.
DestroyImmediate(_bakedMesh); MeshPool.Return(_bakedMesh);
_bakedMesh = null; _bakedMesh = null;
base.OnDisable(); base.OnDisable();

View File

@ -16,18 +16,12 @@ namespace Coffee.UIExtensions
{ {
if (!particle) return; if (!particle) return;
s_ActiveParticles.Add(particle); s_ActiveParticles.Add(particle);
MeshHelper.Register();
BakingCamera.Register();
} }
public static void Unregister(UIParticle particle) public static void Unregister(UIParticle particle)
{ {
if (!particle) return; if (!particle) return;
s_ActiveParticles.Remove(particle); s_ActiveParticles.Remove(particle);
MeshHelper.Unregister();
BakingCamera.Unregister();
} }
#if UNITY_EDITOR #if UNITY_EDITOR
@ -36,6 +30,10 @@ namespace Coffee.UIExtensions
[RuntimeInitializeOnLoadMethod] [RuntimeInitializeOnLoadMethod]
private static void InitializeOnLoad() private static void InitializeOnLoad()
{ {
MeshHelper.Init();
MeshPool.Init();
CombineInstanceArrayPool.Init();
Canvas.willRenderCanvases -= Refresh; Canvas.willRenderCanvases -= Refresh;
Canvas.willRenderCanvases += Refresh; Canvas.willRenderCanvases += Refresh;
} }
@ -59,26 +57,26 @@ namespace Coffee.UIExtensions
{ {
if (!particle || !particle.canvas || !particle.canvasRenderer) return; if (!particle || !particle.canvas || !particle.canvasRenderer) return;
Profiler.BeginSample("Modify scale"); Profiler.BeginSample("[UIParticle] Modify scale");
ModifyScale(particle); ModifyScale(particle);
Profiler.EndSample(); Profiler.EndSample();
Profiler.BeginSample("Bake mesh"); Profiler.BeginSample("[UIParticle] Bake mesh");
BakeMesh(particle); BakeMesh(particle);
Profiler.EndSample(); Profiler.EndSample();
if (QualitySettings.activeColorSpace == ColorSpace.Linear) if (QualitySettings.activeColorSpace == ColorSpace.Linear)
{ {
Profiler.BeginSample("Modify color space to linear"); Profiler.BeginSample("[UIParticle] Modify color space to linear");
particle.bakedMesh.ModifyColorSpaceToLinear(); particle.bakedMesh.ModifyColorSpaceToLinear();
Profiler.EndSample(); Profiler.EndSample();
} }
Profiler.BeginSample("Set mesh to CanvasRenderer"); Profiler.BeginSample("[UIParticle] Set mesh to CanvasRenderer");
particle.canvasRenderer.SetMesh(particle.bakedMesh); particle.canvasRenderer.SetMesh(particle.bakedMesh);
Profiler.EndSample(); Profiler.EndSample();
Profiler.BeginSample("Update Animatable Material Properties"); Profiler.BeginSample("[UIParticle] Update Animatable Material Properties");
// UpdateAnimatableMaterialProperties(particle); // UpdateAnimatableMaterialProperties(particle);
Profiler.EndSample(); Profiler.EndSample();
} }
@ -170,12 +168,12 @@ namespace Coffee.UIExtensions
matrix = GetScaledMatrix(currentPs); matrix = GetScaledMatrix(currentPs);
} }
// Set transform matrix = scaleMatrix * matrix;
MeshHelper.SetTransform(scaleMatrix * matrix);
// Extra world simulation. // Extra world simulation.
if (currentPs.main.simulationSpace == ParticleSystemSimulationSpace.World && 0 < diff.sqrMagnitude) if (currentPs.main.simulationSpace == ParticleSystemSimulationSpace.World && 0 < diff.sqrMagnitude)
{ {
Profiler.BeginSample("[UIParticle] Bake Mesh > Extra world simulation");
var count = currentPs.particleCount; var count = currentPs.particleCount;
if (s_Particles.Length < count) if (s_Particles.Length < count)
{ {
@ -192,48 +190,55 @@ namespace Coffee.UIExtensions
} }
currentPs.SetParticles(s_Particles, count); currentPs.SetParticles(s_Particles, count);
Profiler.EndSample();
} }
// Bake main particles. // Bake main particles.
var r = currentPs.GetComponent<ParticleSystemRenderer>(); var r = currentPs.GetComponent<ParticleSystemRenderer>();
if (CanBakeMesh(r)) if (CanBakeMesh(r))
{ {
var m = MeshHelper.GetTemporaryMesh(i * 2); Profiler.BeginSample("[UIParticle] Bake Mesh > Bake Main Particles");
r.BakeMesh(m, camera, true); var hash = currentPs.GetMaterialHash(false);
if (hash != 0)
if (m.vertexCount == 0)
MeshHelper.DiscardTemporaryMesh();
else
{ {
var index = MeshHelper.activeMeshIndices.BitCount() - 1; var m = MeshHelper.GetTemporaryMesh();
particle.UpdateMaterialProperties(r, index); r.BakeMesh(m, camera, true);
MeshHelper.Push(i * 2, hash, m, matrix);
} }
Profiler.EndSample();
} }
// Bake trails particles. // Bake trails particles.
if (currentPs.trails.enabled) if (currentPs.trails.enabled)
{ {
var m = MeshHelper.GetTemporaryMesh(i * 2 + 1); Profiler.BeginSample("[UIParticle] Bake Mesh > Bake Trails Particles");
try var hash = currentPs.GetMaterialHash(true);
if (hash != 0)
{ {
r.BakeTrailsMesh(m, camera, true); var m = MeshHelper.GetTemporaryMesh();
try
{
r.BakeTrailsMesh(m, camera, true);
MeshHelper.Push(i * 2 + 1, hash, m, matrix);
}
catch
{
MeshHelper.DiscardTemporaryMesh(m);
}
}
if (m.vertexCount == 0) Profiler.EndSample();
MeshHelper.DiscardTemporaryMesh();
}
catch
{
MeshHelper.DiscardTemporaryMesh();
}
} }
} }
// Set active indices. // Set active indices.
particle.activeMeshIndices = MeshHelper.activeMeshIndices; particle.activeMeshIndices = MeshHelper.activeMeshIndices;
// Combine // Combine
Profiler.BeginSample("[UIParticle] Bake Mesh > CombineMesh");
MeshHelper.CombineMesh(particle.bakedMesh); MeshHelper.CombineMesh(particle.bakedMesh);
Profiler.EndSample();
} }
private static bool CanBakeMesh(ParticleSystemRenderer renderer) private static bool CanBakeMesh(ParticleSystemRenderer renderer)
@ -246,31 +251,5 @@ namespace Coffee.UIExtensions
return true; return true;
} }
/// <summary>
/// Copy the value from MaterialPropertyBlock to CanvasRenderer
/// </summary>
private static void UpdateAnimatableMaterialProperties(UIParticle particle, ParticleSystemRenderer renderer)
{
#if UNITY_EDITOR
if (!Application.isPlaying) return;
#endif
if (0 == particle.m_AnimatableProperties.Length) return;
if (0 == particle.canvasRenderer.materialCount) return;
var mat = particle.canvasRenderer.GetMaterial(0);
if (!mat) return;
// #41: Copy the value from MaterialPropertyBlock to CanvasRenderer
if (s_Mpb == null)
s_Mpb = new MaterialPropertyBlock();
renderer.GetPropertyBlock(s_Mpb);
foreach (var ap in particle.m_AnimatableProperties)
{
ap.UpdateMaterialProperties(mat, s_Mpb);
}
s_Mpb.Clear();
}
} }
} }

View File

@ -30,15 +30,120 @@ namespace Coffee.UIExtensions
#endif #endif
} }
internal static class UintExtensions internal static class LongExtensions
{ {
public static int BitCount(this uint self) public static int BitCount(this long self)
{ {
self = (self & 0x55555555) + ((self >> 1) & 0x55555555); self = self - ((self >> 1) & 0x5555555555555555L);
self = (self & 0x33333333) + ((self >> 2) & 0x33333333); self = (self & 0x3333333333333333L) + ((self >> 2) & 0x3333333333333333L);
self = (self & 0x0F0F0F0F) + ((self >> 4) & 0x0F0F0F0F); return (int) (unchecked(((self + (self >> 4)) & 0xF0F0F0F0F0F0F0FL) * 0x101010101010101L) >> 56);
self = (self & 0x00FF00FF) + ((self >> 8) & 0x00FF00FF); }
return (int) ((self & 0x0000ffff) + (self >> 16)); }
internal static class MeshExtensions
{
static readonly List<Color32> s_Colors = new List<Color32>();
public static void ModifyColorSpaceToLinear(this Mesh self)
{
self.GetColors(s_Colors);
for (var i = 0; i < s_Colors.Count; i++)
s_Colors[i] = ((Color) s_Colors[i]).gamma;
self.SetColors(s_Colors);
s_Colors.Clear();
}
public static void Clear(this CombineInstance[] self)
{
for (var i = 0; i < self.Length; i++)
{
MeshPool.Return(self[i].mesh);
self[i].mesh = null;
}
}
}
internal static class MeshPool
{
private static readonly Stack<Mesh> s_Pool = new Stack<Mesh>();
public static void Init()
{
}
static MeshPool()
{
for (var i = 0; i < 32; i++)
{
var m = new Mesh();
m.MarkDynamic();
s_Pool.Push(m);
}
}
public static Mesh Rent()
{
Mesh m;
while (0 < s_Pool.Count)
{
m = s_Pool.Pop();
if (m) return m;
}
m = new Mesh();
m.MarkDynamic();
return m;
}
public static void Return(Mesh mesh)
{
if (!mesh || s_Pool.Contains(mesh)) return;
mesh.Clear(false);
s_Pool.Push(mesh);
}
}
internal static class CombineInstanceArrayPool
{
private static readonly List<CombineInstance[]> s_Pool;
public static void Init()
{
}
static CombineInstanceArrayPool()
{
s_Pool = new List<CombineInstance[]>(32);
for (var i = 0; i < 32; i++)
{
s_Pool.Add(new CombineInstance[i]);
}
}
public static CombineInstance[] Get(List<CombineInstance> src)
{
var dst = s_Pool[src.Count];
for (var i = 0; i < src.Count; i++)
{
dst[i].mesh = src[i].mesh;
dst[i].transform = src[i].transform;
}
return dst;
}
public static CombineInstance[] Get(List<CombineInstanceEx> src, int count)
{
var dst = s_Pool[count];
for (var i = 0; i < count; i++)
{
dst[i].mesh = src[i].mesh;
dst[i].transform = src[i].transform;
}
return dst;
} }
} }
@ -66,6 +171,19 @@ namespace Coffee.UIExtensions
}); });
} }
public static long GetMaterialHash(this ParticleSystem self, bool trail)
{
if (!self) return 0;
var r = self.GetComponent<ParticleSystemRenderer>();
var mat = trail ? r.trailMaterial : r.sharedMaterial;
if (!mat) return 0;
var tex = self.GetTextureForSprite();
return ((long) mat.GetHashCode() << 32) + (tex ? tex.GetHashCode() : 0);
}
public static Texture2D GetTextureForSprite(this ParticleSystem self) public static Texture2D GetTextureForSprite(this ParticleSystem self)
{ {
if (!self) return null; if (!self) return null;
@ -91,5 +209,4 @@ namespace Coffee.UIExtensions
self.ForEach(action); self.ForEach(action);
} }
} }
} }

View File

@ -2,7 +2,7 @@
"name": "com.coffee.ui-particle", "name": "com.coffee.ui-particle",
"displayName": "UI Particle", "displayName": "UI Particle",
"description": "This plugin provide a component to render particle effect for uGUI.\nThe particle rendering is maskable and sortable, without Camera, RenderTexture or Canvas.", "description": "This plugin provide a component to render particle effect for uGUI.\nThe particle rendering is maskable and sortable, without Camera, RenderTexture or Canvas.",
"version": "3.0.0-preview.27", "version": "3.0.0-preview.28",
"unity": "2018.2", "unity": "2018.2",
"license": "MIT", "license": "MIT",
"repository": { "repository": {