You've already forked ParticleEffectForUGUI
mirror of
https://github.com/mob-sakai/ParticleEffectForUGUI.git
synced 2026-05-14 20:20:06 +00:00
3.0.0-preview.19
# [3.0.0-preview.19](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v3.0.0-preview.18...v3.0.0-preview.19) (2020-08-28) ### Bug Fixes * baking camera settings for camera space ([436c5e4](436c5e47f7)) * fix local simulation ([7add9de](7add9defb7)) ### Features * add menu to create UIParticle ([2fa1843](2fa18431f0)) * add play/pause/stop api ([f09a386](f09a386bc5)) * support for changing rendering orders ([745d4a5](745d4a5988)) * Support for child ParticleSystem rendering ([4ee90be](4ee90be17c)) * UIParticle for trail is no longer needed ([466e43c](466e43cf93)) ### BREAKING CHANGES * The child UIParticle is no longer needed.
This commit is contained in:
@@ -9,17 +9,25 @@ namespace Coffee.UIExtensions
|
||||
{
|
||||
static readonly List<UIParticle> s_ActiveParticles = new List<UIParticle>();
|
||||
static MaterialPropertyBlock s_Mpb;
|
||||
static ParticleSystem.Particle[] s_Particles = new ParticleSystem.Particle[2048];
|
||||
|
||||
|
||||
public static void Register(UIParticle particle)
|
||||
{
|
||||
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
|
||||
@@ -55,22 +63,8 @@ namespace Coffee.UIExtensions
|
||||
ModifyScale(particle);
|
||||
Profiler.EndSample();
|
||||
|
||||
if (!particle.isValid) return;
|
||||
|
||||
Profiler.BeginSample("Update trail particle");
|
||||
particle.UpdateTrailParticle();
|
||||
Profiler.EndSample();
|
||||
|
||||
Profiler.BeginSample("Check materials");
|
||||
particle.CheckMaterials();
|
||||
Profiler.EndSample();
|
||||
|
||||
Profiler.BeginSample("Make matrix");
|
||||
var scaledMatrix = GetScaledMatrix(particle);
|
||||
Profiler.EndSample();
|
||||
|
||||
Profiler.BeginSample("Bake mesh");
|
||||
BakeMesh(particle, scaledMatrix);
|
||||
BakeMesh(particle);
|
||||
Profiler.EndSample();
|
||||
|
||||
if (QualitySettings.activeColorSpace == ColorSpace.Linear)
|
||||
@@ -80,78 +74,37 @@ namespace Coffee.UIExtensions
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
Profiler.BeginSample("Set mesh and texture to CanvasRenderer");
|
||||
UpdateMeshAndTexture(particle);
|
||||
Profiler.BeginSample("Set mesh to CanvasRenderer");
|
||||
particle.canvasRenderer.SetMesh(particle.bakedMesh);
|
||||
Profiler.EndSample();
|
||||
|
||||
Profiler.BeginSample("Update Animatable Material Properties");
|
||||
UpdateAnimatableMaterialProperties(particle);
|
||||
// UpdateAnimatableMaterialProperties(particle);
|
||||
Profiler.EndSample();
|
||||
}
|
||||
|
||||
private static void ModifyScale(UIParticle particle)
|
||||
{
|
||||
if (particle.isTrailParticle) return;
|
||||
|
||||
var modifiedScale = particle.m_Scale3D;
|
||||
if (!particle.ignoreCanvasScaler || !particle.canvas) return;
|
||||
|
||||
// Ignore Canvas scaling.
|
||||
if (particle.ignoreCanvasScaler && particle.canvas)
|
||||
{
|
||||
var s = particle.canvas.rootCanvas.transform.localScale;
|
||||
var sInv = new Vector3(
|
||||
Mathf.Approximately(s.x, 0) ? 1 : 1 / s.x,
|
||||
Mathf.Approximately(s.y, 0) ? 1 : 1 / s.y,
|
||||
Mathf.Approximately(s.z, 0) ? 1 : 1 / s.z);
|
||||
modifiedScale = Vector3.Scale(modifiedScale, sInv);
|
||||
}
|
||||
var s = particle.canvas.rootCanvas.transform.localScale;
|
||||
var modifiedScale = new Vector3(
|
||||
Mathf.Approximately(s.x, 0) ? 1 : 1 / s.x,
|
||||
Mathf.Approximately(s.y, 0) ? 1 : 1 / s.y,
|
||||
Mathf.Approximately(s.z, 0) ? 1 : 1 / s.z);
|
||||
|
||||
// Scale is already modified.
|
||||
var tr = particle.transform;
|
||||
if (Mathf.Approximately((tr.localScale - modifiedScale).sqrMagnitude, 0)) return;
|
||||
var transform = particle.transform;
|
||||
if (Mathf.Approximately((transform.localScale - modifiedScale).sqrMagnitude, 0)) return;
|
||||
|
||||
tr.localScale = modifiedScale;
|
||||
transform.localScale = modifiedScale;
|
||||
}
|
||||
|
||||
private static void UpdateMeshAndTexture(UIParticle particle)
|
||||
{
|
||||
// Update mesh.
|
||||
particle.canvasRenderer.SetMesh(particle.bakedMesh);
|
||||
|
||||
// Non sprite mode: external texture is not used.
|
||||
if (!particle.isSpritesMode || particle.isTrailParticle)
|
||||
{
|
||||
particle.canvasRenderer.SetTexture(null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Sprite mode: get sprite's texture.
|
||||
Texture tex = null;
|
||||
Profiler.BeginSample("Check TextureSheetAnimation module");
|
||||
var tsaModule = particle.cachedParticleSystem.textureSheetAnimation;
|
||||
if (tsaModule.enabled && tsaModule.mode == ParticleSystemAnimationMode.Sprites)
|
||||
{
|
||||
var count = tsaModule.spriteCount;
|
||||
for (var i = 0; i < count; i++)
|
||||
{
|
||||
var sprite = tsaModule.GetSprite(i);
|
||||
if (!sprite) continue;
|
||||
|
||||
tex = sprite.GetActualTexture();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
|
||||
particle.canvasRenderer.SetTexture(tex);
|
||||
}
|
||||
|
||||
private static Matrix4x4 GetScaledMatrix(UIParticle particle)
|
||||
private static Matrix4x4 GetScaledMatrix(ParticleSystem particle)
|
||||
{
|
||||
var transform = particle.transform;
|
||||
var tr = particle.isTrailParticle ? transform.parent : transform;
|
||||
var main = particle.mainModule;
|
||||
var main = particle.main;
|
||||
var space = main.simulationSpace;
|
||||
if (space == ParticleSystemSimulationSpace.Custom && !main.customSimulationSpace)
|
||||
space = ParticleSystemSimulationSpace.Local;
|
||||
@@ -159,11 +112,8 @@ namespace Coffee.UIExtensions
|
||||
switch (space)
|
||||
{
|
||||
case ParticleSystemSimulationSpace.Local:
|
||||
var canvasTr = particle.canvas.rootCanvas.transform;
|
||||
return Matrix4x4.Rotate(tr.localRotation).inverse
|
||||
* Matrix4x4.Rotate(canvasTr.localRotation).inverse
|
||||
* Matrix4x4.Scale(tr.localScale).inverse
|
||||
* Matrix4x4.Scale(canvasTr.localScale).inverse;
|
||||
return Matrix4x4.Rotate(transform.rotation).inverse
|
||||
* Matrix4x4.Scale(transform.lossyScale).inverse;
|
||||
case ParticleSystemSimulationSpace.World:
|
||||
return transform.worldToLocalMatrix;
|
||||
case ParticleSystemSimulationSpace.Custom:
|
||||
@@ -175,51 +125,118 @@ namespace Coffee.UIExtensions
|
||||
}
|
||||
}
|
||||
|
||||
private static void BakeMesh(UIParticle particle, Matrix4x4 scaledMatrix)
|
||||
private static void BakeMesh(UIParticle particle)
|
||||
{
|
||||
// Clear mesh before bake.
|
||||
MeshHelper.Clear();
|
||||
particle.bakedMesh.Clear();
|
||||
particle.bakedMesh.Clear(false);
|
||||
|
||||
// No particle to render.
|
||||
if (particle.cachedParticleSystem.particleCount <= 0) return;
|
||||
// if (!particle.isValid) return;
|
||||
|
||||
// Get camera for baking mesh.
|
||||
var cam = BakingCamera.GetCamera(particle.canvas);
|
||||
var renderer = particle.cachedRenderer;
|
||||
var trail = particle.trailModule;
|
||||
var camera = BakingCamera.GetCamera(particle.canvas);
|
||||
var root = particle.transform;
|
||||
var rootMatrix = Matrix4x4.Rotate(root.rotation).inverse
|
||||
* Matrix4x4.Scale(root.lossyScale).inverse;
|
||||
var scaleMatrix = particle.ignoreCanvasScaler
|
||||
? Matrix4x4.Scale(particle.canvas.rootCanvas.transform.localScale.x * particle.scale * Vector3.one)
|
||||
: Matrix4x4.Scale(particle.scale * Vector3.one);
|
||||
|
||||
Profiler.BeginSample("Bake mesh");
|
||||
if (!particle.isSpritesMode) // Non sprite mode: bake main particle and trail particle.
|
||||
{
|
||||
if (CanBakeMesh(renderer))
|
||||
renderer.BakeMesh(MeshHelper.GetTemporaryMesh(), cam, true);
|
||||
// Cache position
|
||||
var position = particle.transform.position;
|
||||
var diff = (position - particle.cachedPosition) * (1 - 1 / particle.scale);
|
||||
particle.cachedPosition = position;
|
||||
|
||||
if (trail.enabled)
|
||||
renderer.BakeTrailsMesh(MeshHelper.GetTemporaryMesh(), cam, true);
|
||||
}
|
||||
else if (particle.isTrailParticle) // Sprite mode (trail): bake trail particle.
|
||||
for (var i = 0; i < particle.particles.Count; i++)
|
||||
{
|
||||
if (trail.enabled)
|
||||
renderer.BakeTrailsMesh(MeshHelper.GetTemporaryMesh(), cam, true);
|
||||
}
|
||||
else // Sprite mode (main): bake main particle.
|
||||
{
|
||||
if (CanBakeMesh(renderer))
|
||||
renderer.BakeMesh(MeshHelper.GetTemporaryMesh(), cam, true);
|
||||
// No particle to render.
|
||||
var currentPs = particle.particles[i];
|
||||
if (!currentPs || !currentPs.IsAlive() || currentPs.particleCount == 0) continue;
|
||||
|
||||
// Calc matrix.
|
||||
var matrix = rootMatrix;
|
||||
if (currentPs.transform != root)
|
||||
{
|
||||
if (currentPs.main.simulationSpace == ParticleSystemSimulationSpace.Local)
|
||||
{
|
||||
var relativePos = root.InverseTransformPoint(currentPs.transform.position);
|
||||
matrix = Matrix4x4.Translate(relativePos) * matrix;
|
||||
}
|
||||
else
|
||||
{
|
||||
matrix = matrix * Matrix4x4.Translate(-root.position);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
matrix = GetScaledMatrix(currentPs);
|
||||
}
|
||||
|
||||
// Set transform
|
||||
MeshHelper.SetTransform(scaleMatrix * matrix);
|
||||
|
||||
// Extra world simulation.
|
||||
if (currentPs.main.simulationSpace == ParticleSystemSimulationSpace.World && 0 < diff.sqrMagnitude)
|
||||
{
|
||||
var count = currentPs.particleCount;
|
||||
if (s_Particles.Length < count)
|
||||
{
|
||||
var size = Mathf.NextPowerOfTwo(count);
|
||||
s_Particles = new ParticleSystem.Particle[size];
|
||||
}
|
||||
|
||||
currentPs.GetParticles(s_Particles);
|
||||
for (var j = 0; j < count; j++)
|
||||
{
|
||||
var p = s_Particles[j];
|
||||
p.position += diff;
|
||||
s_Particles[j] = p;
|
||||
}
|
||||
|
||||
currentPs.SetParticles(s_Particles, count);
|
||||
}
|
||||
|
||||
// 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();
|
||||
}
|
||||
|
||||
// Bake trails particles.
|
||||
if (currentPs.trails.enabled)
|
||||
{
|
||||
var m = MeshHelper.GetTemporaryMesh(i * 2 + 1);
|
||||
try
|
||||
{
|
||||
r.BakeTrailsMesh(m, camera, true);
|
||||
|
||||
if (m.vertexCount == 0)
|
||||
MeshHelper.DiscardTemporaryMesh();
|
||||
}
|
||||
catch
|
||||
{
|
||||
MeshHelper.DiscardTemporaryMesh();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Profiler.EndSample();
|
||||
|
||||
Profiler.BeginSample("Apply matrix to position");
|
||||
MeshHelper.CombineMesh(particle.bakedMesh, scaledMatrix);
|
||||
Profiler.EndSample();
|
||||
// Set active indices.
|
||||
particle.activeMeshIndices = MeshHelper.activeMeshIndices;
|
||||
|
||||
// Combine
|
||||
MeshHelper.CombineMesh(particle.bakedMesh);
|
||||
}
|
||||
|
||||
private static bool CanBakeMesh(ParticleSystemRenderer renderer)
|
||||
{
|
||||
// #69: Editor crashes when mesh is set to null when `ParticleSystem.RenderMode = Mesh`
|
||||
if (renderer.renderMode == ParticleSystemRenderMode.Mesh && !renderer.mesh) return false;
|
||||
if (renderer.renderMode == ParticleSystemRenderMode.Mesh && renderer.mesh == null) return false;
|
||||
|
||||
// #61: When `ParticleSystem.RenderMode = None`, an error occurs
|
||||
if (renderer.renderMode == ParticleSystemRenderMode.None) return false;
|
||||
@@ -230,7 +247,7 @@ namespace Coffee.UIExtensions
|
||||
/// <summary>
|
||||
/// Copy the value from MaterialPropertyBlock to CanvasRenderer
|
||||
/// </summary>
|
||||
private static void UpdateAnimatableMaterialProperties(UIParticle particle)
|
||||
private static void UpdateAnimatableMaterialProperties(UIParticle particle, ParticleSystemRenderer renderer)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying) return;
|
||||
@@ -244,7 +261,7 @@ namespace Coffee.UIExtensions
|
||||
// #41: Copy the value from MaterialPropertyBlock to CanvasRenderer
|
||||
if (s_Mpb == null)
|
||||
s_Mpb = new MaterialPropertyBlock();
|
||||
particle.cachedRenderer.GetPropertyBlock(s_Mpb);
|
||||
renderer.GetPropertyBlock(s_Mpb);
|
||||
foreach (var ap in particle.m_AnimatableProperties)
|
||||
{
|
||||
ap.UpdateMaterialProperties(mat, s_Mpb);
|
||||
|
||||
Reference in New Issue
Block a user