Compare commits

..

14 Commits

Author SHA1 Message Date
mob-sakai 174af4bf7b fix: UIParticleAttractor attracts the particles at wrong position when in RelativeMode
close #262
2023-08-15 09:40:11 +09:00
mob-sakai 65770cadda feat: add public properties for UIParticleAttractor
close #253
2023-08-15 09:40:11 +09:00
mob-sakai 12b5aacf1d refactor 2023-08-15 09:40:11 +09:00
mob-sakai fa8d7fa312 fix: assertion 'ps->array_size()' in UpdateMesh() when using trails of type ribbon
close #241
2023-08-15 09:40:11 +09:00
mob-sakai dc82e4074d fix: change AbsoluteMode default value to true 2023-08-15 09:40:11 +09:00
mob-sakai 924550b0fc fix: scaling ParticleSystem puts prewarmed particles in wrong location
close #235
2023-08-15 09:40:11 +09:00
mob-sakai c4e4fce26f fix: nullReferenceException after copy-n-paste
close #258
2023-08-15 09:40:11 +09:00
mob-sakai ab427e9b6a fix: mesh sharing not working 2023-08-15 09:40:11 +09:00
mob-sakai 5a21298c02 fix: sub-emitters option is not work in editor playing
close #231
2023-08-15 09:40:11 +09:00
mob-sakai 60932e92c1 fix: nullptr exceptions when using nested UIParticle components in hierarchy
close #246
2023-08-15 09:40:11 +09:00
mob-sakai c75ca8663f fix: crash occurs when too many vertices are rendered 2023-08-15 09:40:11 +09:00
mob-sakai 52f2ef1f24 fix: fix typos 2023-08-15 09:40:11 +09:00
Jake O'Connor e92b514624 fix: remove unnecessary per-frame allocation. 2023-08-15 09:40:11 +09:00
AndreevWezom a4bcf93022 feat: add particle system getter and setter for attractor
close #253
2023-08-15 09:40:11 +09:00
3 changed files with 135 additions and 54 deletions

View File

@ -27,7 +27,7 @@ namespace Coffee.UIExtensions
Auto,
Primary,
PrimarySimulator,
Reprica,
Replica,
}
[HideInInspector][SerializeField] internal bool m_IsTrail = false;
@ -44,7 +44,7 @@ namespace Coffee.UIExtensions
[SerializeField]
private List<ParticleSystem> m_Particles = new List<ParticleSystem>();
[Tooltip("Mesh sharing.None: disable mesh sharing.\nAuto: automatically select Primary/Reprica.\nPrimary: provides particle simulation results to the same group.\nPrimary Simulator: Primary, but do not render the particle (simulation only).\nReprica: render simulation results provided by the primary.")]
[Tooltip("Mesh sharing.None: disable mesh sharing.\nAuto: automatically select Primary/Replica.\nPrimary: provides particle simulation results to the same group.\nPrimary Simulator: Primary, but do not render the particle (simulation only).\nReplica: render simulation results provided by the primary.")]
[SerializeField]
private MeshSharing m_MeshSharing = MeshSharing.None;
@ -57,7 +57,7 @@ namespace Coffee.UIExtensions
[SerializeField]
[Tooltip("The particles will be emitted at the ParticleSystem position.\nMove the UIParticle/ParticleSystem to move the particle.")]
private bool m_AbsoluteMode = false;
private bool m_AbsoluteMode = true;
private List<UIParticleRenderer> m_Renderers = new List<UIParticleRenderer>();
@ -80,10 +80,10 @@ namespace Coffee.UIExtensions
/// <summary>
/// Mesh sharing.None: disable mesh sharing.
/// Auto: automatically select Primary/Reprica.
/// Auto: automatically select Primary/Replica.
/// Primary: provides particle simulation results to the same group.
/// Primary Simulator: Primary, but do not render the particle (simulation only).
/// Reprica: render simulation results provided by the primary.
/// Replica: render simulation results provided by the primary.
/// </summary>
public MeshSharing meshSharing
{
@ -145,7 +145,7 @@ namespace Coffee.UIExtensions
internal bool canRender
{
get { return m_MeshSharing == MeshSharing.None || m_MeshSharing == MeshSharing.Auto || m_MeshSharing == MeshSharing.Primary || m_MeshSharing == MeshSharing.Reprica; }
get { return m_MeshSharing == MeshSharing.None || m_MeshSharing == MeshSharing.Auto || m_MeshSharing == MeshSharing.Primary || m_MeshSharing == MeshSharing.Replica; }
}
/// <summary>
@ -286,7 +286,22 @@ namespace Coffee.UIExtensions
public void RefreshParticles(List<ParticleSystem> particles)
{
GetComponentsInChildren(m_Renderers);
// #246: Nullptr exceptions when using nested UIParticle components in hierarchy
m_Renderers.Clear();
foreach (Transform child in transform)
{
var uiParticleRenderer = child.GetComponent<UIParticleRenderer>();
if (uiParticleRenderer != null)
{
m_Renderers.Add(uiParticleRenderer);
}
}
for (var i = 0; i < m_Renderers.Count; i++)
{
m_Renderers[i].Reset(i);
}
var j = 0;
for (var i = 0; i < particles.Count; i++)
@ -298,11 +313,6 @@ namespace Coffee.UIExtensions
GetRenderer(j++).Set(this, particles[i], true);
}
}
for (; j < m_Renderers.Count; j++)
{
GetRenderer(j).Clear(j);
}
}
internal void UpdateTransformScale()
@ -323,9 +333,13 @@ namespace Coffee.UIExtensions
{
if (!isActiveAndEnabled) return;
if (m_Renderers.Any(x => !x))
foreach (var rend in m_Renderers)
{
RefreshParticles(particles);
if (!rend)
{
RefreshParticles(particles);
break;
}
}
var bakeCamera = GetBakeCamera();
@ -386,7 +400,7 @@ namespace Coffee.UIExtensions
{
_tracker.Clear();
UIParticleUpdater.Unregister(this);
m_Renderers.ForEach(r => r.Clear());
m_Renderers.ForEach(r => r.Reset());
UnregisterDirtyMaterialCallback(UpdateRendererMaterial);
base.OnDisable();
@ -437,9 +451,12 @@ namespace Coffee.UIExtensions
{
if (!canvas) return Camera.main;
// World camera.
// Render mode is not ScreenSpaceOverlay, use world camera.
var root = canvas.rootCanvas;
if (root.renderMode != RenderMode.ScreenSpaceOverlay) return root.worldCamera ? root.worldCamera : Camera.main;
if (root.renderMode != RenderMode.ScreenSpaceOverlay)
{
return root.worldCamera ? root.worldCamera : Camera.main;
}
// Create ortho-camera.
if (!_orthoCamera)

View File

@ -36,6 +36,12 @@ namespace Coffee.UIExtensions
[SerializeField]
private UnityEvent m_OnAttracted;
public float destinationRadius
{
get { return m_DestinationRadius; }
set { m_DestinationRadius = Mathf.Clamp(value, 0.1f, 10f); }
}
public float delay
{
get
@ -72,22 +78,31 @@ namespace Coffee.UIExtensions
}
}
public UnityEvent onAttracted
{
get { return m_OnAttracted; }
set { m_OnAttracted = value; }
}
public ParticleSystem particleSystem
{
get
{
return m_ParticleSystem;
}
set
{
m_ParticleSystem = value;
if (!ApplyParticleSystem()) return;
enabled = true;
}
}
private UIParticle _uiParticle;
private void OnEnable()
{
if (m_ParticleSystem == null)
{
Debug.LogError("No particle system attached to particle attractor script", this);
enabled = false;
return;
}
_uiParticle = m_ParticleSystem.GetComponentInParent<UIParticle>();
if (_uiParticle && !_uiParticle.particles.Contains(m_ParticleSystem))
{
_uiParticle = null;
}
if (!ApplyParticleSystem()) return;
UIParticleUpdater.Register(this);
}
@ -154,29 +169,32 @@ namespace Coffee.UIExtensions
var psPos = m_ParticleSystem.transform.position;
var attractorPos = transform.position;
var dstPos = attractorPos;
if (m_ParticleSystem.main.simulationSpace == ParticleSystemSimulationSpace.Local)
var isLocalSpace = m_ParticleSystem.main.simulationSpace == ParticleSystemSimulationSpace.Local;
if (isLocalSpace)
{
dstPos = m_ParticleSystem.transform.InverseTransformPoint(dstPos);
if (isUI)
{
dstPos = dstPos.GetScaled(_uiParticle.transform.localScale, _uiParticle.scale3D.Inverse());
}
}
else
if (isUI)
{
#if UNITY_EDITOR
if (!Application.isPlaying && isUI)
dstPos = dstPos.GetScaled(_uiParticle.transform.localScale, _uiParticle.scale3D.Inverse());
// Relative mode
if (!_uiParticle.absoluteMode)
{
var diff = dstPos - psPos;
diff = diff.GetScaled(_uiParticle.transform.localScale, _uiParticle.scale3D.Inverse());
return psPos + diff;
var diff = _uiParticle.transform.position - psPos;
diff.Scale(_uiParticle.scale3D - _uiParticle.transform.localScale);
diff.Scale(_uiParticle.scale3D.Inverse());
dstPos += diff;
}
#if UNITY_EDITOR
if (!Application.isPlaying && !isLocalSpace)
{
dstPos += psPos - psPos.GetScaled(_uiParticle.transform.localScale, _uiParticle.scale3D.Inverse());
}
#endif
if (isUI)
{
dstPos.Scale(_uiParticle.transform.localScale);
dstPos.Scale(_uiParticle.scale3D.Inverse());
}
}
return dstPos;
}
@ -200,5 +218,22 @@ namespace Coffee.UIExtensions
return Vector3.MoveTowards(current, target, speed);
}
private bool ApplyParticleSystem()
{
if (m_ParticleSystem == null)
{
Debug.LogError("No particle system attached to particle attractor script", this);
enabled = false;
return false;
}
_uiParticle = m_ParticleSystem.GetComponentInParent<UIParticle>();
if (_uiParticle && !_uiParticle.particles.Contains(m_ParticleSystem))
{
_uiParticle = null;
}
return true;
}
}
}

View File

@ -112,7 +112,12 @@ namespace Coffee.UIExtensions
{
_currentMaterialForRendering = null;
if (!IsActive()) return baseMaterial;
if (!IsActive() || !_parent)
{
ModifiedMaterial.Remove(_modifiedMaterial);
_modifiedMaterial = null;
return baseMaterial;
}
var modifiedMaterial = base.GetModifiedMaterial(baseMaterial);
@ -134,7 +139,7 @@ namespace Coffee.UIExtensions
return modifiedMaterial;
}
public void Clear(int index = -1)
public void Reset(int index = -1)
{
if (_renderer)
{
@ -157,6 +162,12 @@ namespace Coffee.UIExtensions
_lastBounds = new Bounds();
enabled = false;
}
else
{
ModifiedMaterial.Remove(_modifiedMaterial);
_modifiedMaterial = null;
_currentMaterialForRendering = null;
}
}
public void Set(UIParticle parent, ParticleSystem particleSystem, bool isTrail)
@ -167,15 +178,18 @@ namespace Coffee.UIExtensions
gameObject.layer = parent.gameObject.layer;
_particleSystem = particleSystem;
_prewarm = _particleSystem.main.prewarm;
#if UNITY_EDITOR
if (Application.isPlaying)
#endif
if (_particleSystem.isPlaying)
{
_particleSystem.Clear();
_particleSystem.Pause();
if (_particleSystem.isPlaying || _prewarm)
{
_particleSystem.Clear();
_particleSystem.Pause();
}
}
_prewarm = _particleSystem.main.prewarm;
_renderer = particleSystem.GetComponent<ParticleSystemRenderer>();
_renderer.enabled = false;
@ -208,7 +222,7 @@ namespace Coffee.UIExtensions
// No particle to render: Clear mesh.
if (
!isActiveAndEnabled || !_particleSystem || !_parent || !canvasRenderer || !canvas || !bakeCamera
|| _parent.meshSharing == UIParticle.MeshSharing.Reprica
|| _parent.meshSharing == UIParticle.MeshSharing.Replica
|| !transform.lossyScale.GetScaled(_parent.scale3D).IsVisible() // Scale is not visible.
|| (!_particleSystem.IsAlive() && !_particleSystem.isPlaying) // No particle.
|| (_isTrail && !_particleSystem.trails.enabled) // Trail, but it is not enabled.
@ -264,7 +278,7 @@ namespace Coffee.UIExtensions
// Bake mesh.
Profiler.BeginSample("[UIParticleRenderer] Bake Mesh");
if (_isTrail && _parent.canSimulate)
if (_isTrail && _parent.canSimulate && 0 < s_CombineInstances[0].mesh.vertices.Length)
{
_renderer.BakeTrailsMesh(s_CombineInstances[0].mesh, bakeCamera, true);
}
@ -276,6 +290,18 @@ namespace Coffee.UIExtensions
{
s_CombineInstances[0].mesh.Clear(false);
}
// Too many vertices to render.
if (65535 <= s_CombineInstances[0].mesh.vertexCount)
{
s_CombineInstances[0].mesh.Clear(false);
UnityEngine.Debug.LogErrorFormat(this,
"Too many vertices to render. index={0}, isTrail={1}, vertexCount={2}(>=65535)",
_index,
_isTrail,
s_CombineInstances[0].mesh.vertexCount
);
}
Profiler.EndSample();
// Combine mesh to transform. ([ParticleSystem local ->] world -> renderer local)
@ -507,6 +533,8 @@ namespace Coffee.UIExtensions
_prewarm = false;
}
// (COMMENT OUT) #231: Sub Emitters option is not work in editor playing
/*
// Emitted particles found.
if (_prevParticleCount != _particleSystem.particleCount)
{
@ -522,6 +550,7 @@ namespace Coffee.UIExtensions
_particleSystem.SetParticles(particles, size);
}
*/
// get world position.
var psTransform = _particleSystem.transform;