2022-06-09 01:05:30 +08:00
|
|
|
#if UNITY_2021_2_OR_NEWER
|
|
|
|
using UnityEditor.Overlays;
|
|
|
|
#else
|
|
|
|
using System.Reflection;
|
|
|
|
#endif
|
2023-08-17 08:43:02 +08:00
|
|
|
#if UNITY_2021_2_OR_NEWER
|
|
|
|
using UnityEditor.SceneManagement;
|
|
|
|
#elif UNITY_2018_3_OR_NEWER
|
|
|
|
using UnityEditor.Experimental.SceneManagement;
|
|
|
|
#endif
|
|
|
|
using System;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using System.Linq;
|
2023-08-17 08:21:12 +08:00
|
|
|
using System.Text.RegularExpressions;
|
2023-08-17 16:48:48 +08:00
|
|
|
using Coffee.UIParticleExtensions;
|
2023-08-17 08:43:02 +08:00
|
|
|
using UnityEditor;
|
|
|
|
using UnityEditor.UI;
|
|
|
|
using UnityEditorInternal;
|
|
|
|
using UnityEngine;
|
|
|
|
using UnityEngine.UI;
|
|
|
|
using Object = UnityEngine.Object;
|
2018-06-22 18:48:14 +08:00
|
|
|
|
|
|
|
namespace Coffee.UIExtensions
|
|
|
|
{
|
2020-02-12 20:38:06 +08:00
|
|
|
[CustomEditor(typeof(UIParticle))]
|
|
|
|
[CanEditMultipleObjects]
|
2020-08-20 03:42:16 +08:00
|
|
|
internal class UIParticleEditor : GraphicEditor
|
2020-02-12 20:38:06 +08:00
|
|
|
{
|
2022-06-09 01:05:30 +08:00
|
|
|
#if UNITY_2021_2_OR_NEWER
|
|
|
|
#if UNITY_2022_1_OR_NEWER
|
2023-08-17 08:43:02 +08:00
|
|
|
[Overlay(typeof(SceneView), "Scene View/UI Particles", "UI Particles", true,
|
|
|
|
defaultDockPosition = DockPosition.Bottom,
|
|
|
|
defaultDockZone = DockZone.Floating,
|
|
|
|
defaultLayout = Layout.Panel)]
|
2022-06-09 01:05:30 +08:00
|
|
|
#else
|
|
|
|
[Overlay(typeof(SceneView), "Scene View/UI Particles", "UI Particles", true)]
|
|
|
|
#endif
|
|
|
|
private class UIParticleOverlay : IMGUIOverlay, ITransientOverlay
|
|
|
|
{
|
|
|
|
public bool visible => s_SerializedObject != null;
|
|
|
|
|
|
|
|
public override void OnGUI()
|
|
|
|
{
|
|
|
|
if (visible)
|
|
|
|
{
|
|
|
|
WindowFunction(null, null);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2020-02-12 20:38:06 +08:00
|
|
|
//################################
|
|
|
|
// Constant or Static Members.
|
|
|
|
//################################
|
2020-08-31 08:28:38 +08:00
|
|
|
private static readonly GUIContent s_ContentRenderingOrder = new GUIContent("Rendering Order");
|
|
|
|
private static readonly GUIContent s_ContentRefresh = new GUIContent("Refresh");
|
2020-09-01 12:50:54 +08:00
|
|
|
private static readonly GUIContent s_ContentFix = new GUIContent("Fix");
|
2020-10-04 22:26:53 +08:00
|
|
|
private static readonly GUIContent s_ContentMaterial = new GUIContent("Material");
|
|
|
|
private static readonly GUIContent s_ContentTrailMaterial = new GUIContent("Trail Material");
|
|
|
|
private static readonly GUIContent s_Content3D = new GUIContent("3D");
|
2022-06-14 12:27:54 +08:00
|
|
|
private static readonly GUIContent s_ContentRandom = new GUIContent("Random");
|
2020-10-04 22:26:53 +08:00
|
|
|
private static readonly GUIContent s_ContentScale = new GUIContent("Scale");
|
2022-06-14 12:27:54 +08:00
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
private static readonly GUIContent s_ContentAutoScaling = new GUIContent("Auto Scaling",
|
|
|
|
"Transform.lossyScale (=world scale) is automatically set to (1, 1, 1)," +
|
|
|
|
" to prevent the root-Canvas scale from affecting the hierarchy-scaled ParticleSystem.");
|
2020-08-28 13:38:13 +08:00
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
private static SerializedObject s_SerializedObject;
|
|
|
|
private static bool s_XYZMode;
|
|
|
|
|
|
|
|
private SerializedProperty _maskable;
|
|
|
|
private SerializedProperty _scale3D;
|
|
|
|
private SerializedProperty _animatableProperties;
|
|
|
|
private SerializedProperty _meshSharing;
|
|
|
|
private SerializedProperty _groupId;
|
|
|
|
private SerializedProperty _groupMaxId;
|
|
|
|
private SerializedProperty _ignoreCanvasScaler;
|
2023-08-18 10:42:22 +08:00
|
|
|
private SerializedProperty _positionMode;
|
2020-08-28 13:38:13 +08:00
|
|
|
private ReorderableList _ro;
|
2022-06-14 12:27:54 +08:00
|
|
|
private bool _showMax;
|
2020-08-20 03:42:16 +08:00
|
|
|
|
2022-06-21 18:47:08 +08:00
|
|
|
private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>();
|
2022-06-21 18:52:22 +08:00
|
|
|
private static readonly List<ParticleSystemVertexStream> s_Streams = new List<ParticleSystemVertexStream>();
|
2023-08-17 08:43:02 +08:00
|
|
|
|
2020-08-20 03:42:16 +08:00
|
|
|
private static readonly List<string> s_MaskablePropertyNames = new List<string>
|
2020-02-12 20:38:06 +08:00
|
|
|
{
|
|
|
|
"_Stencil",
|
|
|
|
"_StencilComp",
|
|
|
|
"_StencilOp",
|
|
|
|
"_StencilWriteMask",
|
|
|
|
"_StencilReadMask",
|
2023-08-17 08:43:02 +08:00
|
|
|
"_ColorMask"
|
2020-02-12 20:38:06 +08:00
|
|
|
};
|
|
|
|
|
2022-06-09 01:05:30 +08:00
|
|
|
[InitializeOnLoadMethod]
|
2023-08-17 08:43:02 +08:00
|
|
|
private static void Init()
|
2022-06-09 01:05:30 +08:00
|
|
|
{
|
|
|
|
#if !UNITY_2021_2_OR_NEWER
|
|
|
|
var miSceneViewOverlayWindow = Type.GetType("UnityEditor.SceneViewOverlay, UnityEditor")
|
2023-08-17 08:43:02 +08:00
|
|
|
?.GetMethods(BindingFlags.Public | BindingFlags.Static)
|
2022-06-24 08:30:08 +08:00
|
|
|
.First(x => x.Name == "Window" && 5 <= x.GetParameters().Length);
|
2023-08-17 08:43:02 +08:00
|
|
|
var windowFunction = (Action<Object, SceneView>)WindowFunction;
|
2022-06-09 01:05:30 +08:00
|
|
|
var windowFunctionType = Type.GetType("UnityEditor.SceneViewOverlay+WindowFunction, UnityEditor");
|
|
|
|
var windowFunctionDelegate = Delegate.CreateDelegate(windowFunctionType, windowFunction.Method);
|
2023-08-17 08:43:02 +08:00
|
|
|
var windowTitle = new GUIContent(ObjectNames.NicifyVariableName(nameof(UIParticle)));
|
2022-06-24 08:30:08 +08:00
|
|
|
#if UNITY_2019_2_OR_NEWER
|
|
|
|
//public static void Window(GUIContent title, WindowFunction sceneViewFunc, int order, Object target, WindowDisplayOption option, EditorWindow window = null)
|
|
|
|
var sceneViewArgs = new object[] { windowTitle, windowFunctionDelegate, 599, null, 2, null };
|
|
|
|
#else
|
|
|
|
//public static void Window(GUIContent title, WindowFunction sceneViewFunc, int order, Object target, WindowDisplayOption option)
|
2022-06-09 01:05:30 +08:00
|
|
|
var sceneViewArgs = new object[] { windowTitle, windowFunctionDelegate, 599, null, 2 };
|
2022-06-24 08:30:08 +08:00
|
|
|
#endif
|
|
|
|
|
2022-06-09 01:05:30 +08:00
|
|
|
#if UNITY_2019_1_OR_NEWER
|
2023-08-17 08:43:02 +08:00
|
|
|
SceneView.duringSceneGui += _ =>
|
2022-06-09 01:05:30 +08:00
|
|
|
#else
|
|
|
|
SceneView.onSceneGUIDelegate += _ =>
|
|
|
|
#endif
|
|
|
|
{
|
|
|
|
if (s_SerializedObject != null)
|
|
|
|
{
|
|
|
|
miSceneViewOverlayWindow.Invoke(null, sceneViewArgs);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
#endif
|
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
SerializedObject CreateSerializeObject()
|
2022-06-09 01:05:30 +08:00
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
var uiParticles = Selection.gameObjects.Select(x => x.GetComponent<ParticleSystem>())
|
|
|
|
.Where(x => x)
|
2023-08-17 16:48:48 +08:00
|
|
|
.Select(x => x.GetComponentInParent<UIParticle>(true))
|
2023-08-17 08:43:02 +08:00
|
|
|
.Where(x => x && x.canvas)
|
|
|
|
.Concat(Selection.gameObjects.Select(x => x.GetComponent<UIParticle>())
|
|
|
|
.Where(x => x && x.canvas))
|
|
|
|
.Distinct()
|
|
|
|
.ToArray();
|
2022-07-01 14:36:37 +08:00
|
|
|
return 0 < uiParticles.Length ? new SerializedObject(uiParticles) : null;
|
2023-08-17 08:43:02 +08:00
|
|
|
}
|
2022-06-09 01:05:30 +08:00
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
s_SerializedObject = CreateSerializeObject();
|
|
|
|
Selection.selectionChanged += () => s_SerializedObject = CreateSerializeObject();
|
2022-06-09 01:05:30 +08:00
|
|
|
}
|
|
|
|
|
2020-02-12 20:38:06 +08:00
|
|
|
//################################
|
|
|
|
// Public/Protected Members.
|
|
|
|
//################################
|
|
|
|
/// <summary>
|
|
|
|
/// This function is called when the object becomes enabled and active.
|
|
|
|
/// </summary>
|
|
|
|
protected override void OnEnable()
|
|
|
|
{
|
|
|
|
base.OnEnable();
|
2022-06-08 11:54:11 +08:00
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
_maskable = serializedObject.FindProperty("m_Maskable");
|
|
|
|
_scale3D = serializedObject.FindProperty("m_Scale3D");
|
|
|
|
_animatableProperties = serializedObject.FindProperty("m_AnimatableProperties");
|
|
|
|
_meshSharing = serializedObject.FindProperty("m_MeshSharing");
|
|
|
|
_groupId = serializedObject.FindProperty("m_GroupId");
|
|
|
|
_groupMaxId = serializedObject.FindProperty("m_GroupMaxId");
|
|
|
|
_ignoreCanvasScaler = serializedObject.FindProperty("m_IgnoreCanvasScaler");
|
2023-08-18 10:42:22 +08:00
|
|
|
_positionMode = serializedObject.FindProperty("m_PositionMode");
|
2020-08-28 13:38:13 +08:00
|
|
|
|
|
|
|
var sp = serializedObject.FindProperty("m_Particles");
|
2023-08-17 08:43:02 +08:00
|
|
|
_ro = new ReorderableList(sp.serializedObject, sp, true, true, true, true)
|
2020-08-28 13:38:13 +08:00
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
elementHeight = EditorGUIUtility.singleLineHeight * 3 + 4,
|
|
|
|
elementHeightCallback = _ => 3 * (EditorGUIUtility.singleLineHeight + 2),
|
|
|
|
drawElementCallback = (rect, index, _, __) =>
|
|
|
|
{
|
|
|
|
EditorGUI.BeginDisabledGroup(sp.hasMultipleDifferentValues);
|
|
|
|
rect.y += 1;
|
|
|
|
rect.height = EditorGUIUtility.singleLineHeight;
|
|
|
|
var p = sp.GetArrayElementAtIndex(index);
|
|
|
|
EditorGUI.ObjectField(rect, p, GUIContent.none);
|
|
|
|
rect.x += 15;
|
|
|
|
rect.width -= 15;
|
|
|
|
var ps = p.objectReferenceValue as ParticleSystem;
|
|
|
|
var materials = ps
|
|
|
|
? new SerializedObject(ps.GetComponent<ParticleSystemRenderer>()).FindProperty("m_Materials")
|
|
|
|
: null;
|
|
|
|
rect.y += rect.height + 1;
|
|
|
|
MaterialField(rect, s_ContentMaterial, materials, 0);
|
|
|
|
rect.y += rect.height + 1;
|
|
|
|
MaterialField(rect, s_ContentTrailMaterial, materials, 1);
|
|
|
|
EditorGUI.EndDisabledGroup();
|
|
|
|
if (materials != null && materials.serializedObject.hasModifiedProperties)
|
|
|
|
{
|
|
|
|
materials.serializedObject.ApplyModifiedProperties();
|
|
|
|
}
|
|
|
|
},
|
|
|
|
drawHeaderCallback = rect =>
|
2020-10-04 22:26:53 +08:00
|
|
|
{
|
2020-11-20 14:10:30 +08:00
|
|
|
#if !UNITY_2019_3_OR_NEWER
|
2023-08-17 08:43:02 +08:00
|
|
|
rect.y -= 1;
|
2020-11-20 14:10:30 +08:00
|
|
|
#endif
|
2023-08-17 08:43:02 +08:00
|
|
|
var pos = new Rect(rect.x, rect.y, 150, rect.height);
|
|
|
|
EditorGUI.LabelField(pos, s_ContentRenderingOrder);
|
2020-08-28 13:38:13 +08:00
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
pos = new Rect(rect.width - 35, rect.y, 60, rect.height);
|
|
|
|
if (GUI.Button(pos, s_ContentRefresh, EditorStyles.miniButton))
|
2020-08-31 08:28:38 +08:00
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
foreach (var uip in targets.OfType<UIParticle>())
|
|
|
|
{
|
|
|
|
uip.RefreshParticles();
|
|
|
|
EditorUtility.SetDirty(uip);
|
|
|
|
}
|
2020-08-31 08:28:38 +08:00
|
|
|
}
|
2020-08-28 13:38:13 +08:00
|
|
|
}
|
|
|
|
};
|
2022-06-21 18:47:08 +08:00
|
|
|
|
|
|
|
// On select UIParticle, refresh particles.
|
2023-08-17 08:43:02 +08:00
|
|
|
if (!Application.isPlaying)
|
2022-06-21 18:47:08 +08:00
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
foreach (var uip in targets.OfType<UIParticle>())
|
|
|
|
{
|
|
|
|
if (PrefabUtility.GetPrefabAssetType(uip) != PrefabAssetType.NotAPrefab) continue;
|
|
|
|
uip.RefreshParticles(uip.particles);
|
|
|
|
}
|
2022-06-21 18:47:08 +08:00
|
|
|
}
|
2020-02-12 20:38:06 +08:00
|
|
|
}
|
|
|
|
|
2020-10-04 22:26:53 +08:00
|
|
|
private static void MaterialField(Rect rect, GUIContent label, SerializedProperty sp, int index)
|
|
|
|
{
|
|
|
|
if (sp == null || sp.arraySize <= index)
|
|
|
|
{
|
|
|
|
EditorGUI.BeginDisabledGroup(true);
|
|
|
|
EditorGUI.ObjectField(rect, label, null, typeof(Material), true);
|
|
|
|
EditorGUI.EndDisabledGroup();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
EditorGUI.PropertyField(rect, sp.GetArrayElementAtIndex(index), label);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-12 20:38:06 +08:00
|
|
|
/// <summary>
|
|
|
|
/// Implement this function to make a custom inspector.
|
|
|
|
/// </summary>
|
|
|
|
public override void OnInspectorGUI()
|
|
|
|
{
|
2020-08-20 03:42:16 +08:00
|
|
|
var current = target as UIParticle;
|
2022-07-01 14:36:37 +08:00
|
|
|
if (!current) return;
|
2020-08-20 03:42:16 +08:00
|
|
|
|
2020-02-12 20:38:06 +08:00
|
|
|
serializedObject.Update();
|
|
|
|
|
2020-10-28 21:19:15 +08:00
|
|
|
// Maskable
|
2023-08-17 08:43:02 +08:00
|
|
|
EditorGUILayout.PropertyField(_maskable);
|
2020-02-12 20:38:06 +08:00
|
|
|
|
2020-08-28 13:38:13 +08:00
|
|
|
// Scale
|
2023-08-17 08:43:02 +08:00
|
|
|
EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4);
|
|
|
|
s_XYZMode = DrawFloatOrVector3Field(_scale3D, s_XYZMode);
|
2022-06-11 22:10:17 +08:00
|
|
|
EditorGUI.EndDisabledGroup();
|
2020-08-28 13:38:13 +08:00
|
|
|
|
2020-02-12 20:38:06 +08:00
|
|
|
// AnimatableProperties
|
2020-09-02 01:39:05 +08:00
|
|
|
var mats = current.particles
|
|
|
|
.Where(x => x)
|
|
|
|
.Select(x => x.GetComponent<ParticleSystemRenderer>().sharedMaterial)
|
|
|
|
.Where(x => x)
|
|
|
|
.ToArray();
|
2020-10-04 22:26:53 +08:00
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
AnimatablePropertyEditor.Draw(_animatableProperties, mats);
|
2020-02-12 20:38:06 +08:00
|
|
|
|
2022-06-11 22:10:17 +08:00
|
|
|
// Mesh sharing
|
2022-06-14 12:27:54 +08:00
|
|
|
EditorGUI.BeginChangeCheck();
|
2023-08-17 08:43:02 +08:00
|
|
|
_showMax = DrawMeshSharing(_meshSharing, _groupId, _groupMaxId, _showMax);
|
2022-06-14 12:27:54 +08:00
|
|
|
if (EditorGUI.EndChangeCheck())
|
|
|
|
{
|
|
|
|
serializedObject.ApplyModifiedProperties();
|
|
|
|
foreach (var uip in targets.OfType<UIParticle>())
|
|
|
|
{
|
|
|
|
uip.ResetGroupId();
|
|
|
|
}
|
|
|
|
}
|
2022-06-11 22:10:17 +08:00
|
|
|
|
2023-08-18 10:42:22 +08:00
|
|
|
// Position Mode
|
|
|
|
EditorGUILayout.PropertyField(_positionMode);
|
2022-06-25 01:04:23 +08:00
|
|
|
|
2023-08-15 20:56:09 +08:00
|
|
|
// Auto Scaling
|
2023-08-17 08:43:02 +08:00
|
|
|
DrawInversedToggle(_ignoreCanvasScaler, s_ContentAutoScaling, () =>
|
2023-08-15 20:56:09 +08:00
|
|
|
{
|
|
|
|
foreach (var uip in targets.OfType<UIParticle>())
|
|
|
|
{
|
|
|
|
if (uip && !uip.autoScaling)
|
|
|
|
{
|
|
|
|
uip.transform.localScale = Vector3.one;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-10-04 22:26:53 +08:00
|
|
|
// Target ParticleSystems.
|
2022-07-01 14:38:11 +08:00
|
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
EditorGUI.BeginDisabledGroup(targets.OfType<UIParticle>().Any(x => !x.canvas));
|
2020-08-28 13:38:13 +08:00
|
|
|
_ro.DoLayoutList();
|
2022-07-01 14:38:11 +08:00
|
|
|
EditorGUI.EndDisabledGroup();
|
2020-09-01 12:50:54 +08:00
|
|
|
serializedObject.ApplyModifiedProperties();
|
2022-07-01 14:38:11 +08:00
|
|
|
if (EditorGUI.EndChangeCheck())
|
|
|
|
{
|
|
|
|
foreach (var uip in targets.OfType<UIParticle>())
|
|
|
|
{
|
|
|
|
uip.RefreshParticles(uip.particles);
|
|
|
|
}
|
|
|
|
}
|
2020-09-01 12:50:54 +08:00
|
|
|
|
2023-08-17 08:21:12 +08:00
|
|
|
// Non-UI built-in shader is not supported.
|
|
|
|
foreach (var mat in current.materials)
|
|
|
|
{
|
|
|
|
if (!mat || !mat.shader) continue;
|
|
|
|
var shader = mat.shader;
|
|
|
|
if (IsBuiltInObject(shader) && !shader.name.StartsWith("UI/"))
|
|
|
|
{
|
|
|
|
EditorGUILayout.HelpBox(
|
|
|
|
$"Built-in shader '{shader.name}' in '{mat.name}' is not supported.\n" +
|
|
|
|
"Use UI shaders instead.",
|
|
|
|
MessageType.Error);
|
|
|
|
}
|
|
|
|
}
|
2023-08-17 08:43:02 +08:00
|
|
|
|
2023-08-17 08:21:12 +08:00
|
|
|
// Does the shader support UI masks?
|
2023-08-17 16:48:48 +08:00
|
|
|
if (current.maskable && current.GetComponentInParent<Mask>(false))
|
2020-02-12 20:38:06 +08:00
|
|
|
{
|
2020-08-28 13:38:13 +08:00
|
|
|
foreach (var mat in current.materials)
|
2020-02-12 20:38:06 +08:00
|
|
|
{
|
2020-08-31 08:28:38 +08:00
|
|
|
if (!mat || !mat.shader) continue;
|
2020-08-28 13:38:13 +08:00
|
|
|
var shader = mat.shader;
|
2022-06-21 18:47:08 +08:00
|
|
|
if (s_Shaders.Contains(shader)) continue;
|
|
|
|
s_Shaders.Add(shader);
|
2020-08-28 13:38:13 +08:00
|
|
|
foreach (var propName in s_MaskablePropertyNames)
|
|
|
|
{
|
|
|
|
if (mat.HasProperty(propName)) continue;
|
2020-08-20 03:42:16 +08:00
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
EditorGUILayout.HelpBox(
|
2023-08-17 08:21:12 +08:00
|
|
|
$"Shader '{shader.name}' doesn't have '{propName}' property." +
|
|
|
|
"\nThis graphic cannot be masked.",
|
2023-08-17 08:43:02 +08:00
|
|
|
MessageType.Warning);
|
2020-08-28 13:38:13 +08:00
|
|
|
break;
|
|
|
|
}
|
2020-02-12 20:38:06 +08:00
|
|
|
}
|
2020-08-12 01:10:22 +08:00
|
|
|
}
|
2023-08-17 08:43:02 +08:00
|
|
|
|
2022-06-21 18:47:08 +08:00
|
|
|
s_Shaders.Clear();
|
2020-02-12 20:38:06 +08:00
|
|
|
|
2022-06-08 11:54:11 +08:00
|
|
|
// UIParticle for trail should be removed.
|
2023-08-17 08:43:02 +08:00
|
|
|
var label = "This UIParticle component should be removed. The UIParticle for trails is no longer needed.";
|
|
|
|
if (FixButton(current.m_IsTrail, label))
|
2020-09-01 12:50:54 +08:00
|
|
|
{
|
|
|
|
DestroyUIParticle(current);
|
|
|
|
}
|
2022-06-10 15:12:15 +08:00
|
|
|
|
|
|
|
// #203: When using linear color space, the particle colors are not output correctly.
|
|
|
|
// To fix, set 'Apply Active Color Space' in renderer module to false.
|
|
|
|
var allPsRenderers = targets.OfType<UIParticle>()
|
|
|
|
.SelectMany(x => x.particles)
|
|
|
|
.Where(x => x)
|
|
|
|
.Select(x => x.GetComponent<ParticleSystemRenderer>())
|
|
|
|
.ToArray();
|
|
|
|
if (0 < allPsRenderers.Length)
|
|
|
|
{
|
|
|
|
var so = new SerializedObject(allPsRenderers);
|
2022-06-21 18:47:08 +08:00
|
|
|
var sp = so.FindProperty("m_ApplyActiveColorSpace");
|
2023-08-17 08:43:02 +08:00
|
|
|
label = "When using linear color space, the particle colors are not output correctly.\n" +
|
|
|
|
"To fix, set 'Apply Active Color Space' in renderer module to false.";
|
|
|
|
if (FixButton(sp.boolValue || sp.hasMultipleDifferentValues, label))
|
2022-06-10 15:12:15 +08:00
|
|
|
{
|
|
|
|
sp.boolValue = false;
|
|
|
|
so.ApplyModifiedProperties();
|
|
|
|
}
|
2022-06-21 18:52:22 +08:00
|
|
|
|
|
|
|
// Check to use 'TEXCOORD*.zw' components as custom vertex stream.
|
|
|
|
foreach (var psr in allPsRenderers)
|
|
|
|
{
|
2022-07-01 14:36:37 +08:00
|
|
|
if (!new SerializedObject(psr).FindProperty("m_UseCustomVertexStreams").boolValue) continue;
|
2022-06-21 18:52:22 +08:00
|
|
|
if (psr.activeVertexStreamsCount == 0) continue;
|
|
|
|
psr.GetActiveVertexStreams(s_Streams);
|
|
|
|
|
|
|
|
if (2 < s_Streams.Select(GetUsedComponentCount).Sum())
|
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
EditorGUILayout.HelpBox(
|
|
|
|
$"ParticleSystem '{psr.name}' uses 'TEXCOORD*.zw' components as custom vertex stream.\n" +
|
|
|
|
"UIParticle does not support it (See README.md).",
|
|
|
|
MessageType.Warning);
|
2022-06-21 18:52:22 +08:00
|
|
|
}
|
2023-08-17 08:43:02 +08:00
|
|
|
|
|
|
|
s_Streams.Clear();
|
2022-06-21 18:52:22 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-08-17 08:21:12 +08:00
|
|
|
private bool IsBuiltInObject(Object obj)
|
|
|
|
{
|
|
|
|
return AssetDatabase.TryGetGUIDAndLocalFileIdentifier(obj, out var guid, out long _)
|
|
|
|
&& Regex.IsMatch(guid, "^0{16}.0{15}$", RegexOptions.Compiled);
|
|
|
|
}
|
|
|
|
|
2022-06-21 18:52:22 +08:00
|
|
|
private static int GetUsedComponentCount(ParticleSystemVertexStream s)
|
|
|
|
{
|
|
|
|
switch (s)
|
|
|
|
{
|
|
|
|
case ParticleSystemVertexStream.Position:
|
|
|
|
case ParticleSystemVertexStream.Normal:
|
|
|
|
case ParticleSystemVertexStream.Tangent:
|
|
|
|
case ParticleSystemVertexStream.Color:
|
|
|
|
return 0;
|
|
|
|
case ParticleSystemVertexStream.UV:
|
|
|
|
case ParticleSystemVertexStream.UV2:
|
|
|
|
case ParticleSystemVertexStream.UV3:
|
|
|
|
case ParticleSystemVertexStream.UV4:
|
|
|
|
case ParticleSystemVertexStream.SizeXY:
|
|
|
|
case ParticleSystemVertexStream.StableRandomXY:
|
|
|
|
case ParticleSystemVertexStream.VaryingRandomXY:
|
|
|
|
case ParticleSystemVertexStream.Custom1XY:
|
|
|
|
case ParticleSystemVertexStream.Custom2XY:
|
|
|
|
case ParticleSystemVertexStream.NoiseSumXY:
|
|
|
|
case ParticleSystemVertexStream.NoiseImpulseXY:
|
|
|
|
return 2;
|
|
|
|
case ParticleSystemVertexStream.AnimBlend:
|
|
|
|
case ParticleSystemVertexStream.AnimFrame:
|
|
|
|
case ParticleSystemVertexStream.VertexID:
|
|
|
|
case ParticleSystemVertexStream.SizeX:
|
|
|
|
case ParticleSystemVertexStream.Rotation:
|
|
|
|
case ParticleSystemVertexStream.RotationSpeed:
|
|
|
|
case ParticleSystemVertexStream.Velocity:
|
|
|
|
case ParticleSystemVertexStream.Speed:
|
|
|
|
case ParticleSystemVertexStream.AgePercent:
|
|
|
|
case ParticleSystemVertexStream.InvStartLifetime:
|
|
|
|
case ParticleSystemVertexStream.StableRandomX:
|
|
|
|
case ParticleSystemVertexStream.VaryingRandomX:
|
|
|
|
case ParticleSystemVertexStream.Custom1X:
|
|
|
|
case ParticleSystemVertexStream.Custom2X:
|
|
|
|
case ParticleSystemVertexStream.NoiseSumX:
|
|
|
|
case ParticleSystemVertexStream.NoiseImpulseX:
|
|
|
|
return 1;
|
|
|
|
case ParticleSystemVertexStream.Center:
|
|
|
|
case ParticleSystemVertexStream.SizeXYZ:
|
|
|
|
case ParticleSystemVertexStream.Rotation3D:
|
|
|
|
case ParticleSystemVertexStream.RotationSpeed3D:
|
|
|
|
case ParticleSystemVertexStream.StableRandomXYZ:
|
|
|
|
case ParticleSystemVertexStream.VaryingRandomXYZ:
|
|
|
|
case ParticleSystemVertexStream.Custom1XYZ:
|
|
|
|
case ParticleSystemVertexStream.Custom2XYZ:
|
|
|
|
case ParticleSystemVertexStream.NoiseSumXYZ:
|
|
|
|
case ParticleSystemVertexStream.NoiseImpulseXYZ:
|
|
|
|
return 3;
|
|
|
|
case ParticleSystemVertexStream.StableRandomXYZW:
|
|
|
|
case ParticleSystemVertexStream.VaryingRandomXYZW:
|
|
|
|
case ParticleSystemVertexStream.Custom1XYZW:
|
|
|
|
case ParticleSystemVertexStream.Custom2XYZW:
|
|
|
|
return 4;
|
2022-06-10 15:12:15 +08:00
|
|
|
}
|
2023-08-17 08:43:02 +08:00
|
|
|
|
2022-06-21 18:52:22 +08:00
|
|
|
return 3;
|
2020-09-01 12:50:54 +08:00
|
|
|
}
|
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
private static bool DrawMeshSharing(SerializedProperty spMeshSharing, SerializedProperty spGroupId,
|
|
|
|
SerializedProperty spGroupMaxId, bool showMax)
|
2022-06-11 22:10:17 +08:00
|
|
|
{
|
2022-06-14 12:27:54 +08:00
|
|
|
showMax |= spGroupId.intValue != spGroupMaxId.intValue ||
|
|
|
|
spGroupId.hasMultipleDifferentValues ||
|
|
|
|
spGroupMaxId.hasMultipleDifferentValues;
|
|
|
|
|
|
|
|
EditorGUILayout.BeginHorizontal();
|
|
|
|
EditorGUILayout.PropertyField(spMeshSharing);
|
|
|
|
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
showMax = GUILayout.Toggle(showMax, s_ContentRandom, EditorStyles.miniButton, GUILayout.Width(60));
|
|
|
|
if (EditorGUI.EndChangeCheck() && !showMax)
|
2023-08-17 08:43:02 +08:00
|
|
|
{
|
2022-06-14 12:27:54 +08:00
|
|
|
spGroupMaxId.intValue = spGroupId.intValue;
|
2023-08-17 08:43:02 +08:00
|
|
|
}
|
|
|
|
|
2022-06-14 12:27:54 +08:00
|
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
|
|
|
|
EditorGUI.BeginDisabledGroup(spMeshSharing.intValue == 0);
|
2022-06-11 22:10:17 +08:00
|
|
|
EditorGUI.indentLevel++;
|
2022-06-14 12:27:54 +08:00
|
|
|
EditorGUILayout.PropertyField(spGroupId);
|
|
|
|
if (showMax)
|
|
|
|
{
|
|
|
|
EditorGUILayout.PropertyField(spGroupMaxId);
|
|
|
|
}
|
|
|
|
else if (spMeshSharing.intValue == 1 || spMeshSharing.intValue == 4)
|
2022-06-11 22:10:17 +08:00
|
|
|
{
|
|
|
|
EditorGUI.BeginDisabledGroup(true);
|
2023-08-17 08:43:02 +08:00
|
|
|
var obj = UIParticleUpdater.GetPrimary(spGroupId.intValue);
|
|
|
|
EditorGUILayout.ObjectField("Primary", obj, typeof(UIParticle), false);
|
2022-06-11 22:10:17 +08:00
|
|
|
EditorGUI.EndDisabledGroup();
|
|
|
|
}
|
2023-08-17 08:43:02 +08:00
|
|
|
|
2022-06-11 22:10:17 +08:00
|
|
|
EditorGUI.indentLevel--;
|
|
|
|
EditorGUI.EndDisabledGroup();
|
2022-06-14 12:27:54 +08:00
|
|
|
|
|
|
|
return showMax;
|
2022-06-11 22:10:17 +08:00
|
|
|
}
|
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
private static void DrawInversedToggle(SerializedProperty sp, GUIContent label, Action onChanged)
|
2023-08-15 20:56:09 +08:00
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
EditorGUI.showMixedValue = sp.hasMultipleDifferentValues;
|
|
|
|
var autoScaling = !sp.boolValue;
|
2023-08-15 20:56:09 +08:00
|
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
if (autoScaling != EditorGUILayout.Toggle(label, autoScaling))
|
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
sp.boolValue = autoScaling;
|
2023-08-15 20:56:09 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (EditorGUI.EndChangeCheck())
|
|
|
|
{
|
|
|
|
EditorApplication.delayCall += onChanged.Invoke;
|
|
|
|
}
|
|
|
|
|
|
|
|
EditorGUI.showMixedValue = false;
|
|
|
|
}
|
|
|
|
|
2023-08-17 08:43:02 +08:00
|
|
|
private static void WindowFunction(Object target, SceneView sceneView)
|
2022-06-09 01:05:30 +08:00
|
|
|
{
|
|
|
|
try
|
|
|
|
{
|
2023-08-15 10:12:45 +08:00
|
|
|
if (s_SerializedObject == null || !s_SerializedObject.targetObject) return;
|
2022-07-01 14:36:37 +08:00
|
|
|
if (s_SerializedObject.targetObjects.OfType<UIParticle>().Any(x => !x || !x.canvas)) return;
|
2022-06-09 01:05:30 +08:00
|
|
|
|
|
|
|
s_SerializedObject.Update();
|
2022-06-27 23:18:59 +08:00
|
|
|
using (new EditorGUILayout.VerticalScope(GUILayout.Width(220f)))
|
|
|
|
{
|
|
|
|
var labelWidth = EditorGUIUtility.labelWidth;
|
|
|
|
EditorGUIUtility.labelWidth = 100;
|
2022-07-01 14:37:18 +08:00
|
|
|
EditorGUILayout.PropertyField(s_SerializedObject.FindProperty("m_Enabled"));
|
2023-08-17 08:43:02 +08:00
|
|
|
s_XYZMode = DrawFloatOrVector3Field(s_SerializedObject.FindProperty("m_Scale3D"), s_XYZMode);
|
|
|
|
DrawInversedToggle(s_SerializedObject.FindProperty("m_IgnoreCanvasScaler"),
|
|
|
|
s_ContentAutoScaling,
|
2023-08-15 20:56:09 +08:00
|
|
|
() =>
|
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
s_SerializedObject.targetObjects
|
|
|
|
.OfType<UIParticle>()
|
|
|
|
.Where(x => x && !x.autoScaling)
|
|
|
|
.ToList()
|
|
|
|
.ForEach(x => x.transform.localScale = Vector3.one);
|
2023-08-15 20:56:09 +08:00
|
|
|
});
|
2023-08-18 10:42:22 +08:00
|
|
|
EditorGUILayout.PropertyField(s_SerializedObject.FindProperty("m_PositionMode"));
|
2022-06-27 23:18:59 +08:00
|
|
|
EditorGUIUtility.labelWidth = labelWidth;
|
|
|
|
}
|
2023-08-17 08:43:02 +08:00
|
|
|
|
2022-06-09 01:05:30 +08:00
|
|
|
s_SerializedObject.ApplyModifiedProperties();
|
|
|
|
}
|
|
|
|
catch
|
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
// ignored
|
2022-06-09 01:05:30 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-06-08 11:54:11 +08:00
|
|
|
private void DestroyUIParticle(UIParticle p, bool ignoreCurrent = false)
|
2020-09-01 12:50:54 +08:00
|
|
|
{
|
2023-08-17 08:43:02 +08:00
|
|
|
if (!p || (ignoreCurrent && target == p)) return;
|
2020-09-01 12:50:54 +08:00
|
|
|
|
|
|
|
var cr = p.canvasRenderer;
|
|
|
|
DestroyImmediate(p);
|
|
|
|
DestroyImmediate(cr);
|
2020-09-01 13:27:06 +08:00
|
|
|
|
2022-02-16 00:47:45 +08:00
|
|
|
#if UNITY_2018_3_OR_NEWER
|
2023-08-17 08:43:02 +08:00
|
|
|
var stage = PrefabStageUtility.GetCurrentPrefabStage();
|
2020-09-01 13:27:06 +08:00
|
|
|
if (stage != null && stage.scene.isLoaded)
|
|
|
|
{
|
2021-08-02 13:45:22 +08:00
|
|
|
#if UNITY_2020_1_OR_NEWER
|
2021-08-02 14:09:21 +08:00
|
|
|
string prefabAssetPath = stage.assetPath;
|
2021-08-02 13:45:22 +08:00
|
|
|
#else
|
2023-08-17 08:43:02 +08:00
|
|
|
var prefabAssetPath = stage.prefabAssetPath;
|
2021-08-02 13:45:22 +08:00
|
|
|
#endif
|
2021-08-02 14:09:21 +08:00
|
|
|
PrefabUtility.SaveAsPrefabAsset(stage.prefabContentsRoot, prefabAssetPath);
|
2020-09-01 13:27:06 +08:00
|
|
|
}
|
2020-09-01 15:03:06 +08:00
|
|
|
#endif
|
2020-09-01 12:50:54 +08:00
|
|
|
}
|
|
|
|
|
2022-06-08 11:54:11 +08:00
|
|
|
private static bool FixButton(bool show, string text)
|
2020-09-01 12:50:54 +08:00
|
|
|
{
|
|
|
|
if (!show) return false;
|
|
|
|
using (new EditorGUILayout.HorizontalScope(GUILayout.ExpandWidth(true)))
|
|
|
|
{
|
|
|
|
EditorGUILayout.HelpBox(text, MessageType.Warning, true);
|
|
|
|
using (new EditorGUILayout.VerticalScope())
|
|
|
|
{
|
|
|
|
return GUILayout.Button(s_ContentFix, GUILayout.Width(30));
|
|
|
|
}
|
|
|
|
}
|
2020-02-12 20:38:06 +08:00
|
|
|
}
|
2020-10-04 22:26:53 +08:00
|
|
|
|
|
|
|
private static bool DrawFloatOrVector3Field(SerializedProperty sp, bool showXyz)
|
|
|
|
{
|
|
|
|
var x = sp.FindPropertyRelative("x");
|
|
|
|
var y = sp.FindPropertyRelative("y");
|
|
|
|
var z = sp.FindPropertyRelative("z");
|
|
|
|
|
|
|
|
showXyz |= !Mathf.Approximately(x.floatValue, y.floatValue) ||
|
|
|
|
!Mathf.Approximately(y.floatValue, z.floatValue) ||
|
|
|
|
y.hasMultipleDifferentValues ||
|
|
|
|
z.hasMultipleDifferentValues;
|
|
|
|
|
|
|
|
EditorGUILayout.BeginHorizontal();
|
|
|
|
if (showXyz)
|
|
|
|
{
|
|
|
|
EditorGUILayout.PropertyField(sp);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
EditorGUILayout.PropertyField(x, s_ContentScale);
|
|
|
|
if (EditorGUI.EndChangeCheck())
|
2021-02-19 08:57:02 +08:00
|
|
|
{
|
2022-06-08 11:54:11 +08:00
|
|
|
y.floatValue = z.floatValue = x.floatValue;
|
2021-02-19 08:57:02 +08:00
|
|
|
}
|
2020-10-04 22:26:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
|
|
showXyz = GUILayout.Toggle(showXyz, s_Content3D, EditorStyles.miniButton, GUILayout.Width(30));
|
|
|
|
if (EditorGUI.EndChangeCheck() && !showXyz)
|
2023-08-17 08:43:02 +08:00
|
|
|
{
|
2020-10-04 22:26:53 +08:00
|
|
|
z.floatValue = y.floatValue = x.floatValue;
|
2023-08-17 08:43:02 +08:00
|
|
|
}
|
|
|
|
|
2020-10-04 22:26:53 +08:00
|
|
|
EditorGUILayout.EndHorizontal();
|
|
|
|
|
|
|
|
return showXyz;
|
|
|
|
}
|
2020-02-12 20:38:06 +08:00
|
|
|
}
|
|
|
|
}
|