feat: UIParticle no longer inherits from MaskableGraphic

BREAKING CHANGE: Some members inherited from MaskableGraphic will no longer be available.
mob-sakai 2024-01-29 10:00:24 +09:00
parent a3e725fd5a
commit acebfb27f6
3 changed files with 144 additions and 100 deletions

View File

@ -2,7 +2,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using UnityEditor; using UnityEditor;
using UnityEditor.UI;
using UnityEditorInternal; using UnityEditorInternal;
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
@ -18,6 +17,7 @@ using Object = UnityEngine.Object;
#if UNITY_2021_2_OR_NEWER #if UNITY_2021_2_OR_NEWER
using UnityEditor.SceneManagement; using UnityEditor.SceneManagement;
#elif UNITY_2018_3_OR_NEWER #elif UNITY_2018_3_OR_NEWER
using UnityEditor.Experimental.SceneManagement; using UnityEditor.Experimental.SceneManagement;
#endif #endif
@ -26,7 +26,7 @@ namespace Coffee.UIExtensions
{ {
[CustomEditor(typeof(UIParticle))] [CustomEditor(typeof(UIParticle))]
[CanEditMultipleObjects] [CanEditMultipleObjects]
internal class UIParticleEditor : GraphicEditor internal class UIParticleEditor : Editor
{ {
#if UNITY_2021_2_OR_NEWER #if UNITY_2021_2_OR_NEWER
#if UNITY_2022_1_OR_NEWER #if UNITY_2022_1_OR_NEWER
@ -146,10 +146,8 @@ namespace Coffee.UIExtensions
/// <summary> /// <summary>
/// This function is called when the object becomes enabled and active. /// This function is called when the object becomes enabled and active.
/// </summary> /// </summary>
protected override void OnEnable() private void OnEnable()
{ {
base.OnEnable();
_maskable = serializedObject.FindProperty("m_Maskable"); _maskable = serializedObject.FindProperty("m_Maskable");
_scale3D = serializedObject.FindProperty("m_Scale3D"); _scale3D = serializedObject.FindProperty("m_Scale3D");
_animatableProperties = serializedObject.FindProperty("m_AnimatableProperties"); _animatableProperties = serializedObject.FindProperty("m_AnimatableProperties");
@ -529,9 +527,7 @@ namespace Coffee.UIExtensions
{ {
if (!p || (ignoreCurrent && target == p)) return; if (!p || (ignoreCurrent && target == p)) return;
var cr = p.canvasRenderer;
DestroyImmediate(p); DestroyImmediate(p);
DestroyImmediate(cr);
#if UNITY_2018_3_OR_NEWER #if UNITY_2018_3_OR_NEWER
var stage = PrefabStageUtility.GetCurrentPrefabStage(); var stage = PrefabStageUtility.GetCurrentPrefabStage();

View File

@ -6,7 +6,6 @@ using UnityEngine;
using UnityEngine.EventSystems; using UnityEngine.EventSystems;
using UnityEngine.Rendering; using UnityEngine.Rendering;
using UnityEngine.Serialization; using UnityEngine.Serialization;
using UnityEngine.UI;
using Random = UnityEngine.Random; using Random = UnityEngine.Random;
[assembly: InternalsVisibleTo("Coffee.UIParticle.Editor")] [assembly: InternalsVisibleTo("Coffee.UIParticle.Editor")]
@ -19,7 +18,7 @@ namespace Coffee.UIExtensions
[ExecuteAlways] [ExecuteAlways]
[RequireComponent(typeof(RectTransform))] [RequireComponent(typeof(RectTransform))]
[RequireComponent(typeof(CanvasRenderer))] [RequireComponent(typeof(CanvasRenderer))]
public class UIParticle : MaskableGraphic, ISerializationCallbackReceiver public class UIParticle : UIBehaviour, ISerializationCallbackReceiver
{ {
public enum AutoScalingMode public enum AutoScalingMode
{ {
@ -45,16 +44,19 @@ namespace Coffee.UIExtensions
[HideInInspector] [HideInInspector]
[SerializeField] [SerializeField]
[Obsolete]
internal bool m_IsTrail; internal bool m_IsTrail;
[HideInInspector] [HideInInspector]
[FormerlySerializedAs("m_IgnoreParent")] [FormerlySerializedAs("m_IgnoreParent")]
[SerializeField] [SerializeField]
[Obsolete]
private bool m_IgnoreCanvasScaler; private bool m_IgnoreCanvasScaler;
[HideInInspector] [HideInInspector]
[SerializeField] [SerializeField]
private bool m_AbsoluteMode; [Obsolete]
internal bool m_AbsoluteMode;
[Tooltip("Particle effect scale")] [Tooltip("Particle effect scale")]
[SerializeField] [SerializeField]
@ -93,25 +95,54 @@ namespace Coffee.UIExtensions
[SerializeField] [SerializeField]
[Tooltip("Prevent the root-Canvas scale from affecting the hierarchy-scaled ParticleSystem.")] [Tooltip("Prevent the root-Canvas scale from affecting the hierarchy-scaled ParticleSystem.")]
private bool m_AutoScaling = true; [Obsolete]
internal bool m_AutoScaling;
[SerializeField] [SerializeField]
[Tooltip("Transform: Transform.lossyScale (=world scale) will be set to (1, 1, 1)." + [Tooltip("Transform: Transform.lossyScale (=world scale) will be set to (1, 1, 1)." +
"UIParticle: UIParticle.scale will be adjusted.")] "UIParticle: UIParticle.scale will be adjusted.")]
private AutoScalingMode m_AutoScalingMode = AutoScalingMode.Transform; private AutoScalingMode m_AutoScalingMode = AutoScalingMode.Transform;
[SerializeField]
private bool m_Maskable = true;
private readonly List<UIParticleRenderer> _renderers = new List<UIParticleRenderer>(); private readonly List<UIParticleRenderer> _renderers = new List<UIParticleRenderer>();
private Canvas _canvas;
private int _groupId; private int _groupId;
private Camera _orthoCamera; private Camera _orthoCamera;
private DrivenRectTransformTracker _tracker; private DrivenRectTransformTracker _tracker;
/// <summary> public RectTransform rectTransform => transform as RectTransform;
/// Should this graphic be considered a target for ray-casting?
/// </summary> public Canvas canvas
public override bool raycastTarget
{ {
get => false; get
set { } {
if (_canvas) return _canvas;
var tr = transform;
while (tr && !_canvas)
{
if (tr.TryGetComponent(out _canvas)) return _canvas;
tr = tr.parent;
}
return null;
}
}
/// <summary>
/// Does this graphic allow masking.
/// </summary>
public bool maskable
{
get => m_Maskable;
set
{
if (value == m_Maskable) return;
m_Maskable = value;
UpdateRendererMaterial();
}
} }
/// <summary> /// <summary>
@ -266,8 +297,6 @@ namespace Coffee.UIExtensions
} }
} }
public override Material materialForRendering => null;
/// <summary> /// <summary>
/// Paused. /// Paused.
/// </summary> /// </summary>
@ -282,8 +311,8 @@ namespace Coffee.UIExtensions
ResetGroupId(); ResetGroupId();
UpdateTracker(); UpdateTracker();
UIParticleUpdater.Register(this); UIParticleUpdater.Register(this);
RegisterDirtyMaterialCallback(UpdateRendererMaterial);
//
if (0 < particles.Count) if (0 < particles.Count)
{ {
RefreshParticles(particles); RefreshParticles(particles);
@ -293,7 +322,7 @@ namespace Coffee.UIExtensions
RefreshParticles(); RefreshParticles();
} }
base.OnEnable(); UpdateRendererMaterial();
} }
/// <summary> /// <summary>
@ -304,9 +333,15 @@ namespace Coffee.UIExtensions
UpdateTracker(); UpdateTracker();
UIParticleUpdater.Unregister(this); UIParticleUpdater.Unregister(this);
_renderers.ForEach(r => r.Reset()); _renderers.ForEach(r => r.Reset());
UnregisterDirtyMaterialCallback(UpdateRendererMaterial); _canvas = null;
}
base.OnDisable(); /// <summary>
/// Called when the state of the parent Canvas is changed.
/// </summary>
protected override void OnCanvasHierarchyChanged()
{
_canvas = null;
} }
/// <summary> /// <summary>
@ -316,11 +351,20 @@ namespace Coffee.UIExtensions
{ {
} }
/// <summary>
/// This function is called when a direct or indirect parent of the transform of the GameObject has changed.
/// </summary>
protected override void OnTransformParentChanged()
{
_canvas = null;
}
#if UNITY_EDITOR #if UNITY_EDITOR
protected override void OnValidate() protected override void OnValidate()
{ {
base.OnValidate(); base.OnValidate();
UpdateTracker(); UpdateTracker();
UpdateRendererMaterial();
} }
#endif #endif
@ -330,6 +374,7 @@ namespace Coffee.UIExtensions
void ISerializationCallbackReceiver.OnAfterDeserialize() void ISerializationCallbackReceiver.OnAfterDeserialize()
{ {
#pragma warning disable CS0612 // Type or member is obsolete
if (m_IgnoreCanvasScaler || m_AutoScaling) if (m_IgnoreCanvasScaler || m_AutoScaling)
{ {
m_IgnoreCanvasScaler = false; m_IgnoreCanvasScaler = false;
@ -342,6 +387,7 @@ namespace Coffee.UIExtensions
m_AbsoluteMode = false; m_AbsoluteMode = false;
m_PositionMode = PositionMode.Absolute; m_PositionMode = PositionMode.Absolute;
} }
#pragma warning restore CS0612 // Type or member is obsolete
} }
public void Play() public void Play()
@ -400,9 +446,10 @@ namespace Coffee.UIExtensions
{ {
if (!instance) return; if (!instance) return;
foreach (Transform child in transform) var childCount = transform.childCount;
for (var i = 0; i < childCount; i++)
{ {
var go = child.gameObject; var go = transform.GetChild(i).gameObject;
go.SetActive(false); go.SetActive(false);
if (destroyOldParticles) if (destroyOldParticles)
{ {
@ -433,7 +480,14 @@ namespace Coffee.UIExtensions
{ {
if (!root) return; if (!root) return;
root.GetComponentsInChildren(true, particles); root.GetComponentsInChildren(true, particles);
particles.RemoveAll(x => x.GetComponentInParent<UIParticle>(true) != this); for (var i = particles.Count - 1; 0 <= i; i--)
{
var ps = particles[i];
if (!ps || ps.GetComponentInParent<UIParticle>(true) != this)
{
particles.RemoveAt(i);
}
}
for (var i = 0; i < particles.Count; i++) for (var i = 0; i < particles.Count; i++)
{ {
@ -448,31 +502,39 @@ namespace Coffee.UIExtensions
RefreshParticles(particles); RefreshParticles(particles);
} }
public void RefreshParticles(List<ParticleSystem> particles) /// <summary>
/// Refresh UIParticle using a list of ParticleSystems.
/// </summary>
public void RefreshParticles(List<ParticleSystem> particleSystems)
{ {
// Collect children UIParticleRenderer components.
// #246: Nullptr exceptions when using nested UIParticle components in hierarchy // #246: Nullptr exceptions when using nested UIParticle components in hierarchy
_renderers.Clear(); _renderers.Clear();
foreach (Transform child in transform) var childCount = transform.childCount;
for (var i = 0; i < childCount; i++)
{ {
var uiParticleRenderer = child.GetComponent<UIParticleRenderer>(); var child = transform.GetChild(i);
if (child.TryGetComponent(out UIParticleRenderer uiParticleRenderer))
if (uiParticleRenderer != null)
{ {
_renderers.Add(uiParticleRenderer); _renderers.Add(uiParticleRenderer);
} }
} }
// Reset the UIParticleRenderer components.
for (var i = 0; i < _renderers.Count; i++) for (var i = 0; i < _renderers.Count; i++)
{ {
_renderers[i].Reset(i); _renderers[i].Reset(i);
} }
// Set the ParticleSystem to the UIParticleRenderer. If the trail is enabled, set it additionally.
var j = 0; var j = 0;
for (var i = 0; i < particles.Count; i++) for (var i = 0; i < particleSystems.Count; i++)
{ {
var ps = particles[i]; var ps = particleSystems[i];
if (!ps) continue; if (!ps) continue;
GetRenderer(j++).Set(this, ps, false); GetRenderer(j++).Set(this, ps, false);
// If the trail is enabled, set it additionally.
if (ps.trails.enabled) if (ps.trails.enabled)
{ {
GetRenderer(j++).Set(this, ps, true); GetRenderer(j++).Set(this, ps, true);
@ -500,11 +562,10 @@ namespace Coffee.UIExtensions
for (var i = 0; i < _renderers.Count; i++) for (var i = 0; i < _renderers.Count; i++)
{ {
var r = _renderers[i]; var r = _renderers[i];
if (!r) if (r) continue;
{
RefreshParticles(particles); RefreshParticles(particles);
break; break;
}
} }
var bakeCamera = GetBakeCamera(); var bakeCamera = GetBakeCamera();
@ -512,6 +573,7 @@ namespace Coffee.UIExtensions
{ {
var r = _renderers[i]; var r = _renderers[i];
if (!r) continue; if (!r) continue;
r.UpdateMesh(bakeCamera); r.UpdateMesh(bakeCamera);
} }
} }
@ -523,17 +585,6 @@ namespace Coffee.UIExtensions
: Random.Range(m_GroupId, m_GroupMaxId + 1); : Random.Range(m_GroupId, m_GroupMaxId + 1);
} }
protected override void UpdateMaterial()
{
}
/// <summary>
/// Call to update the geometry of the Graphic onto the CanvasRenderer.
/// </summary>
protected override void UpdateGeometry()
{
}
private void UpdateRendererMaterial() private void UpdateRendererMaterial()
{ {
for (var i = 0; i < _renderers.Count; i++) for (var i = 0; i < _renderers.Count; i++)
@ -574,11 +625,12 @@ namespace Coffee.UIExtensions
// When render mode is ScreenSpaceOverlay, use ortho-camera. // When render mode is ScreenSpaceOverlay, use ortho-camera.
if (!_orthoCamera) if (!_orthoCamera)
{ {
// Find existing ortho-camera. // Find existing orthographic-camera.
foreach (Transform child in transform) var childCount = transform.childCount;
for (var i = 0; i < childCount; i++)
{ {
var cam = child.GetComponent<Camera>(); if (transform.GetChild(i).TryGetComponent<Camera>(out var cam)
if (cam && cam.name == "[generated] UIParticleOverlayCamera") && cam.name == "[generated] UIParticleOverlayCamera")
{ {
_orthoCamera = cam; _orthoCamera = cam;
break; break;
@ -600,8 +652,7 @@ namespace Coffee.UIExtensions
} }
// //
var size = ((RectTransform)root.transform).rect.size; _orthoCamera.orthographicSize = 10;
_orthoCamera.orthographicSize = Mathf.Max(size.x, size.y) * root.scaleFactor;
_orthoCamera.transform.SetPositionAndRotation(new Vector3(0, 0, -1000), Quaternion.identity); _orthoCamera.transform.SetPositionAndRotation(new Vector3(0, 0, -1000), Quaternion.identity);
_orthoCamera.orthographic = true; _orthoCamera.orthographic = true;
_orthoCamera.farClipPlane = 2000f; _orthoCamera.farClipPlane = 2000f;
@ -612,7 +663,7 @@ namespace Coffee.UIExtensions
private void UpdateTracker() private void UpdateTracker()
{ {
#pragma warning disable CS0618 // Type or member is obsolete #pragma warning disable CS0618 // Type or member is obsolete
if (!enabled || !autoScaling || autoScalingMode != AutoScalingMode.Transform) if (!enabled || autoScalingMode != AutoScalingMode.Transform)
#pragma warning restore CS0618 // Type or member is obsolete #pragma warning restore CS0618 // Type or member is obsolete
{ {
_tracker.Clear(); _tracker.Clear();

View File

@ -33,6 +33,7 @@ namespace Coffee.UIExtensions
private int _index; private int _index;
private bool _isTrail; private bool _isTrail;
private Bounds _lastBounds; private Bounds _lastBounds;
private Material _materialForRendering;
private Material _modifiedMaterial; private Material _modifiedMaterial;
private UIParticle _parent; private UIParticle _parent;
private ParticleSystem _particleSystem; private ParticleSystem _particleSystem;
@ -91,6 +92,19 @@ namespace Coffee.UIExtensions
} }
} }
public override Material materialForRendering
{
get
{
if (!_materialForRendering)
{
_materialForRendering = base.materialForRendering;
}
return _materialForRendering;
}
}
public void Reset(int index = -1) public void Reset(int index = -1)
{ {
if (_renderer) if (_renderer)
@ -110,8 +124,7 @@ namespace Coffee.UIExtensions
if (this && isActiveAndEnabled) if (this && isActiveAndEnabled)
{ {
material = null; material = null;
workerMesh.Clear(); canvasRenderer.Clear();
canvasRenderer.SetMesh(workerMesh);
_lastBounds = new Bounds(); _lastBounds = new Bounds();
enabled = false; enabled = false;
} }
@ -202,10 +215,11 @@ namespace Coffee.UIExtensions
); );
if (!MaterialRepository.Valid(hash, _modifiedMaterial)) if (!MaterialRepository.Valid(hash, _modifiedMaterial))
{ {
MaterialRepository.Get(hash, ref _modifiedMaterial, () => new Material(modifiedMaterial) MaterialRepository.Get(hash, ref _modifiedMaterial, x => new Material(x.mat)
{ {
hideFlags = HideFlags.HideAndDontSave hideFlags = HideFlags.HideAndDontSave,
}); mainTexture = x.texture ? x.texture : x.mat.mainTexture
}, (mat: modifiedMaterial, texture));
} }
return _modifiedMaterial; return _modifiedMaterial;
@ -232,7 +246,7 @@ namespace Coffee.UIExtensions
} }
} }
_renderer = ps.GetComponent<ParticleSystemRenderer>(); ps.TryGetComponent(out _renderer);
_renderer.enabled = false; _renderer.enabled = false;
//_emitter = emitter; //_emitter = emitter;
@ -424,66 +438,49 @@ namespace Coffee.UIExtensions
Profiler.EndSample(); Profiler.EndSample();
// Update animatable material properties.
Profiler.BeginSample("[UIParticleRenderer] Update Animatable Material Properties");
UpdateMaterialProperties();
Profiler.EndSample();
// Get grouped renderers. // Get grouped renderers.
Profiler.BeginSample("[UIParticleRenderer] Set Mesh");
s_Renderers.Clear(); s_Renderers.Clear();
if (_parent.useMeshSharing) if (_parent.useMeshSharing)
{ {
UIParticleUpdater.GetGroupedRenderers(_parent.groupId, _index, s_Renderers); UIParticleUpdater.GetGroupedRenderers(_parent.groupId, _index, s_Renderers);
} }
// Set mesh to the CanvasRenderer.
Profiler.BeginSample("[UIParticleRenderer] Set Mesh");
for (var i = 0; i < s_Renderers.Count; i++) for (var i = 0; i < s_Renderers.Count; i++)
{ {
if (s_Renderers[i] == this) continue; if (s_Renderers[i] == this) continue;
s_Renderers[i].canvasRenderer.SetMesh(workerMesh); s_Renderers[i].canvasRenderer.SetMesh(workerMesh);
s_Renderers[i]._lastBounds = _lastBounds; s_Renderers[i]._lastBounds = _lastBounds;
s_Renderers[i].canvasRenderer.materialCount = 1;
s_Renderers[i].canvasRenderer.SetMaterial(materialForRendering, 0);
} }
if (!_parent.canRender) if (_parent.canRender)
{
canvasRenderer.SetMesh(workerMesh);
}
else
{ {
workerMesh.Clear(); workerMesh.Clear();
} }
canvasRenderer.SetMesh(workerMesh);
Profiler.EndSample();
// Update animatable material properties.
Profiler.BeginSample("[UIParticleRenderer] Update Animatable Material Properties");
#if UNITY_EDITOR
if (_modifiedMaterial != material)
{
_renderer.GetSharedMaterials(s_Materials);
material = s_Materials[_isTrail ? 1 : 0];
s_Materials.Clear();
SetMaterialDirty();
}
#endif
UpdateMaterialProperties();
if (_parent.useMeshSharing)
{
if (!_currentMaterialForRendering)
{
_currentMaterialForRendering = materialForRendering;
}
for (var i = 0; i < s_Renderers.Count; i++)
{
if (s_Renderers[i] == this) continue;
s_Renderers[i].canvasRenderer.materialCount = 1;
s_Renderers[i].canvasRenderer.SetMaterial(_currentMaterialForRendering, 0);
}
}
Profiler.EndSample(); Profiler.EndSample();
s_Renderers.Clear(); s_Renderers.Clear();
} }
public override void SetMaterialDirty()
{
_materialForRendering = null;
base.SetMaterialDirty();
}
/// <summary> /// <summary>
/// Call to update the geometry of the Graphic onto the CanvasRenderer. /// Call to update the geometry of the Graphic onto the CanvasRenderer.
/// </summary> /// </summary>
@ -687,12 +684,12 @@ namespace Coffee.UIExtensions
if (s_Mpb.isEmpty) return; if (s_Mpb.isEmpty) return;
// #41: Copy the value from MaterialPropertyBlock to CanvasRenderer // #41: Copy the value from MaterialPropertyBlock to CanvasRenderer
if (!_modifiedMaterial) return; if (!materialForRendering) return;
for (var i = 0; i < _parent.m_AnimatableProperties.Length; i++) for (var i = 0; i < _parent.m_AnimatableProperties.Length; i++)
{ {
var ap = _parent.m_AnimatableProperties[i]; var ap = _parent.m_AnimatableProperties[i];
ap.UpdateMaterialProperties(_modifiedMaterial, s_Mpb); ap.UpdateMaterialProperties(materialForRendering, s_Mpb);
} }
s_Mpb.Clear(); s_Mpb.Clear();