Selaa lähdekoodia

[unity] Support for prefab preview thumbnails. See #1931. Fixes prefab instance always listing MeshFilter as changed (via parameter `Advanced - Fix Prefab Override MeshFilter`, see changelog). Closes #1273.

Harald Csaszar 4 vuotta sitten
vanhempi
commit
c2cbdc57b7

+ 6 - 4
CHANGELOG.md

@@ -106,12 +106,12 @@
   * **Corrected all `Outline` shaders outline thickness** when `Advanced - Sample 8 Neighbourhood` is disabled (thus using `4 Neighbourhood`). Previously weighting was incorrectly thick (4x as thick) compared to 8 neighbourhood, now it is more consistent. This might require adjustment of all your outline materials where `Sample 8 Neighbourhood` is disabled to restore the previous outline thickness, by adjusting the `Outline Threshold` parameter through adding a `/4` to make the threshold 4 times smaller.
   * Reverted changes: `BoneFollower` property `followLocalScale` has intermediately been renamed to `followScale` but was renamed back to `followLocalScale`. Serialized values (scenes and prefabs) will automatically be upgraded, only code accessing `followScale` needs to be adapted.
   * Fixed Timeline not pausing (and resuming) clip playback on Director pause, this is now the default behaviour. If you require the old behaviour (e.g. to continue playing an idle animation during Director pause), there is now an additional parameter `Don't Pause with Director` provided that can be enabled for each Timeline clip.
-  * Fixed Timeline `Spine AnimationState Clips` ignoring empty space on the Timeline after a clip's end. Timeline clips now also offer `Don't End with Clip` and `Clip End Mix Out Duration` parameters if you prefer the old behaviour of previous versions. By default when empty space follows the clip on the timeline, the empty animation is set on the track with a MixDuration of `Clip End Mix Out Duration`. Set `Don't End with Clip` to true to continue playing the clip's animation instead and mimic the old 3.8 behaviour. If you prefer pausing the animation instead of mixing out to the empty animation, set `Clip End Mix Out Duration` to a value less than 0, then the animation is paused instead.
+  * Fixed Timeline `Spine AnimationState Clips` ignoring empty space on the Timeline after a clip's end. Timeline clips now also offer `Don't End with Clip` and `Clip End Mix Out Duration` parameters if you prefer the old behaviour of previous versions. By default when empty space follows the clip on the timeline, the empty animation is set on the track with a MixDuration of `Clip End Mix Out Duration`. Set `Don't End with Clip` to `true` to continue playing the clip's animation instead and mimic the old 3.8 behaviour. If you prefer pausing the animation instead of mixing out to the empty animation, set `Clip End Mix Out Duration` to a value less than 0, then the animation is paused instead.
   
 * **Additions**
   * Additional **Fix Draw Order** parameter at SkeletonRenderer, defaults to `disabled` (previous behaviour).
     Applies only when 3+ submeshes are used (2+ materials with alternating order, e.g. "A B A").
-		If true, MaterialPropertyBlocks are assigned at each material to prevent aggressive batching of submeshes
+		If `true`, MaterialPropertyBlocks are assigned at each material to prevent aggressive batching of submeshes
 		by e.g. the LWRP renderer, leading to incorrect draw order (e.g. "A1 B A2" changed to "A1A2 B").
 		You can leave this parameter disabled when everything is drawn correctly to save the additional performance cost.
   * **Additional Timeline features.** SpineAnimationStateClip now provides a `Speed Multiplier`, a start time offset parameter `Clip In`, support for blending successive animations by overlapping tracks. An additional `Use Blend Duration` parameter *(defaults to true)* allows for automatic synchronisation of MixDuration with the current overlap blend duration. An additional Spine preferences parameter `Use Blend Duration` has been added which can be disabled to default to the previous behaviour before this update.
@@ -153,7 +153,9 @@
   * `SkeletonRagdoll` and `SkeletonRagdoll2D` now support bone scale at any bone in the skeleton hierarchy. This includes negative scale and root bone scale.
   * `Attachment.GetRemappedClone(Sprite)` method now provides an additional optional parameter `useOriginalRegionScale`. When set to `true`, the replaced attachment's scale is used instead of the Sprite's `Pixel per Unity` setting, allowing for more consistent scaling. *Note:* When remapping Sprites, be sure to set the Sprite's `Mesh Type` to `Full Rect` and not `Tight`, otherwise the scale will be wrong.
   * `SkeletonGraphic` now **supports all Slot blend modes** when `Advanced - Multiple Canvas Renderers` is enabled in the Inspector. The `SkeletonGraphic` Inspector now provides a `Blend Mode Materials` section where you can assign `SkeletonGraphic` materials for each blend mode, or use the new default materials. New `SkeletonGraphic` shaders and materials have been added for each blend mode. The `BlendModes.unity` example scene has been extended to demonstrate this new feature. For detailed information see the [`SkeletonGraphic documentation page`](http://esotericsoftware.com/spine-unity#Parameters).
-  * Timeline clips now also offer `Don't End with Clip` and `Clip End Mix Out Duration` parameters. By default when empty space follows the clip on the timeline, the empty animation is set on the track with a MixDuration of `Clip End Mix Out Duration`. Set `Don't End with Clip` to true to continue playing the clip's animation instead and mimic the old 3.8 behaviour. If you prefer pausing the animation instead of mixing out to the empty animation, set `Clip End Mix Out Duration` to a value less than 0, then the animation is paused instead.
+  * Timeline clips now also offer `Don't End with Clip` and `Clip End Mix Out Duration` parameters. By default when empty space follows the clip on the timeline, the empty animation is set on the track with a MixDuration of `Clip End Mix Out Duration`. Set `Don't End with Clip` to `true` to continue playing the clip's animation instead and mimic the old 3.8 behaviour. If you prefer pausing the animation instead of mixing out to the empty animation, set `Clip End Mix Out Duration` to a value less than 0, then the animation is paused instead.
+  * Prefabs containing `SkeletonRenderer`, `SkeletonAnimation` and `SkeletonMecanim` now provide a proper Editor preview, including the preview thumbnail.
+  * `SkeletonRenderer` (and subclasses`SkeletonAnimation` and `SkeletonMecanim`) now provide a property `Advanced - Fix Prefab Override MeshFilter`, which when enabled fixes the prefab always being marked as changed. It sets the MeshFilter's hide flags to `DontSaveInEditor`. Unfortunately this comes at the cost of references to the `MeshFilter` by other components being lost, therefore this parameter defaults to `false` to keep the safe existing behaviour.
 
 * **Changes of default values**
 
@@ -1023,7 +1025,7 @@ This will automatically:
      * We will continue to bundle the unitypackage with the empty .cs files of deprecated classes until Spine 3.7 to ensure the upgrade process does not break.
    * The [SpineAttachment(slotField:)] optional parameter found property value now acts as a Find(slotName) argument rather than Contains(slotName).
    * `SkeletonAnimator` now uses a `SkeletonAnimator.MecanimTranslator` class to translate an Animator's Mecanim State Machine into skeleton poses. This makes code reuse possible for a Mecanim version of SkeletonGraphic.
-   * `SkeletonAnimator` `autoreset` and the `mixModes` array are now a part of SkeletonAnimator's MecanimTranslator `.Translator`. `autoReset` is set to true by default. Old prefabs and scene objects with Skeleton Animator may no longer have correct values set.
+   * `SkeletonAnimator` `autoreset` and the `mixModes` array are now a part of SkeletonAnimator's MecanimTranslator `.Translator`. `autoReset` is set to `true` by default. Old prefabs and scene objects with Skeleton Animator may no longer have correct values set.
    * Warnings and conditionals checking for specific Unity 5.2-and-below incompatibility have been removed.
 
 ## XNA/MonoGame

+ 15 - 2
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Components/SkeletonRendererInspector.cs

@@ -41,6 +41,10 @@
 #define BUILT_IN_SPRITE_MASK_COMPONENT
 #endif
 
+#if UNITY_2020_2_OR_NEWER
+#define HAS_ON_POSTPROCESS_PREFAB
+#endif
+
 using UnityEditor;
 using System.Collections.Generic;
 using UnityEngine;
@@ -60,7 +64,8 @@ namespace Spine.Unity.Editor {
 
 		protected SerializedProperty skeletonDataAsset, initialSkinName;
 		protected SerializedProperty initialFlipX, initialFlipY;
-		protected SerializedProperty updateWhenInvisible, singleSubmesh, separatorSlotNames, clearStateOnDisable, immutableTriangles, fixDrawOrder;
+		protected SerializedProperty updateWhenInvisible, singleSubmesh, separatorSlotNames, clearStateOnDisable,
+			immutableTriangles, fixDrawOrder, fixPrefabOverrideViaMeshFilter;
 		protected SerializedProperty normals, tangents, zSpacing, pmaVertexColors, tintBlack; // MeshGenerator settings
 		protected SerializedProperty maskInteraction;
 		protected SerializedProperty maskMaterialsNone, maskMaterialsInside, maskMaterialsOutside;
@@ -75,7 +80,8 @@ namespace Spine.Unity.Editor {
 		protected bool deleteOutsideMaskMaterialsQueued = false;
 
 		protected GUIContent SkeletonDataAssetLabel, SkeletonUtilityButtonContent;
-		protected GUIContent PMAVertexColorsLabel, ClearStateOnDisableLabel, ZSpacingLabel, ImmubleTrianglesLabel, TintBlackLabel, UpdateWhenInvisibleLabel, SingleSubmeshLabel, FixDrawOrderLabel;
+		protected GUIContent PMAVertexColorsLabel, ClearStateOnDisableLabel, ZSpacingLabel, ImmubleTrianglesLabel,
+			TintBlackLabel, UpdateWhenInvisibleLabel, SingleSubmeshLabel, FixDrawOrderLabel, FixPrefabOverrideViaMeshFilterLabel;
 		protected GUIContent NormalsLabel, TangentsLabel, MaskInteractionLabel;
 		protected GUIContent MaskMaterialsHeadingLabel, MaskMaterialsNoneLabel, MaskMaterialsInsideLabel, MaskMaterialsOutsideLabel;
 		protected GUIContent SetMaterialButtonLabel, ClearMaterialButtonLabel, DeleteMaterialButtonLabel;
@@ -123,6 +129,7 @@ namespace Spine.Unity.Editor {
 			SingleSubmeshLabel = new GUIContent("Use Single Submesh", "Simplifies submesh generation by assuming you are only using one Material and need only one submesh. This is will disable multiple materials, render separation, and custom slot materials.");
 			UpdateWhenInvisibleLabel = new GUIContent("Update When Invisible", "Update mode used when the MeshRenderer becomes invisible. Update mode is automatically reset to UpdateMode.FullUpdate when the mesh becomes visible again.");
 			FixDrawOrderLabel = new GUIContent("Fix Draw Order", "Applies only when 3+ submeshes are used (2+ materials with alternating order, e.g. \"A B A\"). If true, GPU instancing will be disabled at all materials and MaterialPropertyBlocks are assigned at each material to prevent aggressive batching of submeshes by e.g. the LWRP renderer, leading to incorrect draw order (e.g. \"A1 B A2\" changed to \"A1A2 B\"). You can disable this parameter when everything is drawn correctly to save the additional performance cost. Note: the GPU instancing setting will remain disabled at affected material assets after exiting play mode, you have to enable it manually if you accidentally enabled this parameter.");
+			FixPrefabOverrideViaMeshFilterLabel = new GUIContent("Fix Prefab Overr. MeshFilter", "Fixes the prefab always being marked as changed (sets the MeshFilter's hide flags to DontSaveInEditor), but at the cost of references to the MeshFilter by other components being lost.");
 			MaskInteractionLabel = new GUIContent("Mask Interaction", "SkeletonRenderer's interaction with a Sprite Mask.");
 			MaskMaterialsHeadingLabel = new GUIContent("Mask Interaction Materials", "Materials used for different interaction with sprite masks.");
 			MaskMaterialsNoneLabel = new GUIContent("Normal Materials", "Normal materials used when Mask Interaction is set to None.");
@@ -146,6 +153,7 @@ namespace Spine.Unity.Editor {
 			updateWhenInvisible = so.FindProperty("updateWhenInvisible");
 			singleSubmesh = so.FindProperty("singleSubmesh");
 			fixDrawOrder = so.FindProperty("fixDrawOrder");
+			fixPrefabOverrideViaMeshFilter = so.FindProperty("fixPrefabOverrideViaMeshFilter");
 			maskInteraction = so.FindProperty("maskInteraction");
 			maskMaterialsNone = so.FindProperty("maskMaterials.materialsMaskDisabled");
 			maskMaterialsInside = so.FindProperty("maskMaterials.materialsInsideMask");
@@ -340,6 +348,11 @@ namespace Spine.Unity.Editor {
 							if (immutableTriangles != null) EditorGUILayout.PropertyField(immutableTriangles, ImmubleTrianglesLabel);
 							EditorGUILayout.PropertyField(clearStateOnDisable, ClearStateOnDisableLabel);
 							EditorGUILayout.Space();
+
+						#if HAS_ON_POSTPROCESS_PREFAB
+							if (fixPrefabOverrideViaMeshFilter != null) EditorGUILayout.PropertyField(fixPrefabOverrideViaMeshFilter, FixPrefabOverrideViaMeshFilterLabel);
+							EditorGUILayout.Space();
+						#endif
 						}
 
 						SeparatorsField(separatorSlotNames);

+ 25 - 1
spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/SpineEditorUtilities.cs

@@ -50,6 +50,10 @@
 #define BUILT_IN_SPRITE_MASK_COMPONENT
 #endif
 
+#if UNITY_2020_2_OR_NEWER
+#define HAS_ON_POSTPROCESS_PREFAB
+#endif
+
 using UnityEngine;
 using UnityEditor;
 using System.Collections.Generic;
@@ -95,7 +99,27 @@ namespace Spine.Unity.Editor {
 			texturesWithoutMetaFile.Clear();
 		}
 
-#region Initialization
+#if HAS_ON_POSTPROCESS_PREFAB
+		// Post process prefabs for setting the MeshFilter to not cause constant Prefab override changes.
+		void OnPostprocessPrefab (GameObject g) {
+			var skeletonRenderers = g.GetComponentsInChildren<SkeletonRenderer>(true);
+			foreach (SkeletonRenderer renderer in skeletonRenderers) {
+				var meshFilter = renderer.GetComponent<MeshFilter>();
+				if (meshFilter == null)
+					meshFilter = renderer.gameObject.AddComponent<MeshFilter>();
+
+				renderer.EditorUpdateMeshFilterHideFlags();
+				renderer.Initialize(true, true);
+				renderer.LateUpdateMesh();
+				var mesh = meshFilter.sharedMesh;
+				string meshName = string.Format("Skeleton Prefab Mesh \"{0}\"", renderer.name);
+				mesh.name = meshName;
+				context.AddObjectToAsset(meshName, mesh);
+			}
+		}
+#endif
+
+		#region Initialization
 		static SpineEditorUtilities () {
 			EditorApplication.delayCall += Initialize; // delayed so that AssetDatabase is ready.
 		}

+ 29 - 5
spine-unity/Assets/Spine/Runtime/spine-unity/Components/SkeletonRenderer.cs

@@ -56,7 +56,7 @@ namespace Spine.Unity {
 	#else
 	[ExecuteInEditMode]
 	#endif
-	[RequireComponent(typeof(MeshFilter), typeof(MeshRenderer)), DisallowMultipleComponent]
+	[RequireComponent(typeof(MeshRenderer)), DisallowMultipleComponent]
 	[HelpURL("http://esotericsoftware.com/spine-unity#SkeletonRenderer-Component")]
 	public class SkeletonRenderer : MonoBehaviour, ISkeletonComponent, IHasSkeletonDataAsset {
 		public SkeletonDataAsset skeletonDataAsset;
@@ -73,6 +73,21 @@ namespace Spine.Unity {
 			set { editorSkipSkinSync = value; }
 		}
 		protected bool editorSkipSkinSync = false;
+		/// <summary>Sets the MeshFilter's hide flags to DontSaveInEditor which fixes the prefab
+		/// always being marked as changed, but at the cost of references to the MeshFilter by other
+		/// components being lost.</summary>
+		public bool fixPrefabOverrideViaMeshFilter = false;
+		public void EditorUpdateMeshFilterHideFlags () {
+			if (!meshFilter) {
+				meshFilter = GetComponent<MeshFilter>();
+				if (meshFilter == null)
+					meshFilter = gameObject.AddComponent<MeshFilter>();
+			}
+			if (fixPrefabOverrideViaMeshFilter)
+				meshFilter.hideFlags = HideFlags.DontSaveInEditor;
+			else
+				meshFilter.hideFlags = HideFlags.None;
+		}
 		#endif
 		/// <summary>Flip X and Y to use when the Skeleton is initialized.</summary>
 		public bool initialFlipX, initialFlipY;
@@ -341,6 +356,9 @@ namespace Spine.Unity {
 			valid = true;
 
 			meshFilter = GetComponent<MeshFilter>();
+			if (meshFilter == null)
+				meshFilter = gameObject.AddComponent<MeshFilter>();
+
 			meshRenderer = GetComponent<MeshRenderer>();
 			rendererBuffers.Initialize();
 
@@ -380,18 +398,23 @@ namespace Spine.Unity {
 		public virtual void LateUpdate () {
 			if (!valid) return;
 
-			#if UNITY_EDITOR && NEW_PREFAB_SYSTEM
+		#if UNITY_EDITOR && NEW_PREFAB_SYSTEM
 			// Don't store mesh or material at the prefab, otherwise it will permanently reload
 			var prefabType = UnityEditor.PrefabUtility.GetPrefabAssetType(this);
 			if (UnityEditor.PrefabUtility.IsPartOfPrefabAsset(this) &&
 				(prefabType == UnityEditor.PrefabAssetType.Regular || prefabType == UnityEditor.PrefabAssetType.Variant)) {
 				return;
 			}
-			#endif
+			EditorUpdateMeshFilterHideFlags();
+		#endif
 
 			if (updateMode != UpdateMode.FullUpdate) return;
 
-			#if SPINE_OPTIONAL_RENDEROVERRIDE
+			LateUpdateMesh();
+		}
+
+		public virtual void LateUpdateMesh () {
+#if SPINE_OPTIONAL_RENDEROVERRIDE
 			bool doMeshOverride = generateMeshOverride != null;
 			if ((!meshRenderer.enabled)	&& !doMeshOverride) return;
 			#else
@@ -488,7 +511,8 @@ namespace Spine.Unity {
 			meshGenerator.FillLateVertexData(currentMesh);
 
 			// STEP 4. The UnityEngine.Mesh is ready. Set it as the MeshFilter's mesh. Store the instructions used for that mesh. ===========
-			meshFilter.sharedMesh = currentMesh;
+			if (meshFilter)
+				meshFilter.sharedMesh = currentMesh;
 			currentSmartMesh.instructionUsed.Set(currentInstructions);
 
 			#if BUILT_IN_SPRITE_MASK_COMPONENT