You've already forked ParticleEffectForUGUI
mirror of
https://github.com/mob-sakai/ParticleEffectForUGUI.git
synced 2026-06-29 11:03:44 +00:00
Compare commits
7 Commits
5.0.0-prev
...
e32120b18c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e32120b18c | ||
|
|
58070b3495 | ||
|
|
a84c7db4ef | ||
|
|
1c8aa684c4 | ||
|
|
c019156200 | ||
|
|
827c9a738f | ||
|
|
19b076b319 |
@@ -3,7 +3,7 @@
|
|||||||
"com.coffee.development": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/Development",
|
"com.coffee.development": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/Development",
|
||||||
"com.coffee.minimal-resource": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/MinimalResource",
|
"com.coffee.minimal-resource": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/MinimalResource",
|
||||||
"com.coffee.nano-monitor": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/NanoMonitor",
|
"com.coffee.nano-monitor": "https://github.com/mob-sakai/Coffee.Internal.git?path=Packages/NanoMonitor",
|
||||||
"com.unity.ide.rider": "3.0.31",
|
"com.unity.ide.rider": "3.0.36",
|
||||||
"com.unity.test-framework": "1.1.33",
|
"com.unity.test-framework": "1.1.33",
|
||||||
"com.unity.modules.animation": "1.0.0",
|
"com.unity.modules.animation": "1.0.0",
|
||||||
"com.unity.modules.physics": "1.0.0"
|
"com.unity.modules.physics": "1.0.0"
|
||||||
|
|||||||
@@ -40,7 +40,7 @@
|
|||||||
"url": "https://packages.unity.com"
|
"url": "https://packages.unity.com"
|
||||||
},
|
},
|
||||||
"com.unity.ide.rider": {
|
"com.unity.ide.rider": {
|
||||||
"version": "3.0.31",
|
"version": "3.0.36",
|
||||||
"depth": 0,
|
"depth": 0,
|
||||||
"source": "registry",
|
"source": "registry",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
@@ -8,12 +9,11 @@ using UnityEngine;
|
|||||||
using UnityEngine.Profiling;
|
using UnityEngine.Profiling;
|
||||||
using UnityEngine.UI;
|
using UnityEngine.UI;
|
||||||
using Coffee.UIParticleInternal;
|
using Coffee.UIParticleInternal;
|
||||||
|
using Object = UnityEngine.Object;
|
||||||
#if UNITY_2021_2_OR_NEWER
|
#if UNITY_2021_2_OR_NEWER
|
||||||
using UnityEditor.Overlays;
|
using UnityEditor.Overlays;
|
||||||
#else
|
#else
|
||||||
using System;
|
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Object = UnityEngine.Object;
|
|
||||||
#endif
|
#endif
|
||||||
#if UNITY_2021_2_OR_NEWER
|
#if UNITY_2021_2_OR_NEWER
|
||||||
using UnityEditor.SceneManagement;
|
using UnityEditor.SceneManagement;
|
||||||
@@ -66,6 +66,7 @@ namespace Coffee.UIExtensions
|
|||||||
private ReorderableList _ro;
|
private ReorderableList _ro;
|
||||||
private bool _showMax;
|
private bool _showMax;
|
||||||
private bool _is3DScaleMode;
|
private bool _is3DScaleMode;
|
||||||
|
private GameObject[] _gameObjects;
|
||||||
|
|
||||||
private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>();
|
private static readonly HashSet<Shader> s_Shaders = new HashSet<Shader>();
|
||||||
#if UNITY_2018 || UNITY_2019
|
#if UNITY_2018 || UNITY_2019
|
||||||
@@ -183,6 +184,13 @@ namespace Coffee.UIExtensions
|
|||||||
y.hasMultipleDifferentValues ||
|
y.hasMultipleDifferentValues ||
|
||||||
z.hasMultipleDifferentValues;
|
z.hasMultipleDifferentValues;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add temporary ParticleSystem for preview if enabled.
|
||||||
|
if (UIParticleProjectSettings.s_PreviewOnSelectOnSelect)
|
||||||
|
{
|
||||||
|
_gameObjects = targets.OfType<UIParticle>().Select(x => x.gameObject).ToArray();
|
||||||
|
ParticleSystemPreviewSystem.Register(_gameObjects);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -197,7 +205,10 @@ namespace Coffee.UIExtensions
|
|||||||
serializedObject.Update();
|
serializedObject.Update();
|
||||||
|
|
||||||
// Maskable
|
// Maskable
|
||||||
|
if (_maskable != null)
|
||||||
|
{
|
||||||
EditorGUILayout.PropertyField(_maskable);
|
EditorGUILayout.PropertyField(_maskable);
|
||||||
|
}
|
||||||
|
|
||||||
// Scale
|
// Scale
|
||||||
EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4);
|
EditorGUI.BeginDisabledGroup(!_meshSharing.hasMultipleDifferentValues && _meshSharing.intValue == 4);
|
||||||
@@ -344,6 +355,10 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// Remove the temporary ParticleSystem.
|
||||||
|
ParticleSystemPreviewSystem.DrawWarningForTemporary(_gameObjects);
|
||||||
|
|
||||||
Profiler.EndSample();
|
Profiler.EndSample();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,7 +497,7 @@ namespace Coffee.UIExtensions
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private static bool FixButton(bool show, string text)
|
private static bool FixButton(bool show, string text, GUIContent buttonText = null)
|
||||||
{
|
{
|
||||||
if (!show) return false;
|
if (!show) return false;
|
||||||
using (new EditorGUILayout.HorizontalScope(GUILayout.ExpandWidth(true)))
|
using (new EditorGUILayout.HorizontalScope(GUILayout.ExpandWidth(true)))
|
||||||
@@ -490,7 +505,7 @@ namespace Coffee.UIExtensions
|
|||||||
EditorGUILayout.HelpBox(text, MessageType.Warning, true);
|
EditorGUILayout.HelpBox(text, MessageType.Warning, true);
|
||||||
using (new EditorGUILayout.VerticalScope())
|
using (new EditorGUILayout.VerticalScope())
|
||||||
{
|
{
|
||||||
return GUILayout.Button(s_ContentFix, GUILayout.Width(30));
|
return GUILayout.Button(buttonText ?? s_ContentFix, GUILayout.ExpandWidth(false));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,9 +183,14 @@ _This package requires **Unity 2018.3 or later**._
|
|||||||
- **Time Scale Multiplier:** Time scale multiplier.
|
- **Time Scale Multiplier:** Time scale multiplier.
|
||||||
- **Rendering Order**: The ParticleSystem list to be rendered. You can change the order and the materials.
|
- **Rendering Order**: The ParticleSystem list to be rendered. You can change the order and the materials.
|
||||||
|
|
||||||
**NOTE:** Press the `Refresh` button to reconstruct the rendering order based on children ParticleSystem's sorting order
|
> [!TIPS]
|
||||||
|
> Press the `Refresh` button to reconstruct the rendering order based on children ParticleSystem's sorting order
|
||||||
and z-position.
|
and z-position.
|
||||||
|
|
||||||
|
> [!TIPS]
|
||||||
|
> When a `GameObject` with this component is selected in the editor, a temporary `ParticleSystem` is added if needed so you can preview the effect in the Scene view.
|
||||||
|
> The generated `ParticleSystem` is marked with `HideFlags.DontSave`, so it is neither saved nor included in builds.
|
||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
### Basic Usage
|
### Basic Usage
|
||||||
@@ -195,6 +200,10 @@ and z-position.
|
|||||||
2. Adjust the ParticleSystem as you like.
|
2. Adjust the ParticleSystem as you like.
|
||||||

|

|
||||||
|
|
||||||
|
> [!Tips]
|
||||||
|
> Adding a `UIParticle` to the parent is the recommended setup rather than attaching it directly to the `ParticleSystem`.
|
||||||
|
> When using `ParticleSystem.emission.rateOverDistance`, it is recommended to move the transform of `UIParticle` rather than the `ParticleSystem`.
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
### Usage with Your Existing ParticleSystem Prefab
|
### Usage with Your Existing ParticleSystem Prefab
|
||||||
@@ -256,13 +265,34 @@ uiParticle.Stop();
|
|||||||
- **Unscaled Time:** Update with unscaled delta time.
|
- **Unscaled Time:** Update with unscaled delta time.
|
||||||
- **OnAttracted**: An event called when attracting is complete (per particle).
|
- **OnAttracted**: An event called when attracting is complete (per particle).
|
||||||
|
|
||||||
|
|
||||||
|
<br><br>
|
||||||
|
|
||||||
|
### Component: ParticleSystemPreviewer
|
||||||
|
|
||||||
|
`ParticleSystemPreviewer` is used to preview a ParticleSystem in the editor.
|
||||||
|
|
||||||
|
- When a `GameObject` with this component is selected in the editor, a temporary `ParticleSystem` is added if needed so you can preview the effect in the Scene view.
|
||||||
|
- The generated `ParticleSystem` is marked with `HideFlags.DontSave`, so it is neither saved nor included in builds.
|
||||||
|
|
||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
### Project Settings
|
### Project Settings
|
||||||
|
|
||||||

|
You can adjust the project-wide settings for `UI Particle`. (`Edit > Project Settings > UI > UI Particle`)
|
||||||
|
|
||||||
- Click `Edit > Project Settings` to open the Project Settings window and then select `UI > UI Particle` category.
|

|
||||||
|
|
||||||
|
#### Settings
|
||||||
|
|
||||||
|
- **Enable Linear To Gamma**: Automatically correct the color space of the mesh.
|
||||||
|
|
||||||
|
#### Editor
|
||||||
|
|
||||||
|
- **Hide Generated Component**: Automatically hide the generated `UIParticleRenderer` component and `UIParticle BakingCamera`.
|
||||||
|
|
||||||
|
- **Preview On Select**: When selecting UIParticle, a temporary ParticleSystem is generated for preview.
|
||||||
|
|
||||||
<br><br>
|
<br><br>
|
||||||
|
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
Profiler.BeginSample("(COF)[CanvasExt] GetViewProjectionMatrix");
|
Profiler.BeginSample("(COF)[CanvasExt] GetViewProjectionMatrix");
|
||||||
var rootCanvas = canvas.rootCanvas;
|
var rootCanvas = canvas.rootCanvas;
|
||||||
var cam = rootCanvas.worldCamera;
|
var cam = rootCanvas.worldCamera;
|
||||||
if (rootCanvas && rootCanvas.renderMode != RenderMode.ScreenSpaceOverlay && cam)
|
if (rootCanvas != null && rootCanvas.renderMode != RenderMode.ScreenSpaceOverlay && cam != null)
|
||||||
{
|
{
|
||||||
if (eye == Camera.MonoOrStereoscopicEye.Mono)
|
if (eye == Camera.MonoOrStereoscopicEye.Mono)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -12,6 +12,33 @@ namespace Coffee.UIParticleInternal
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal static class ComponentExtensions
|
internal static class ComponentExtensions
|
||||||
{
|
{
|
||||||
|
#if !UNITY_2019_2_OR_NEWER
|
||||||
|
public static bool TryGetComponent<T>(this GameObject self, out T component)
|
||||||
|
where T : Component
|
||||||
|
{
|
||||||
|
if (self == null)
|
||||||
|
{
|
||||||
|
component = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
component = self.GetComponent<T>();
|
||||||
|
return component != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool TryGetComponent<T>(this Component self, out T component)
|
||||||
|
where T : Component
|
||||||
|
{
|
||||||
|
if (self == null)
|
||||||
|
{
|
||||||
|
component = null;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.gameObject.TryGetComponent(out component);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get components in children of a specific type in the hierarchy of a GameObject.
|
/// Get components in children of a specific type in the hierarchy of a GameObject.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@@ -72,7 +99,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
{
|
{
|
||||||
T component = null;
|
T component = null;
|
||||||
var transform = self.transform;
|
var transform = self.transform;
|
||||||
while (transform)
|
while (transform != null)
|
||||||
{
|
{
|
||||||
if (transform.TryGetComponent<T>(out var c))
|
if (transform.TryGetComponent<T>(out var c))
|
||||||
{
|
{
|
||||||
@@ -93,7 +120,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
where T : Component
|
where T : Component
|
||||||
{
|
{
|
||||||
var tr = includeSelf ? self.transform : self.transform.parent;
|
var tr = includeSelf ? self.transform : self.transform.parent;
|
||||||
while (tr)
|
while (tr != null)
|
||||||
{
|
{
|
||||||
if (tr.TryGetComponent<T>(out var c) && valid(c)) return c;
|
if (tr.TryGetComponent<T>(out var c) && valid(c)) return c;
|
||||||
if (tr == stopAfter) return null;
|
if (tr == stopAfter) return null;
|
||||||
@@ -170,7 +197,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
if (!includeInactive) return self.GetComponentInParent<T>();
|
if (!includeInactive) return self.GetComponentInParent<T>();
|
||||||
|
|
||||||
var current = self.transform;
|
var current = self.transform;
|
||||||
while (current)
|
while (current != null)
|
||||||
{
|
{
|
||||||
if (current.TryGetComponent<T>(out var c)) return c;
|
if (current.TryGetComponent<T>(out var c)) return c;
|
||||||
current = current.parent;
|
current = current.parent;
|
||||||
|
|||||||
@@ -14,22 +14,66 @@ namespace Coffee.UIParticleInternal
|
|||||||
public abstract class PreloadedProjectSettings : ScriptableObject
|
public abstract class PreloadedProjectSettings : ScriptableObject
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
{
|
{
|
||||||
private class Postprocessor : AssetPostprocessor
|
[Tooltip("When enabled, this settings asset will be added to PlayerSettings.preloadedAssets in build.\n\n" +
|
||||||
|
"When disable, you should load this settings via Resources, AssetBundles or Addressables to use.")]
|
||||||
|
[SerializeField]
|
||||||
|
[Header("Advanced")]
|
||||||
|
[HideInInspector]
|
||||||
|
private bool m_PreLoadSettingsInBuild = true;
|
||||||
|
|
||||||
|
protected static bool s_BuildingPlayer;
|
||||||
|
|
||||||
|
private class EditorEvents : AssetPostprocessor, IPreprocessBuildWithReport, IPostprocessBuildWithReport
|
||||||
{
|
{
|
||||||
|
int IOrderedCallback.callbackOrder => 0;
|
||||||
|
|
||||||
private static void OnPostprocessAllAssets(string[] _, string[] __, string[] ___, string[] ____)
|
private static void OnPostprocessAllAssets(string[] _, string[] __, string[] ___, string[] ____)
|
||||||
{
|
{
|
||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private class PreprocessBuildWithReport : IPreprocessBuildWithReport
|
|
||||||
{
|
|
||||||
int IOrderedCallback.callbackOrder => 0;
|
|
||||||
|
|
||||||
void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report)
|
void IPreprocessBuildWithReport.OnPreprocessBuild(BuildReport report)
|
||||||
{
|
{
|
||||||
|
AssetDatabase.Refresh();
|
||||||
|
Initialize();
|
||||||
|
s_BuildingPlayer = true;
|
||||||
|
|
||||||
|
foreach (var t in TypeCache.GetTypesDerivedFrom(typeof(PreloadedProjectSettings<>)))
|
||||||
|
{
|
||||||
|
var settings = GetDefaultSettings(t);
|
||||||
|
if (settings == null || settings.m_PreLoadSettingsInBuild) continue;
|
||||||
|
|
||||||
|
PlayerSettings.SetPreloadedAssets(
|
||||||
|
PlayerSettings.GetPreloadedAssets()
|
||||||
|
.Where(x => x != null && x.GetType() != t)
|
||||||
|
.ToArray());
|
||||||
|
|
||||||
|
Debug.Log($"[PreloadedProjectSettings] Build started: removed '{settings.name}' " +
|
||||||
|
$"({t.Name}) from PreloadedAssets. " +
|
||||||
|
$"It will be restored after build completes.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IPostprocessBuildWithReport.OnPostprocessBuild(BuildReport report)
|
||||||
|
{
|
||||||
|
s_BuildingPlayer = false;
|
||||||
Initialize();
|
Initialize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if UNITY_2019_3_OR_NEWER
|
||||||
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
|
private static void OnDomainReload()
|
||||||
|
{
|
||||||
|
foreach (var t in TypeCache.GetTypesDerivedFrom(typeof(PreloadedProjectSettings<>)))
|
||||||
|
{
|
||||||
|
var defaultSettings = GetDefaultSettings(t);
|
||||||
|
if (defaultSettings != null)
|
||||||
|
{
|
||||||
|
defaultSettings.OnDomainReload();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void Initialize()
|
private static void Initialize()
|
||||||
@@ -38,14 +82,17 @@ namespace Coffee.UIParticleInternal
|
|||||||
{
|
{
|
||||||
var defaultSettings = GetDefaultSettings(t);
|
var defaultSettings = GetDefaultSettings(t);
|
||||||
if (defaultSettings == null)
|
if (defaultSettings == null)
|
||||||
|
{
|
||||||
|
if (!s_BuildingPlayer)
|
||||||
{
|
{
|
||||||
// When create a new instance, automatically set it as default settings.
|
// When create a new instance, automatically set it as default settings.
|
||||||
defaultSettings = CreateInstance(t) as PreloadedProjectSettings;
|
defaultSettings = CreateInstance(t) as PreloadedProjectSettings;
|
||||||
SetDefaultSettings(defaultSettings);
|
SetDefaultSettings(defaultSettings);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (GetPreloadedSettings(t).Length != 1)
|
else if (GetPreloadedSettings(t).Length != 1)
|
||||||
{
|
{
|
||||||
SetDefaultSettings(defaultSettings);
|
if (!s_BuildingPlayer) SetDefaultSettings(defaultSettings);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (defaultSettings != null)
|
if (defaultSettings != null)
|
||||||
@@ -73,7 +120,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
protected static PreloadedProjectSettings GetDefaultSettings(Type type)
|
protected static PreloadedProjectSettings GetDefaultSettings(Type type)
|
||||||
{
|
{
|
||||||
return GetPreloadedSettings(type).FirstOrDefault() as PreloadedProjectSettings
|
return GetPreloadedSettings(type).FirstOrDefault() as PreloadedProjectSettings
|
||||||
?? AssetDatabase.FindAssets($"t:{nameof(PreloadedProjectSettings)}")
|
?? AssetDatabase.FindAssets($"t:{type.Name}")
|
||||||
.Select(AssetDatabase.GUIDToAssetPath)
|
.Select(AssetDatabase.GUIDToAssetPath)
|
||||||
.Select(AssetDatabase.LoadAssetAtPath<PreloadedProjectSettings>)
|
.Select(AssetDatabase.LoadAssetAtPath<PreloadedProjectSettings>)
|
||||||
.FirstOrDefault(x => x != null && x.GetType() == type);
|
.FirstOrDefault(x => x != null && x.GetType() == type);
|
||||||
@@ -119,6 +166,39 @@ namespace Coffee.UIParticleInternal
|
|||||||
protected virtual void OnInitialize()
|
protected virtual void OnInitialize()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual void OnDomainReload()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal abstract class PreloadedProjectSettingsEditor : Editor
|
||||||
|
{
|
||||||
|
private SerializedProperty _preLoadSettingsInBuild;
|
||||||
|
|
||||||
|
protected virtual void OnEnable()
|
||||||
|
{
|
||||||
|
_preLoadSettingsInBuild = serializedObject.FindProperty("m_PreLoadSettingsInBuild");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void DrawPreLoadSettingsInBuild(string packageName)
|
||||||
|
{
|
||||||
|
EditorGUILayout.PropertyField(_preLoadSettingsInBuild);
|
||||||
|
if (!_preLoadSettingsInBuild.boolValue)
|
||||||
|
{
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
EditorGUILayout.HelpBox(
|
||||||
|
$"{target.GetType().Name} asset will not be built in.\n" +
|
||||||
|
$"please load manually from Resources, AssetBundle, or Addressables before using {packageName}.",
|
||||||
|
MessageType.Warning);
|
||||||
|
if (GUILayout.Button("Ping"))
|
||||||
|
{
|
||||||
|
EditorGUIUtility.PingObject(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
@@ -151,14 +231,14 @@ namespace Coffee.UIParticleInternal
|
|||||||
return s_Instance;
|
return s_Instance;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetDefaultSettings(s_Instance);
|
if (!s_BuildingPlayer) SetDefaultSettings(s_Instance);
|
||||||
return s_Instance;
|
return s_Instance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnPlayModeStateChanged(PlayModeStateChange state)
|
private void OnPlayModeStateChanged(PlayModeStateChange state)
|
||||||
{
|
{
|
||||||
if (!this) return;
|
if (this == null) return;
|
||||||
|
|
||||||
switch (state)
|
switch (state)
|
||||||
{
|
{
|
||||||
@@ -175,6 +255,11 @@ namespace Coffee.UIParticleInternal
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void OnDomainReload()
|
||||||
|
{
|
||||||
|
s_Instance = null;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
public static T instance => s_Instance != null ? s_Instance : s_Instance = CreateInstance<T>();
|
public static T instance => s_Instance != null ? s_Instance : s_Instance = CreateInstance<T>();
|
||||||
#endif
|
#endif
|
||||||
@@ -192,10 +277,14 @@ namespace Coffee.UIParticleInternal
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
EditorApplication.playModeStateChanged -= OnPlayModeStateChanged;
|
||||||
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
EditorApplication.playModeStateChanged += OnPlayModeStateChanged;
|
||||||
|
#else
|
||||||
|
if (s_Instance != null && s_Instance != this)
|
||||||
|
{
|
||||||
|
Destroy(s_Instance);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (s_Instance != null) return;
|
|
||||||
s_Instance = this as T;
|
s_Instance = this as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +315,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
{
|
{
|
||||||
if (_target == null)
|
if (_target == null)
|
||||||
{
|
{
|
||||||
if (_editor)
|
if (_editor != null)
|
||||||
{
|
{
|
||||||
DestroyImmediate(_editor);
|
DestroyImmediate(_editor);
|
||||||
_editor = null;
|
_editor = null;
|
||||||
|
|||||||
@@ -66,11 +66,6 @@ namespace Coffee.UIParticleInternal
|
|||||||
node = node.Next;
|
node = node.Next;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
_delegates.Clear();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -8,19 +8,19 @@ namespace Coffee.UIParticleInternal
|
|||||||
{
|
{
|
||||||
private static readonly Dictionary<Type, IFrameCache> s_Caches = new Dictionary<Type, IFrameCache>();
|
private static readonly Dictionary<Type, IFrameCache> s_Caches = new Dictionary<Type, IFrameCache>();
|
||||||
|
|
||||||
static FrameCache()
|
#if UNITY_EDITOR && UNITY_2019_3_OR_NEWER
|
||||||
{
|
|
||||||
s_Caches.Clear();
|
|
||||||
UIExtraCallbacks.onLateAfterCanvasRebuild += ClearAllCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
|
||||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
|
#elif UNITY_EDITOR
|
||||||
|
[InitializeOnLoadMethod]
|
||||||
|
#else
|
||||||
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||||
|
#endif
|
||||||
private static void Clear()
|
private static void Clear()
|
||||||
{
|
{
|
||||||
s_Caches.Clear();
|
s_Caches.Clear();
|
||||||
|
UIExtraCallbacks.onLateAfterCanvasRebuild -= ClearAllCache;
|
||||||
|
UIExtraCallbacks.onLateAfterCanvasRebuild += ClearAllCache;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Tries to retrieve a value from the frame cache with a specified key.
|
/// Tries to retrieve a value from the frame cache with a specified key.
|
||||||
|
|||||||
@@ -1,2 +1,11 @@
|
|||||||
fileFormatVersion: 2
|
fileFormatVersion: 2
|
||||||
guid: 4f9f22bb079324476b1473030ad9fec3
|
guid: 4f9f22bb079324476b1473030ad9fec3
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
|
|||||||
@@ -13,7 +13,9 @@ namespace Coffee.UIParticleInternal
|
|||||||
|
|
||||||
public static int count => s_Repository.count;
|
public static int count => s_Repository.count;
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
public static Func<string, Shader> onShaderFind = Shader.Find;
|
||||||
|
|
||||||
|
#if UNITY_EDITOR && UNITY_2019_3_OR_NEWER
|
||||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
public static void Clear()
|
public static void Clear()
|
||||||
{
|
{
|
||||||
@@ -48,7 +50,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
public static void Get(Hash128 hash, ref Material material, string shaderName)
|
public static void Get(Hash128 hash, ref Material material, string shaderName)
|
||||||
{
|
{
|
||||||
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
||||||
s_Repository.Get(hash, ref material, x => new Material(Shader.Find(x))
|
s_Repository.Get(hash, ref material, x => new Material(onShaderFind(x))
|
||||||
{
|
{
|
||||||
hideFlags = HideFlags.DontSave | HideFlags.NotEditable
|
hideFlags = HideFlags.DontSave | HideFlags.NotEditable
|
||||||
}, shaderName);
|
}, shaderName);
|
||||||
@@ -61,7 +63,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
public static void Get(Hash128 hash, ref Material material, string shaderName, string[] keywords)
|
public static void Get(Hash128 hash, ref Material material, string shaderName, string[] keywords)
|
||||||
{
|
{
|
||||||
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
Profiler.BeginSample("(COF)[MaterialRepository] Get");
|
||||||
s_Repository.Get(hash, ref material, x => new Material(Shader.Find(x.shaderName))
|
s_Repository.Get(hash, ref material, x => new Material(onShaderFind(x.shaderName))
|
||||||
{
|
{
|
||||||
hideFlags = HideFlags.DontSave | HideFlags.NotEditable,
|
hideFlags = HideFlags.DontSave | HideFlags.NotEditable,
|
||||||
shaderKeywords = x.keywords
|
shaderKeywords = x.keywords
|
||||||
|
|||||||
@@ -48,15 +48,10 @@ namespace Coffee.UIParticleInternal
|
|||||||
{
|
{
|
||||||
if (obj == null) return;
|
if (obj == null) return;
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
if (Application.isEditor)
|
Object.DestroyImmediate(obj, true);
|
||||||
{
|
#else
|
||||||
Object.DestroyImmediate(obj);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
Object.Destroy(obj);
|
Object.Destroy(obj);
|
||||||
}
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
[Conditional("UNITY_EDITOR")]
|
[Conditional("UNITY_EDITOR")]
|
||||||
@@ -114,7 +109,7 @@ namespace Coffee.UIParticleInternal
|
|||||||
{
|
{
|
||||||
if (Misc.isBatchOrBuilding) return;
|
if (Misc.isBatchOrBuilding) return;
|
||||||
|
|
||||||
var types = TypeCache.GetTypesWithAttribute<IconAttribute>();
|
var types = TypeCache.GetTypesWithAttribute(typeof(IconAttribute));
|
||||||
var scripts = MonoImporter.GetAllRuntimeMonoScripts();
|
var scripts = MonoImporter.GetAllRuntimeMonoScripts();
|
||||||
foreach (var type in types)
|
foreach (var type in types)
|
||||||
{
|
{
|
||||||
|
|||||||
88
Packages/src/Runtime/Internal/Utilities/TypeCache.cs
Normal file
88
Packages/src/Runtime/Internal/Utilities/TypeCache.cs
Normal file
@@ -0,0 +1,88 @@
|
|||||||
|
#if !UNITY_2019_2_OR_NEWER
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
|
||||||
|
namespace Coffee.UIParticleInternal
|
||||||
|
{
|
||||||
|
public static class TypeCache
|
||||||
|
{
|
||||||
|
private static readonly object s_Lock = new object();
|
||||||
|
private static readonly Dictionary<Type, Type[]> s_DerivedTypesCache = new Dictionary<Type, Type[]>();
|
||||||
|
private static readonly Dictionary<Type, Type[]> s_AttributeTypesCache = new Dictionary<Type, Type[]>();
|
||||||
|
|
||||||
|
public static IEnumerable<Type> GetTypesDerivedFrom(Type baseType)
|
||||||
|
{
|
||||||
|
lock (s_Lock)
|
||||||
|
{
|
||||||
|
if (s_DerivedTypesCache.TryGetValue(baseType, out var cached))
|
||||||
|
{
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
var types = new List<Type>();
|
||||||
|
foreach (var t in GetAllLoadableTypes())
|
||||||
|
{
|
||||||
|
if (t != baseType && baseType.IsAssignableFrom(t))
|
||||||
|
{
|
||||||
|
types.Add(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_DerivedTypesCache[baseType] = types.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<Type> GetTypesWithAttribute(Type attr)
|
||||||
|
{
|
||||||
|
lock (s_Lock)
|
||||||
|
{
|
||||||
|
if (s_AttributeTypesCache.TryGetValue(attr, out var cached))
|
||||||
|
{
|
||||||
|
return cached;
|
||||||
|
}
|
||||||
|
|
||||||
|
var types = new List<Type>();
|
||||||
|
foreach (var t in GetAllLoadableTypes())
|
||||||
|
{
|
||||||
|
if (t.GetCustomAttributes(attr, inherit: true).Length > 0)
|
||||||
|
{
|
||||||
|
types.Add(t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_AttributeTypesCache[attr] = types.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<Type> GetAllLoadableTypes()
|
||||||
|
{
|
||||||
|
foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||||
|
{
|
||||||
|
Type[] types;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
types = assembly.GetTypes();
|
||||||
|
}
|
||||||
|
catch (ReflectionTypeLoadException ex)
|
||||||
|
{
|
||||||
|
types = ex.Types;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (types == null)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var t in types)
|
||||||
|
{
|
||||||
|
if (t != null)
|
||||||
|
{
|
||||||
|
yield return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
11
Packages/src/Runtime/Internal/Utilities/TypeCache.cs.meta
Normal file
11
Packages/src/Runtime/Internal/Utilities/TypeCache.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: bc1207b657ed74ec19e459664d06925f
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -82,14 +82,18 @@ namespace Coffee.UIParticleInternal
|
|||||||
message: "InitializeAfterCanvasRebuild");
|
message: "InitializeAfterCanvasRebuild");
|
||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR && UNITY_2019_3_OR_NEWER
|
||||||
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
|
#elif UNITY_EDITOR
|
||||||
[InitializeOnLoadMethod]
|
[InitializeOnLoadMethod]
|
||||||
#endif
|
#else
|
||||||
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
|
||||||
|
#endif
|
||||||
private static void InitializeOnLoad()
|
private static void InitializeOnLoad()
|
||||||
{
|
{
|
||||||
Canvas.willRenderCanvases -= OnAfterCanvasRebuild;
|
Canvas.willRenderCanvases -= OnAfterCanvasRebuild;
|
||||||
s_IsInitializedAfterCanvasRebuild = false;
|
s_IsInitializedAfterCanvasRebuild = false;
|
||||||
|
s_LastScreenSize = default;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
237
Packages/src/Runtime/ParticleSystemPreviewer.cs
Normal file
237
Packages/src/Runtime/ParticleSystemPreviewer.cs
Normal file
@@ -0,0 +1,237 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using Coffee.UIParticleInternal;
|
||||||
|
using UnityEditor;
|
||||||
|
using UnityEngine;
|
||||||
|
|
||||||
|
namespace Coffee.UIExtensions
|
||||||
|
{
|
||||||
|
[Icon("Packages/com.coffee.ui-particle/Editor/UIParticleIcon.png")]
|
||||||
|
[ExecuteAlways]
|
||||||
|
internal class ParticleSystemPreviewer : MonoBehaviour
|
||||||
|
{
|
||||||
|
// Do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
[CustomEditor(typeof(ParticleSystemPreviewer))]
|
||||||
|
[CanEditMultipleObjects]
|
||||||
|
internal class ParticleSystemPreviewerEditor : Editor
|
||||||
|
{
|
||||||
|
private GameObject[] _gameObjects;
|
||||||
|
|
||||||
|
private void OnEnable()
|
||||||
|
{
|
||||||
|
_gameObjects = targets.OfType<ParticleSystemPreviewer>().Select(x => x.gameObject).ToArray();
|
||||||
|
ParticleSystemPreviewSystem.Register(_gameObjects);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void OnInspectorGUI()
|
||||||
|
{
|
||||||
|
base.OnInspectorGUI();
|
||||||
|
ParticleSystemPreviewSystem.DrawWarningForTemporary(_gameObjects);
|
||||||
|
ParticleSystemPreviewSystem.DrawWarningForPermanent(_gameObjects);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This class manages temporary ParticleSystems for preview purposes.
|
||||||
|
/// When previewing in the editor, it is common to place an empty ParticleSystem as the root, but it consumes memory at runtime if included in the build.
|
||||||
|
/// The temporary ParticleSystems created by this class only exist when the specified GameObject is selected, and are automatically deleted when the selection is cleared.
|
||||||
|
/// </summary>
|
||||||
|
internal class ParticleSystemPreviewSystem : ScriptableSingleton<ParticleSystemPreviewSystem>
|
||||||
|
{
|
||||||
|
private const HideFlags k_TemporaryHideFlags = HideFlags.DontSave | HideFlags.NotEditable;
|
||||||
|
|
||||||
|
[SerializeField]
|
||||||
|
private List<GameObject> m_PreviewObjects = new List<GameObject>();
|
||||||
|
|
||||||
|
#if UNITY_2019_3_OR_NEWER
|
||||||
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
|
#endif
|
||||||
|
[InitializeOnLoadMethod]
|
||||||
|
public static void Initialize()
|
||||||
|
{
|
||||||
|
instance.OnSelectionChanged();
|
||||||
|
|
||||||
|
Selection.selectionChanged -= instance.OnSelectionChanged;
|
||||||
|
Selection.selectionChanged += instance.OnSelectionChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a temporary ParticleSystem to the specified GameObject for preview purposes.
|
||||||
|
/// </summary>
|
||||||
|
public static void Register(GameObject[] targets)
|
||||||
|
{
|
||||||
|
foreach (var target in targets)
|
||||||
|
{
|
||||||
|
Register(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a temporary ParticleSystem to the specified GameObject for preview purposes.
|
||||||
|
/// </summary>
|
||||||
|
public static void Register(GameObject target)
|
||||||
|
{
|
||||||
|
if (!target) return;
|
||||||
|
if (EditorApplication.isPlaying) return;
|
||||||
|
if (instance.m_PreviewObjects.Contains(target)) return;
|
||||||
|
if (target.TryGetComponent<ParticleSystem>(out var ps))
|
||||||
|
{
|
||||||
|
if (ps.hideFlags == k_TemporaryHideFlags)
|
||||||
|
{
|
||||||
|
RegisterParticleSystem(ps);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create temporary ParticleSystem for preview.
|
||||||
|
RegisterParticleSystem(target.AddComponent<ParticleSystem>());
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the temporary ParticleSystem associated with the specified GameObject.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target"></param>
|
||||||
|
public static void Unregister(GameObject target)
|
||||||
|
{
|
||||||
|
if (!target) return;
|
||||||
|
|
||||||
|
var index = instance.m_PreviewObjects.IndexOf(target);
|
||||||
|
if (index < 0) return;
|
||||||
|
|
||||||
|
instance.m_PreviewObjects.RemoveAt(index);
|
||||||
|
if (HasTemporaryParticleSystem(target))
|
||||||
|
{
|
||||||
|
RemoveParticleSystem(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void RegisterParticleSystem(ParticleSystem ps)
|
||||||
|
{
|
||||||
|
if (!ps) return;
|
||||||
|
if (EditorApplication.isPlaying) return;
|
||||||
|
|
||||||
|
ps.hideFlags = k_TemporaryHideFlags;
|
||||||
|
|
||||||
|
var emission = ps.emission;
|
||||||
|
emission.enabled = false;
|
||||||
|
var shape = ps.shape;
|
||||||
|
shape.enabled = false;
|
||||||
|
|
||||||
|
if (ps.TryGetComponent<ParticleSystemRenderer>(out var psr))
|
||||||
|
{
|
||||||
|
psr.enabled = false;
|
||||||
|
psr.hideFlags = k_TemporaryHideFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
instance.m_PreviewObjects.Add(ps.gameObject);
|
||||||
|
EditorUtility.SetDirty(ps.gameObject);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes the temporary ParticleSystem associated with the specified GameObject.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="target"></param>
|
||||||
|
private static void RemoveParticleSystem(GameObject target)
|
||||||
|
{
|
||||||
|
if (target.TryGetComponent<ParticleSystem>(out var ps))
|
||||||
|
{
|
||||||
|
Misc.DestroyImmediate(ps);
|
||||||
|
EditorUtility.SetDirty(target);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (target.TryGetComponent<ParticleSystem>(out var psr))
|
||||||
|
{
|
||||||
|
Misc.DestroyImmediate(psr);
|
||||||
|
EditorUtility.SetDirty(target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the specified GameObject has a temporary ParticleSystem.
|
||||||
|
/// </summary>
|
||||||
|
private static bool HasTemporaryParticleSystem(GameObject target)
|
||||||
|
{
|
||||||
|
return target
|
||||||
|
&& instance.m_PreviewObjects.Contains(target)
|
||||||
|
&& target.TryGetComponent<ParticleSystem>(out var ps)
|
||||||
|
&& ps.hideFlags == k_TemporaryHideFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Checks if the specified GameObject has a permanent ParticleSystem.
|
||||||
|
/// </summary>
|
||||||
|
private static bool HasPermanentParticleSystem(GameObject target)
|
||||||
|
{
|
||||||
|
return target
|
||||||
|
&& target.TryGetComponent<ParticleSystem>(out var ps)
|
||||||
|
&& ps.hideFlags != k_TemporaryHideFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSelectionChanged()
|
||||||
|
{
|
||||||
|
var selectedGameObjects = Selection.gameObjects;
|
||||||
|
for (var i = m_PreviewObjects.Count - 1; 0 <= i; i--)
|
||||||
|
{
|
||||||
|
var go = m_PreviewObjects[i];
|
||||||
|
if (!go)
|
||||||
|
{
|
||||||
|
m_PreviewObjects.RemoveAt(i);
|
||||||
|
}
|
||||||
|
else if (EditorApplication.isPlaying && !selectedGameObjects.Contains(go))
|
||||||
|
{
|
||||||
|
Unregister(go);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawWarningForTemporary(GameObject[] gameObjects)
|
||||||
|
{
|
||||||
|
if (gameObjects == null || gameObjects.Length == 0 || !gameObjects.Any(HasTemporaryParticleSystem)) return;
|
||||||
|
|
||||||
|
if (WarningButton("The temporary ParticleSystem for preview is attached.\n" +
|
||||||
|
"It will be removed when exiting edit mode.", "Remove"))
|
||||||
|
{
|
||||||
|
foreach (var go in gameObjects)
|
||||||
|
{
|
||||||
|
if (HasTemporaryParticleSystem(go))
|
||||||
|
{
|
||||||
|
RemoveParticleSystem(go);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void DrawWarningForPermanent(GameObject[] gameObjects)
|
||||||
|
{
|
||||||
|
if (gameObjects == null || gameObjects.Length == 0 || !gameObjects.Any(HasPermanentParticleSystem)) return;
|
||||||
|
|
||||||
|
if (WarningButton("The permanent ParticleSystem is attached.\n" +
|
||||||
|
"It will be included in build.", "Remove"))
|
||||||
|
{
|
||||||
|
foreach (var go in gameObjects)
|
||||||
|
{
|
||||||
|
if (HasPermanentParticleSystem(go))
|
||||||
|
{
|
||||||
|
RemoveParticleSystem(go);
|
||||||
|
Unregister(go);
|
||||||
|
Register(go);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static bool WarningButton(string message, string buttonText)
|
||||||
|
{
|
||||||
|
EditorGUILayout.BeginHorizontal();
|
||||||
|
EditorGUILayout.HelpBox(message, MessageType.Warning, true);
|
||||||
|
var clicked = GUILayout.Button(EditorGUIUtility.TrTempContent(buttonText));
|
||||||
|
EditorGUILayout.EndHorizontal();
|
||||||
|
return clicked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
11
Packages/src/Runtime/ParticleSystemPreviewer.cs.meta
Normal file
11
Packages/src/Runtime/ParticleSystemPreviewer.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
fileFormatVersion: 2
|
||||||
|
guid: b171deb49fb7b471291108ad7e1c9baa
|
||||||
|
MonoImporter:
|
||||||
|
externalObjects: {}
|
||||||
|
serializedVersion: 2
|
||||||
|
defaultReferences: []
|
||||||
|
executionOrder: 0
|
||||||
|
icon: {instanceID: 0}
|
||||||
|
userData:
|
||||||
|
assetBundleName:
|
||||||
|
assetBundleVariant:
|
||||||
@@ -545,7 +545,10 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
var ps = particles[i];
|
var ps = particles[i];
|
||||||
if (!ps
|
if (!ps
|
||||||
|
#if UNITY_EDITOR
|
||||||
|
|| (ps.hideFlags & HideFlags.DontSave) != 0 // Dummy ParticleSystems for preview.
|
||||||
|| ps.gameObject.CompareTag("EditorOnly") // Ignore "EditorOnly" tagged ParticleSystems.
|
|| ps.gameObject.CompareTag("EditorOnly") // Ignore "EditorOnly" tagged ParticleSystems.
|
||||||
|
#endif
|
||||||
|| ps.GetComponentInParent<UIParticle>(true) != this) // Ignore ParticleSystems that are not under this UIParticle.
|
|| ps.GetComponentInParent<UIParticle>(true) != this) // Ignore ParticleSystems that are not under this UIParticle.
|
||||||
{
|
{
|
||||||
particles.RemoveAt(i);
|
particles.RemoveAt(i);
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
using Coffee.UIParticleInternal;
|
using Coffee.UIParticleInternal;
|
||||||
using UnityEditor;
|
using UnityEditor;
|
||||||
using UnityEngine;
|
using UnityEngine;
|
||||||
|
using UnityEngine.Serialization;
|
||||||
|
|
||||||
namespace Coffee.UIExtensions
|
namespace Coffee.UIExtensions
|
||||||
{
|
{
|
||||||
@@ -9,12 +10,14 @@ namespace Coffee.UIExtensions
|
|||||||
{
|
{
|
||||||
[Header("Setting")]
|
[Header("Setting")]
|
||||||
[SerializeField]
|
[SerializeField]
|
||||||
internal bool m_EnableLinearToGamma = true;
|
[Tooltip("Automatically correct the color space of the mesh.")]
|
||||||
|
[FormerlySerializedAs("m_EnableLinearToGamma")]
|
||||||
|
internal bool m_AutoColorCorrection = true;
|
||||||
|
|
||||||
public static bool enableLinearToGamma
|
public static bool autoColorCorrection
|
||||||
{
|
{
|
||||||
get => instance.m_EnableLinearToGamma;
|
get => instance.m_AutoColorCorrection;
|
||||||
set => instance.m_EnableLinearToGamma = value;
|
set => instance.m_AutoColorCorrection = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -25,10 +28,16 @@ namespace Coffee.UIExtensions
|
|||||||
[SerializeField]
|
[SerializeField]
|
||||||
private bool m_HideGeneratedObjects = true;
|
private bool m_HideGeneratedObjects = true;
|
||||||
|
|
||||||
public static HideFlags globalHideFlags => instance.m_HideGeneratedObjects
|
[Tooltip("When selecting UIParticle, a temporary ParticleSystem is generated for preview.")]
|
||||||
|
[SerializeField]
|
||||||
|
private bool m_PreviewOnSelect = true;
|
||||||
|
|
||||||
|
internal static HideFlags globalHideFlags => instance.m_HideGeneratedObjects
|
||||||
? HideFlags.DontSave | HideFlags.NotEditable | HideFlags.HideInHierarchy | HideFlags.HideInInspector
|
? HideFlags.DontSave | HideFlags.NotEditable | HideFlags.HideInHierarchy | HideFlags.HideInInspector
|
||||||
: HideFlags.DontSave | HideFlags.NotEditable;
|
: HideFlags.DontSave | HideFlags.NotEditable;
|
||||||
|
|
||||||
|
internal static bool s_PreviewOnSelectOnSelect => instance.m_PreviewOnSelect;
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
[SettingsProvider]
|
[SettingsProvider]
|
||||||
private static SettingsProvider CreateSettingsProvider()
|
private static SettingsProvider CreateSettingsProvider()
|
||||||
|
|||||||
@@ -444,7 +444,7 @@ namespace Coffee.UIExtensions
|
|||||||
_lastBounds = bounds;
|
_lastBounds = bounds;
|
||||||
|
|
||||||
// Convert linear color to gamma color.
|
// Convert linear color to gamma color.
|
||||||
if (UIParticleProjectSettings.enableLinearToGamma && canvas.ShouldGammaToLinearInMesh())
|
if (UIParticleProjectSettings.autoColorCorrection && canvas.ShouldGammaToLinearInMesh())
|
||||||
{
|
{
|
||||||
workerMesh.LinearToGamma();
|
workerMesh.LinearToGamma();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,6 +39,17 @@ namespace Coffee.UIExtensions
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
|
#if UNITY_2019_3_OR_NEWER
|
||||||
|
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.SubsystemRegistration)]
|
||||||
|
private static void OnDomainReload()
|
||||||
|
{
|
||||||
|
s_ActiveParticles.Clear();
|
||||||
|
s_ActiveAttractors.Clear();
|
||||||
|
s_UpdatedGroupIds.Clear();
|
||||||
|
s_FrameCount = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
[InitializeOnLoadMethod]
|
[InitializeOnLoadMethod]
|
||||||
private static void InitializeOnLoad()
|
private static void InitializeOnLoad()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -40,12 +40,8 @@
|
|||||||
Lighting Off
|
Lighting Off
|
||||||
ZWrite Off
|
ZWrite Off
|
||||||
ZTest [unity_GUIZTestMode]
|
ZTest [unity_GUIZTestMode]
|
||||||
Fog
|
Fog { Mode Off }
|
||||||
{
|
|
||||||
Mode Off
|
|
||||||
}
|
|
||||||
Blend One One
|
Blend One One
|
||||||
|
|
||||||
ColorMask [_ColorMask]
|
ColorMask [_ColorMask]
|
||||||
|
|
||||||
Pass
|
Pass
|
||||||
@@ -76,6 +72,7 @@
|
|||||||
fixed4 color : COLOR;
|
fixed4 color : COLOR;
|
||||||
float2 texcoord : TEXCOORD0;
|
float2 texcoord : TEXCOORD0;
|
||||||
float4 worldPosition : TEXCOORD1;
|
float4 worldPosition : TEXCOORD1;
|
||||||
|
float4 mask : TEXCOORD2;
|
||||||
UNITY_VERTEX_OUTPUT_STEREO
|
UNITY_VERTEX_OUTPUT_STEREO
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -84,16 +81,43 @@
|
|||||||
float4 _MainTex_ST;
|
float4 _MainTex_ST;
|
||||||
fixed4 _TextureSampleAdd;
|
fixed4 _TextureSampleAdd;
|
||||||
float4 _ClipRect;
|
float4 _ClipRect;
|
||||||
|
float _UIMaskSoftnessX;
|
||||||
|
float _UIMaskSoftnessY;
|
||||||
|
int _UIVertexColorAlwaysGammaSpace;
|
||||||
|
|
||||||
|
half3 _UIGammaToLinear(half3 value)
|
||||||
|
{
|
||||||
|
half3 low = 0.0849710 * value - 0.000163029;
|
||||||
|
half3 high = value * (value * (value * 0.265885 + 0.736584) - 0.00980184) + 0.00319697;
|
||||||
|
|
||||||
|
// We should be 0.5 away from any actual gamma value stored in an 8 bit channel
|
||||||
|
const half3 split = (half3)0.0725490; // Equals 18.5 / 255
|
||||||
|
return (value < split) ? low : high;
|
||||||
|
}
|
||||||
|
|
||||||
v2f vert(appdata_t v)
|
v2f vert(appdata_t v)
|
||||||
{
|
{
|
||||||
v2f OUT;
|
v2f OUT;
|
||||||
UNITY_SETUP_INSTANCE_ID(v);
|
UNITY_SETUP_INSTANCE_ID(v);
|
||||||
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
|
UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(OUT);
|
||||||
|
float4 vPosition = UnityObjectToClipPos(v.vertex);
|
||||||
OUT.worldPosition = v.vertex;
|
OUT.worldPosition = v.vertex;
|
||||||
OUT.vertex = UnityObjectToClipPos(OUT.worldPosition);
|
OUT.vertex = vPosition;
|
||||||
|
|
||||||
OUT.texcoord = TRANSFORM_TEX(v.texcoord, _MainTex);
|
float2 pixelSize = vPosition.w;
|
||||||
|
pixelSize /= float2(1, 1) * abs(mul((float2x2)UNITY_MATRIX_P, _ScreenParams.xy));
|
||||||
|
|
||||||
|
float4 clampedRect = clamp(_ClipRect, -2e10, 2e10);
|
||||||
|
float2 maskUV = (v.vertex.xy - clampedRect.xy) / (clampedRect.zw - clampedRect.xy);
|
||||||
|
OUT.texcoord = TRANSFORM_TEX(v.texcoord.xy, _MainTex);
|
||||||
|
OUT.mask = float4(v.vertex.xy * 2 - clampedRect.xy - clampedRect.zw, 0.25 / (0.25 * half2(_UIMaskSoftnessX, _UIMaskSoftnessY) + abs(pixelSize.xy)));
|
||||||
|
|
||||||
|
if (_UIVertexColorAlwaysGammaSpace)
|
||||||
|
{
|
||||||
|
#ifndef UNITY_COLORSPACE_GAMMA
|
||||||
|
v.color.rgb = _UIGammaToLinear(v.color.rgb);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
OUT.color = v.color * _Color;
|
OUT.color = v.color * _Color;
|
||||||
return OUT;
|
return OUT;
|
||||||
@@ -101,10 +125,18 @@
|
|||||||
|
|
||||||
fixed4 frag(v2f IN) : SV_Target
|
fixed4 frag(v2f IN) : SV_Target
|
||||||
{
|
{
|
||||||
half4 color = (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd) * IN.color;
|
//Round up the alpha color coming from the interpolator (to 1.0/256.0 steps)
|
||||||
|
//The incoming alpha could have numerical instability, which makes it very sensible to
|
||||||
|
//HDR color transparency blend, when it blends with the world's texture.
|
||||||
|
const half alphaPrecision = half(0xff);
|
||||||
|
const half invAlphaPrecision = half(1.0 / alphaPrecision);
|
||||||
|
IN.color.a = round(IN.color.a * alphaPrecision) * invAlphaPrecision;
|
||||||
|
|
||||||
|
half4 color = IN.color * (tex2D(_MainTex, IN.texcoord) + _TextureSampleAdd);
|
||||||
|
|
||||||
#ifdef UNITY_UI_CLIP_RECT
|
#ifdef UNITY_UI_CLIP_RECT
|
||||||
color.a *= UnityGet2DClipping(IN.worldPosition.xy, _ClipRect);
|
half2 m = saturate((_ClipRect.zw - _ClipRect.xy - abs(IN.mask.xy)) * IN.mask.zw);
|
||||||
|
color.a *= m.x * m.y;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef UNITY_UI_ALPHACLIP
|
#ifdef UNITY_UI_ALPHACLIP
|
||||||
@@ -112,6 +144,7 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
color.rgb *= color.a;
|
color.rgb *= color.a;
|
||||||
|
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
ENDCG
|
ENDCG
|
||||||
|
|||||||
Reference in New Issue
Block a user