Compare commits

..

11 Commits
2.1.1 ... 2.3.0

Author SHA1 Message Date
mob-sakai
9c525ad0f0 update documents for v2.3.0 2019-05-12 16:03:20 +09:00
mob-sakai
66a0ab7ad5 fix #47; World simulation bug 2019-05-08 00:06:46 +09:00
mob-sakai
888eac4e54 update documents for v2.2.1 2019-02-26 11:30:17 +09:00
mob-sakai
f6e64c325b close #45; Disable ParticleSystemRenderer on reset 2019-02-26 11:28:22 +09:00
mob-sakai
beb6fa8367 Format 2019-02-26 11:11:48 +09:00
mob-sakai
6c2ed22e3a fix #44; v2.2.0 has 2 warnings 2019-02-26 11:10:47 +09:00
mob-sakai
4c260061c8 update documents for v2.2.0 2019-02-23 23:39:55 +09:00
mob-sakai
fb2904160e Update demo 2019-02-23 23:28:50 +09:00
mob-sakai
7696451ac9 Refactor 2019-02-23 23:28:50 +09:00
mob-sakai
54098eea56 close #43; Display warning when material does not support Mask 2019-02-23 21:29:38 +09:00
mob-sakai
79bbc4de95 close #42; Support changing material property by AnimationClip 2019-02-23 16:40:57 +09:00
7 changed files with 353 additions and 20 deletions

View File

@@ -1,13 +1,41 @@
# Changelog
## [v2.3.0](https://github.com/mob-sakai/ParticleEffectForUGUI/tree/v2.3.0) (2019-05-12)
[Full Changelog](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v2.2.1...v2.3.0)
World simulation bug due to transform movement have been fixed
**Fixed bugs:**
- World simulation bug due to transform movement [\#47](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/47)
## [v2.2.1](https://github.com/mob-sakai/ParticleEffectForUGUI/tree/v2.2.1) (2019-02-26)
[Full Changelog](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v2.2.0...v2.2.1)
**Fixed bugs:**
- v2.2.0 has 2 warnings [\#44](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/44)
- Disable ParticleSystemRenderer on reset [\#45](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/45)
## [v2.2.0](https://github.com/mob-sakai/ParticleEffectForUGUI/tree/v2.2.0) (2019-02-23)
[Full Changelog](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v2.1.1...v2.2.0)
**Implemented enhancements:**
- Display warning when material does not support Mask [\#43](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/43)
- Support changing material property by AnimationClip [\#42](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/42)
**Fixed bugs:**
- UV Animation is not work. [\#41](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/41)
## [v2.1.1](https://github.com/mob-sakai/ParticleEffectForUGUI/tree/v2.1.1) (2019-02-15)
[Full Changelog](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v2.1.0...v2.1.1)
**Fixed bugs:**
- UIParticle.Scale - Rendering Order Issue [\#39](https://github.com/mob-sakai/ParticleEffectForUGUI/issues/39)
## [v2.1.0](https://github.com/mob-sakai/ParticleEffectForUGUI/tree/v2.1.0) (2019-02-07)
[Full Changelog](https://github.com/mob-sakai/ParticleEffectForUGUI/compare/v2.0.0...v2.1.0)

View File

@@ -55,6 +55,8 @@ Compares this "Baking mesh" approach with the conventional approach:
![](https://user-images.githubusercontent.com/12690315/49866926-6c22f500-fe4c-11e8-8393-d5a546e9e2d3.gif)
* Scaled gizmo
![](https://user-images.githubusercontent.com/12690315/50343861-f31e4e80-056b-11e9-8f60-8bd0a8ff7adb.gif)
* Animatable material property
![](https://user-images.githubusercontent.com/12690315/53286323-2d94a980-37b0-11e9-8afb-c4a207805ff2.gif)
@@ -74,12 +76,13 @@ Find the manifest.json file in the Packages folder of your project and edit it t
```js
{
"dependencies": {
"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git#2.1.0",
"com.coffee.ui-particle": "https://github.com/mob-sakai/ParticleEffectForUGUI.git#2.2.1",
...
},
}
```
To update the package, change `#{version}` to the target version.
To update the package, change `#{version}` to the target version.
Or, use [UpmGitExtension](https://github.com/mob-sakai/UpmGitExtension).
#### Using .unitypackage file (for Unity 2018.2+)
@@ -124,6 +127,21 @@ Select `Assets > Import Package > Custom Package` from the menu.
<br><br><br><br>
## Development Note
#### Animatable material property
![](https://user-images.githubusercontent.com/12690315/53286323-2d94a980-37b0-11e9-8afb-c4a207805ff2.gif)
Animation clips can change the material properties of the Renderer, such as ParticleSystemRenderer.
It uses MaterialPropertyBlock so it does not create new material instances.
Using material properties, you can change UV animation, scale and color etc.
Well, there is a component called CanvasRenderer.
It is used by all Graphic components for UI (Text, Image, Raw Image, etc.) including UIParticle.
However, It is **NOT** a Renderer.
Therefore, in UIParticle, changing ParticleSystemRenderer's MaterialPropertyBlock by animation clip is ignored.
To prevent this, Use "Animatable Material Property".
"Animatable Material Property" gets the necessary properties from ParticleSystemRenderer's MaterialPropertyBlock and sets them to the CanvasRenderer's material.

View File

@@ -6,6 +6,7 @@ using System.Linq;
using UnityEditor.IMGUI.Controls;
using System;
using System.Reflection;
using ShaderPropertyType = Coffee.UIExtensions.UIParticle.AnimatableProperty.ShaderPropertyType;
namespace Coffee.UIExtensions
{
@@ -13,6 +14,108 @@ namespace Coffee.UIExtensions
[CanEditMultipleObjects]
public class UIParticleEditor : GraphicEditor
{
class AnimatedPropertiesEditor
{
static readonly List<string> s_ActiveNames = new List<string> ();
static readonly System.Text.StringBuilder s_Sb = new System.Text.StringBuilder ();
public string name;
public ShaderPropertyType type;
static string CollectActiveNames (SerializedProperty sp, List<string> result)
{
result.Clear ();
for (int i = 0; i < sp.arraySize; i++)
{
result.Add (sp.GetArrayElementAtIndex (i).FindPropertyRelative ("m_Name").stringValue);
}
s_Sb.Length = 0;
if (result.Count == 0)
{
s_Sb.Append ("Nothing");
}
else
{
result.Aggregate (s_Sb, (a, b) => s_Sb.AppendFormat ("{0}, ", b));
s_Sb.Length -= 2;
}
return s_Sb.ToString ();
}
public static void DrawAnimatableProperties (SerializedProperty sp, Material mat)
{
if (!mat || !mat.shader)
return;
bool isClicked = false;
using (new EditorGUILayout.HorizontalScope (GUILayout.ExpandWidth (false)))
{
var r = EditorGUI.PrefixLabel (EditorGUILayout.GetControlRect (true), new GUIContent (sp.displayName, sp.tooltip));
isClicked = GUI.Button (r, CollectActiveNames (sp, s_ActiveNames), EditorStyles.popup);
}
if (isClicked)
{
GenericMenu gm = new GenericMenu ();
gm.AddItem (new GUIContent ("Nothing"), s_ActiveNames.Count == 0, () =>
{
sp.ClearArray ();
sp.serializedObject.ApplyModifiedProperties ();
});
for (int i = 0; i < sp.arraySize; i++)
{
var p = sp.GetArrayElementAtIndex (i);
var name = p.FindPropertyRelative ("m_Name").stringValue;
var type = (ShaderPropertyType)p.FindPropertyRelative ("m_Type").intValue;
AddMenu (gm, sp, new AnimatedPropertiesEditor () { name = name, type = type }, false);
}
for (int i = 0; i < ShaderUtil.GetPropertyCount (mat.shader); i++)
{
var pName = ShaderUtil.GetPropertyName (mat.shader, i);
var type = (ShaderPropertyType)ShaderUtil.GetPropertyType (mat.shader, i);
AddMenu (gm, sp, new AnimatedPropertiesEditor () { name = pName, type = type }, true);
if (type == ShaderPropertyType.Texture)
{
AddMenu (gm, sp, new AnimatedPropertiesEditor () { name = pName + "_ST", type = ShaderPropertyType.Vector }, true);
AddMenu (gm, sp, new AnimatedPropertiesEditor () { name = pName + "_HDR", type = ShaderPropertyType.Vector }, true);
AddMenu (gm, sp, new AnimatedPropertiesEditor () { name = pName + "_TexelSize", type = ShaderPropertyType.Vector }, true);
}
}
gm.ShowAsContext ();
}
}
public static void AddMenu (GenericMenu menu, SerializedProperty sp, AnimatedPropertiesEditor property, bool add)
{
if (add && s_ActiveNames.Contains (property.name))
return;
menu.AddItem (new GUIContent (string.Format ("{0} ({1})", property.name, property.type)), s_ActiveNames.Contains (property.name), () =>
{
var index = s_ActiveNames.IndexOf (property.name);
if (0 <= index)
{
sp.DeleteArrayElementAtIndex (index);
}
else
{
sp.InsertArrayElementAtIndex (sp.arraySize);
var p = sp.GetArrayElementAtIndex (sp.arraySize - 1);
p.FindPropertyRelative ("m_Name").stringValue = property.name;
p.FindPropertyRelative ("m_Type").intValue = (int)property.type;
}
sp.serializedObject.ApplyModifiedProperties ();
});
}
}
//################################
// Constant or Static Members.
//################################
@@ -25,6 +128,15 @@ namespace Coffee.UIExtensions
static readonly Color s_ShapeGizmoThicknessTint = new Color (0.7f, 0.7f, 0.7f, 1.0f);
static Material s_Material;
static readonly List<string> s_MaskablePropertyNames = new List<string> ()
{
"_Stencil",
"_StencilComp",
"_StencilOp",
"_StencilWriteMask",
"_StencilReadMask",
"_ColorMask",
};
//################################
// Public/Protected Members.
@@ -39,6 +151,7 @@ namespace Coffee.UIExtensions
_spTrailParticle = serializedObject.FindProperty ("m_TrailParticle");
_spScale = serializedObject.FindProperty ("m_Scale");
_spIgnoreParent = serializedObject.FindProperty ("m_IgnoreParent");
_spAnimatableProperties = serializedObject.FindProperty ("m_AnimatableProperties");
if (!s_Material)
{
@@ -86,6 +199,9 @@ namespace Coffee.UIExtensions
EditorGUILayout.PropertyField (_spScale);
EditorGUI.EndDisabledGroup ();
// AnimatableProperties
AnimatedPropertiesEditor.DrawAnimatableProperties (_spAnimatableProperties, current.material);
current.GetComponentsInChildren<ParticleSystem> (true, s_ParticleSystems);
if (s_ParticleSystems.Any (x => x.GetComponent<UIParticle> () == null))
{
@@ -104,9 +220,28 @@ namespace Coffee.UIExtensions
}
s_ParticleSystems.Clear ();
if (current.maskable && current.material && current.material.shader)
{
var mat = current.material;
var shader = mat.shader;
foreach (var propName in s_MaskablePropertyNames)
{
if (!mat.HasProperty (propName))
{
EditorGUILayout.HelpBox (string.Format ("Shader {0} doesn't have '{1}' property. This graphic is not maskable.", shader.name, propName), MessageType.Warning);
break;
}
}
}
serializedObject.ApplyModifiedProperties ();
}
//################################
// Private Members.
//################################
@@ -114,6 +249,7 @@ namespace Coffee.UIExtensions
SerializedProperty _spTrailParticle;
SerializedProperty _spScale;
SerializedProperty _spIgnoreParent;
SerializedProperty _spAnimatableProperties;
UIParticle [] _particles;
ArcHandle _arcHandle = new ArcHandle ();
BoxBoundsHandle _boxBoundsHandle = new BoxBoundsHandle ();
@@ -174,7 +310,7 @@ namespace Coffee.UIExtensions
transformMatrix *= emitterMatrix;
Handles.matrix = transformMatrix;
if(uip.canvas.renderMode == RenderMode.ScreenSpaceOverlay || ps.main.scalingMode == ParticleSystemScalingMode.Hierarchy)
if (uip.canvas.renderMode == RenderMode.ScreenSpaceOverlay || ps.main.scalingMode == ParticleSystemScalingMode.Hierarchy)
{
Handles.matrix = Handles.matrix * Matrix4x4.Scale (Vector3.one * uip.scale);
}

View File

@@ -3,6 +3,7 @@ using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Profiling;
using UnityEngine.UI;
using ShaderPropertyType = Coffee.UIExtensions.UIParticle.AnimatableProperty.ShaderPropertyType;
namespace Coffee.UIExtensions
@@ -35,6 +36,42 @@ namespace Coffee.UIExtensions
[Tooltip ("Ignore parent scale")]
[SerializeField] bool m_IgnoreParent = false;
[Tooltip ("Animatable material properties. AnimationでParticleSystemのマテリアルプロパティを変更する場合、有効にしてください。")]
[SerializeField] AnimatableProperty [] m_AnimatableProperties = new AnimatableProperty [0];
static MaterialPropertyBlock s_Mpb;
[System.Serializable]
public class AnimatableProperty : ISerializationCallbackReceiver
{
public enum ShaderPropertyType
{
Color,
Vector,
Float,
Range,
Texture,
};
[SerializeField]
string m_Name = "";
[SerializeField]
ShaderPropertyType m_Type = ShaderPropertyType.Vector;
public int id { get; private set; }
public ShaderPropertyType type { get { return m_Type; } }
public void OnBeforeSerialize ()
{
}
public void OnAfterDeserialize ()
{
id = Shader.PropertyToID (m_Name);
}
}
//################################
// Public/Protected Members.
@@ -57,9 +94,7 @@ namespace Coffee.UIExtensions
if (!tex && _renderer)
{
Profiler.BeginSample ("Check material");
var mat = m_IsTrail
? _renderer.trailMaterial
: _renderer.sharedMaterial;
var mat = material;
if (mat && mat.HasProperty (s_IdMainTex))
{
tex = mat.mainTexture;
@@ -70,6 +105,35 @@ namespace Coffee.UIExtensions
}
}
public override Material material
{
get
{
return _renderer
? m_IsTrail
? _renderer.trailMaterial
: _renderer.sharedMaterial
: null;
}
set
{
if (!_renderer)
{
}
else if (m_IsTrail && _renderer.trailMaterial != value)
{
_renderer.trailMaterial = value;
SetMaterialDirty ();
}
else if (!m_IsTrail && _renderer.sharedMaterial != value)
{
_renderer.sharedMaterial = value;
SetMaterialDirty ();
}
}
}
/// <summary>
/// Particle effect scale.
/// </summary>
@@ -117,7 +181,15 @@ namespace Coffee.UIExtensions
/// <param name="baseMaterial">Configured Material.</param>
public override Material GetModifiedMaterial (Material baseMaterial)
{
return base.GetModifiedMaterial (_renderer ? _renderer.sharedMaterial : baseMaterial);
Material mat = null;
if (!_renderer)
mat = baseMaterial;
else if (m_AnimatableProperties.Length == 0)
mat = _renderer.sharedMaterial;
else
mat = new Material (material);
return base.GetModifiedMaterial (mat);
}
/// <summary>
@@ -129,6 +201,7 @@ namespace Coffee.UIExtensions
if (s_ActiveParticles.Count == 0)
{
Canvas.willRenderCanvases += UpdateMeshes;
s_Mpb = new MaterialPropertyBlock ();
}
s_ActiveParticles.Add (this);
@@ -151,6 +224,13 @@ namespace Coffee.UIExtensions
_mesh.MarkDynamic ();
CheckTrail ();
if (cachedParticleSystem)
{
_oldPos = cachedParticleSystem.main.scalingMode == ParticleSystemScalingMode.Local
? rectTransform.localPosition
: rectTransform.position;
}
base.OnEnable ();
}
@@ -182,6 +262,21 @@ namespace Coffee.UIExtensions
base.OnDisable ();
}
#if UNITY_EDITOR
/// <summary>
/// Reset to default values.
/// </summary>
protected override void Reset ()
{
// Disable ParticleSystemRenderer on reset.
if (cachedParticleSystem)
{
cachedParticleSystem.GetComponent<ParticleSystemRenderer> ().enabled = false;
}
base.Reset ();
}
#endif
/// <summary>
/// Call to update the geometry of the Graphic onto the CanvasRenderer.
/// </summary>
@@ -236,7 +331,7 @@ namespace Coffee.UIExtensions
UIParticle _parent;
List<UIParticle> _children = new List<UIParticle> ();
Matrix4x4 scaleaMatrix = default (Matrix4x4);
Vector3 _worldPos;
Vector3 _oldPos;
static ParticleSystem.Particle [] s_Particles = new ParticleSystem.Particle [4096];
/// <summary>
@@ -285,11 +380,12 @@ namespace Coffee.UIExtensions
Profiler.EndSample ();
Profiler.BeginSample ("Make Matrix");
scaleaMatrix = m_ParticleSystem.main.scalingMode == ParticleSystemScalingMode.Hierarchy
ParticleSystem.MainModule main = m_ParticleSystem.main;
scaleaMatrix = main.scalingMode == ParticleSystemScalingMode.Hierarchy
? Matrix4x4.Scale (scale * Vector3.one)
: Matrix4x4.Scale (scale * rootCanvas.transform.localScale);
Matrix4x4 matrix = default (Matrix4x4);
switch (m_ParticleSystem.main.simulationSpace)
switch (main.simulationSpace)
{
case ParticleSystemSimulationSpace.Local:
matrix =
@@ -302,12 +398,25 @@ namespace Coffee.UIExtensions
scaleaMatrix
* rectTransform.worldToLocalMatrix;
bool isLocalScaling = main.scalingMode == ParticleSystemScalingMode.Local;
Vector3 newPos = rectTransform.position;
Vector3 delta = (newPos - _worldPos);
_worldPos = newPos;
if (canvas.renderMode != RenderMode.WorldSpace && !Mathf.Approximately (scale, 0) && 0 < delta.sqrMagnitude)
Vector3 delta = (newPos - _oldPos);
_oldPos = newPos;
if (!Mathf.Approximately (scale, 0) && 0 < delta.sqrMagnitude)
{
delta *= (1 - 1 / scale);
if(isLocalScaling)
{
var s = rootCanvas.transform.localScale * scale;
delta.x *= 1f - 1f / s.x;
delta.y *= 1f - 1f / s.y;
delta.z *= 1f - 1f / s.z;
}
else
{
delta = delta * (1 - 1 / scale);
}
int count = m_ParticleSystem.particleCount;
if (s_Particles.Length < count)
{
@@ -369,6 +478,10 @@ namespace Coffee.UIExtensions
Profiler.BeginSample ("Set mesh and texture to CanvasRenderer");
canvasRenderer.SetMesh (_mesh);
canvasRenderer.SetTexture (mainTexture);
// Copy the value from MaterialPropertyBlock to CanvasRenderer (#41)
UpdateAnimatableMaterialProperties ();
Profiler.EndSample ();
}
}
@@ -427,5 +540,43 @@ namespace Coffee.UIExtensions
_parent._children.Add (this);
}
}
/// <summary>
/// Copy the value from MaterialPropertyBlock to CanvasRenderer (#41)
/// </summary>
void UpdateAnimatableMaterialProperties ()
{
#if UNITY_EDITOR
if (!Application.isPlaying)
return;
#endif
if (0 == m_AnimatableProperties.Length)
return;
_renderer.GetPropertyBlock (s_Mpb);
for (int i = 0; i < canvasRenderer.materialCount; i++)
{
var mat = canvasRenderer.GetMaterial (i);
foreach (var ap in m_AnimatableProperties)
{
switch (ap.type)
{
case ShaderPropertyType.Color:
mat.SetColor (ap.id, s_Mpb.GetColor (ap.id));
break;
case ShaderPropertyType.Vector:
mat.SetVector (ap.id, s_Mpb.GetVector (ap.id));
break;
case ShaderPropertyType.Float:
case ShaderPropertyType.Range:
mat.SetFloat (ap.id, s_Mpb.GetFloat (ap.id));
break;
case ShaderPropertyType.Texture:
mat.SetTexture (ap.id, s_Mpb.GetTexture (ap.id));
break;
}
}
}
}
}
}

View File

@@ -77,7 +77,7 @@
v2f OUT;
OUT.worldPosition = IN.vertex;
OUT.vertex = UnityObjectToClipPos(IN.vertex);
OUT.texcoord = IN.texcoord;
OUT.texcoord = TRANSFORM_TEX(IN.texcoord, _MainTex);
#ifdef UNITY_HALF_TEXEL_OFFSET
OUT.vertex.xy += (_ScreenParams.zw-1.0)*float2(-1,1);
#endif

Binary file not shown.

View File

@@ -2,7 +2,7 @@
"name": "com.coffee.ui-particle",
"displayName": "UI Particle",
"description": "This plugin provide a component to render particle effect for uGUI.\nThe particle rendering is maskable and sortable, without Camera, RenderTexture or Canvas.",
"version": "2.1.1",
"version": "2.3.0",
"unity": "2018.2",
"license": "MIT",
"repository": {