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
parent
2b9e8ecd73
commit
7f36ca15dd
|
@ -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)
|
||||
|
||||
|
||||
|
|
|
@ -45,7 +45,7 @@ namespace Coffee.UIExtensions
|
|||
}
|
||||
|
||||
private Camera _camera;
|
||||
private int _refCount;
|
||||
// private int _refCount;
|
||||
|
||||
private static BakingCamera Create()
|
||||
{
|
||||
|
@ -70,26 +70,6 @@ namespace Coffee.UIExtensions
|
|||
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)
|
||||
{
|
||||
if (!canvas) return Camera.main;
|
||||
|
|
|
@ -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++;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0328b9fb8360e4f8e8a842f87d330466
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,3 +1,4 @@
|
|||
using System;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
@ -8,8 +9,9 @@ namespace Coffee.UIExtensions
|
|||
{
|
||||
internal class AnimatedPropertiesEditor
|
||||
{
|
||||
static readonly List<string> s_ActiveNames = new List<string>();
|
||||
static readonly System.Text.StringBuilder s_Sb = new System.Text.StringBuilder();
|
||||
private static readonly List<string> s_ActiveNames = new List<string>();
|
||||
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 ShaderPropertyType _type;
|
||||
|
@ -39,10 +41,8 @@ namespace Coffee.UIExtensions
|
|||
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;
|
||||
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);
|
||||
var type = (ShaderPropertyType) ShaderUtil.GetPropertyType(mat.shader, i);
|
||||
AddMenu(gm, sp, new AnimatedPropertiesEditor {_name = pName, _type = type}, true);
|
||||
if (!mat || !mat.shader) continue;
|
||||
|
||||
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 + "_HDR", _type = ShaderPropertyType.Vector}, true);
|
||||
AddMenu(gm, sp, new AnimatedPropertiesEditor {_name = pName + "_TexelSize", _type = ShaderPropertyType.Vector}, true);
|
||||
AddMenu(gm, sp, new AnimatedPropertiesEditor {_name = pName, _type = type}, 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();
|
||||
|
|
|
@ -2,6 +2,7 @@ using UnityEditor;
|
|||
using UnityEditor.UI;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEditorInternal;
|
||||
using UnityEngine.UI;
|
||||
|
||||
|
@ -100,7 +101,12 @@ namespace Coffee.UIExtensions
|
|||
EditorGUILayout.PropertyField(_spScale);
|
||||
|
||||
// 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();
|
||||
|
||||
|
@ -125,19 +131,21 @@ namespace Coffee.UIExtensions
|
|||
|
||||
// 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);
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
|
|
@ -1,104 +1,106 @@
|
|||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Profiling;
|
||||
|
||||
namespace Coffee.UIExtensions
|
||||
{
|
||||
internal static class MeshHelper
|
||||
{
|
||||
private static CombineInstance[] s_CombineInstances;
|
||||
private static int s_TempIndex;
|
||||
private static int s_CurrentIndex;
|
||||
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 long activeMeshIndices { get; private set; }
|
||||
private static readonly List<CombineInstanceEx> s_CachedInstance;
|
||||
private static int count;
|
||||
|
||||
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--;
|
||||
|
||||
if (0 < s_RefCount || s_CombineInstances == null) return;
|
||||
|
||||
for (var i = 0; i < s_CombineInstances.Length; i++)
|
||||
s_CachedInstance = new List<CombineInstanceEx>(8);
|
||||
for (var i = 0; i < 8; i++)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
Object.DestroyImmediate(s_CombineInstances[i].mesh);
|
||||
else
|
||||
#endif
|
||||
{
|
||||
Object.Destroy(s_CombineInstances[i].mesh);
|
||||
}
|
||||
s_CachedInstance.Add(new CombineInstanceEx());
|
||||
}
|
||||
}
|
||||
|
||||
private static CombineInstanceEx Get(int index, long hash)
|
||||
{
|
||||
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;
|
||||
s_CurrentIndex = index;
|
||||
activeMeshIndices += (uint)(1 << s_CurrentIndex);
|
||||
s_CombineInstances[s_TempIndex].transform = s_Transform;
|
||||
return s_CombineInstances[s_TempIndex++].mesh;
|
||||
return MeshPool.Rent();
|
||||
}
|
||||
|
||||
public static void DiscardTemporaryMesh()
|
||||
public static void Push(int index, long hash, Mesh mesh, Matrix4x4 transform)
|
||||
{
|
||||
if (s_TempIndex == 0) return;
|
||||
s_TempIndex--;
|
||||
activeMeshIndices -= (uint)(1 << s_CurrentIndex);
|
||||
}
|
||||
if (mesh.vertexCount <= 0)
|
||||
{
|
||||
DiscardTemporaryMesh(mesh);
|
||||
return;
|
||||
}
|
||||
|
||||
public static void SetTransform(Matrix4x4 transform)
|
||||
{
|
||||
s_Transform = transform;
|
||||
Profiler.BeginSample("[UIParticle] MeshHelper > Get CombineInstanceEx");
|
||||
var inst = Get(index, hash);
|
||||
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()
|
||||
{
|
||||
if (s_CombineInstances == null) return;
|
||||
s_CurrentIndex = 0;
|
||||
count = 0;
|
||||
activeMeshIndices = 0;
|
||||
s_TempIndex = 0;
|
||||
for (var i = 0; i < s_CombineInstances.Length; i++)
|
||||
foreach (var inst in s_CachedInstance)
|
||||
{
|
||||
if (!s_CombineInstances[i].mesh)
|
||||
{
|
||||
var mesh = new Mesh();
|
||||
mesh.MarkDynamic();
|
||||
s_CombineInstances[i].mesh = mesh;
|
||||
}
|
||||
else
|
||||
{
|
||||
s_CombineInstances[i].mesh.Clear(false);
|
||||
}
|
||||
inst.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
public static void ModifyColorSpaceToLinear(this Mesh self)
|
||||
public static void DiscardTemporaryMesh(Mesh mesh)
|
||||
{
|
||||
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();
|
||||
MeshPool.Return(mesh);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -39,7 +39,7 @@ namespace Coffee.UIExtensions
|
|||
private Mesh _bakedMesh;
|
||||
private readonly List<Material> _modifiedMaterials = new List<Material>();
|
||||
private readonly List<Material> _maskMaterials = new List<Material>();
|
||||
private uint _activeMeshIndices;
|
||||
private long _activeMeshIndices;
|
||||
private Vector3 _cachedPosition;
|
||||
private static readonly List<Material> s_TempMaterials = new List<Material>(2);
|
||||
private static MaterialPropertyBlock s_Mpb;
|
||||
|
@ -91,7 +91,7 @@ namespace Coffee.UIExtensions
|
|||
get { return _modifiedMaterials; }
|
||||
}
|
||||
|
||||
internal uint activeMeshIndices
|
||||
internal long activeMeshIndices
|
||||
{
|
||||
get { return _activeMeshIndices; }
|
||||
set
|
||||
|
@ -190,7 +190,7 @@ namespace Coffee.UIExtensions
|
|||
r.GetSharedMaterials(s_TempMaterials);
|
||||
|
||||
// Main
|
||||
var bit = 1 << (i * 2);
|
||||
var bit = (long) 1 << (i * 2);
|
||||
if (0 < (activeMeshIndices & bit) && 0 < s_TempMaterials.Count)
|
||||
{
|
||||
var mat = GetModifiedMaterial(s_TempMaterials[0], ps.GetTextureForSprite());
|
||||
|
@ -264,8 +264,7 @@ namespace Coffee.UIExtensions
|
|||
}
|
||||
|
||||
// Create objects.
|
||||
_bakedMesh = new Mesh();
|
||||
_bakedMesh.MarkDynamic();
|
||||
_bakedMesh = MeshPool.Rent();
|
||||
|
||||
base.OnEnable();
|
||||
|
||||
|
@ -283,7 +282,7 @@ namespace Coffee.UIExtensions
|
|||
_tracker.Clear();
|
||||
|
||||
// Destroy object.
|
||||
DestroyImmediate(_bakedMesh);
|
||||
MeshPool.Return(_bakedMesh);
|
||||
_bakedMesh = null;
|
||||
|
||||
base.OnDisable();
|
||||
|
|
|
@ -16,18 +16,12 @@ namespace Coffee.UIExtensions
|
|||
{
|
||||
if (!particle) return;
|
||||
s_ActiveParticles.Add(particle);
|
||||
|
||||
MeshHelper.Register();
|
||||
BakingCamera.Register();
|
||||
}
|
||||
|
||||
public static void Unregister(UIParticle particle)
|
||||
{
|
||||
if (!particle) return;
|
||||
s_ActiveParticles.Remove(particle);
|
||||
|
||||
MeshHelper.Unregister();
|
||||
BakingCamera.Unregister();
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
|
@ -36,6 +30,10 @@ namespace Coffee.UIExtensions
|
|||
[RuntimeInitializeOnLoadMethod]
|
||||
private static void InitializeOnLoad()
|
||||
{
|
||||
MeshHelper.Init();
|
||||
MeshPool.Init();
|
||||
CombineInstanceArrayPool.Init();
|
||||
|
||||
Canvas.willRenderCanvases -= Refresh;
|
||||
Canvas.willRenderCanvases += Refresh;
|
||||
}
|
||||
|
@ -59,26 +57,26 @@ namespace Coffee.UIExtensions
|
|||
{
|
||||
if (!particle || !particle.canvas || !particle.canvasRenderer) return;
|
||||
|
||||
Profiler.BeginSample("Modify scale");
|
||||
Profiler.BeginSample("[UIParticle] Modify scale");
|
||||
ModifyScale(particle);
|
||||
Profiler.EndSample();
|
||||
|
||||
Profiler.BeginSample("Bake mesh");
|
||||
Profiler.BeginSample("[UIParticle] Bake mesh");
|
||||
BakeMesh(particle);
|
||||
Profiler.EndSample();
|
||||
|
||||
if (QualitySettings.activeColorSpace == ColorSpace.Linear)
|
||||
{
|
||||
Profiler.BeginSample("Modify color space to linear");
|
||||
Profiler.BeginSample("[UIParticle] Modify color space to linear");
|
||||
particle.bakedMesh.ModifyColorSpaceToLinear();
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
Profiler.BeginSample("Set mesh to CanvasRenderer");
|
||||
Profiler.BeginSample("[UIParticle] Set mesh to CanvasRenderer");
|
||||
particle.canvasRenderer.SetMesh(particle.bakedMesh);
|
||||
Profiler.EndSample();
|
||||
|
||||
Profiler.BeginSample("Update Animatable Material Properties");
|
||||
Profiler.BeginSample("[UIParticle] Update Animatable Material Properties");
|
||||
// UpdateAnimatableMaterialProperties(particle);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
@ -170,12 +168,12 @@ namespace Coffee.UIExtensions
|
|||
matrix = GetScaledMatrix(currentPs);
|
||||
}
|
||||
|
||||
// Set transform
|
||||
MeshHelper.SetTransform(scaleMatrix * matrix);
|
||||
matrix = scaleMatrix * matrix;
|
||||
|
||||
// Extra world simulation.
|
||||
if (currentPs.main.simulationSpace == ParticleSystemSimulationSpace.World && 0 < diff.sqrMagnitude)
|
||||
{
|
||||
Profiler.BeginSample("[UIParticle] Bake Mesh > Extra world simulation");
|
||||
var count = currentPs.particleCount;
|
||||
if (s_Particles.Length < count)
|
||||
{
|
||||
|
@ -192,48 +190,55 @@ namespace Coffee.UIExtensions
|
|||
}
|
||||
|
||||
currentPs.SetParticles(s_Particles, count);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
// Bake main particles.
|
||||
var r = currentPs.GetComponent<ParticleSystemRenderer>();
|
||||
if (CanBakeMesh(r))
|
||||
{
|
||||
var m = MeshHelper.GetTemporaryMesh(i * 2);
|
||||
r.BakeMesh(m, camera, true);
|
||||
|
||||
if (m.vertexCount == 0)
|
||||
MeshHelper.DiscardTemporaryMesh();
|
||||
else
|
||||
Profiler.BeginSample("[UIParticle] Bake Mesh > Bake Main Particles");
|
||||
var hash = currentPs.GetMaterialHash(false);
|
||||
if (hash != 0)
|
||||
{
|
||||
var index = MeshHelper.activeMeshIndices.BitCount() - 1;
|
||||
particle.UpdateMaterialProperties(r, index);
|
||||
var m = MeshHelper.GetTemporaryMesh();
|
||||
r.BakeMesh(m, camera, true);
|
||||
MeshHelper.Push(i * 2, hash, m, matrix);
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
// Bake trails particles.
|
||||
if (currentPs.trails.enabled)
|
||||
{
|
||||
var m = MeshHelper.GetTemporaryMesh(i * 2 + 1);
|
||||
try
|
||||
Profiler.BeginSample("[UIParticle] Bake Mesh > Bake Trails Particles");
|
||||
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)
|
||||
MeshHelper.DiscardTemporaryMesh();
|
||||
}
|
||||
catch
|
||||
{
|
||||
MeshHelper.DiscardTemporaryMesh();
|
||||
}
|
||||
Profiler.EndSample();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Set active indices.
|
||||
particle.activeMeshIndices = MeshHelper.activeMeshIndices;
|
||||
|
||||
// Combine
|
||||
Profiler.BeginSample("[UIParticle] Bake Mesh > CombineMesh");
|
||||
MeshHelper.CombineMesh(particle.bakedMesh);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
private static bool CanBakeMesh(ParticleSystemRenderer renderer)
|
||||
|
@ -246,31 +251,5 @@ namespace Coffee.UIExtensions
|
|||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
133
Scripts/Utils.cs
133
Scripts/Utils.cs
|
@ -30,15 +30,120 @@ namespace Coffee.UIExtensions
|
|||
#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 & 0x33333333) + ((self >> 2) & 0x33333333);
|
||||
self = (self & 0x0F0F0F0F) + ((self >> 4) & 0x0F0F0F0F);
|
||||
self = (self & 0x00FF00FF) + ((self >> 8) & 0x00FF00FF);
|
||||
return (int) ((self & 0x0000ffff) + (self >> 16));
|
||||
self = self - ((self >> 1) & 0x5555555555555555L);
|
||||
self = (self & 0x3333333333333333L) + ((self >> 2) & 0x3333333333333333L);
|
||||
return (int) (unchecked(((self + (self >> 4)) & 0xF0F0F0F0F0F0F0FL) * 0x101010101010101L) >> 56);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if (!self) return null;
|
||||
|
@ -91,5 +209,4 @@ namespace Coffee.UIExtensions
|
|||
self.ForEach(action);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "com.coffee.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.",
|
||||
"version": "3.0.0-preview.27",
|
||||
"version": "3.0.0-preview.28",
|
||||
"unity": "2018.2",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
|
|
Loading…
Reference in New Issue