[unity] SkeletonBakingWindow and various editor fixes.

This commit is contained in:
pharan 2017-05-20 10:13:45 +08:00
parent 7570c69aa2
commit 439c8e8e22
9 changed files with 165 additions and 103 deletions

View File

@ -82,6 +82,7 @@
* **[SpineAttribute(includeNone:false)]** SpineAttributes now have an `includeNone` optional parameter to specify if you want to include or exclude a none ("") value option in the dropdown menu. Default is `includeNone:true`.
* **[SpineAttachment(skinField:"mySkin")]** The SpineAttachment attribute now has a skinField optional parameter to limit the dropdown items to attachments in a specific skin instead of the just default skin or all the skins in SkeletonData.
* **SkeletonDebugWindow**. Debugging tools have been moved from the SkeletonRenderer and SkeletonUtility component inspectors into its own utility window. You can access "Skeleton Debug" under the `Advanced...` foldout in the SkeletonRenderer inspector, or in SkeletonRenderer's right-click/context menu.
* **Skeleton Baking Window** The old Skeleton Baking feature is also now accessible through the SkeletonDataAsset's right-click/context menu.
* **AttachmentTools source material**. `AttachmentTools` methods can now accept a `sourceMaterial` argument to copy material properties from.
* **AttachmentTools Skin Extensions**. Using AttachmentTools, you can now add entries by slot name by also providing a skeleton argument. Also `Append(Skin)`, `RemoveAttachment` and `Clear` have been added.
* **BoneFollower and SkeletonUtilityBone Add RigidBody Button**. The BoneFollower and SkeletonUtilityBone component inspectors will now offer to add a `Rigidbody` or `Rigidbody2D` if it detects a collider of the appropriate type. Having a rigidbody on a moving transform with a collider fits better with the Unity physics systems and prevents excess calculations. It will not detect colliders on child objects so you have to add Rigidbody components manually accordingly.

View File

@ -287,73 +287,6 @@ namespace Spine.Unity.Editor {
}
}
#endif
#if SPINE_BAKING
bool pre = isBakingExpanded;
isBakingExpanded = EditorGUILayout.Foldout(isBakingExpanded, new GUIContent("Baking", Icons.unityIcon));
if (pre != isBakingExpanded)
EditorPrefs.SetBool(ShowBakingPrefsKey, isBakingExpanded);
if (isBakingExpanded) {
EditorGUI.indentLevel++;
const string BakingWarningMessage =
// "WARNING!" +
// "\nBaking is NOT the same as SkeletonAnimator!" +
// "\n\n" +
"The main use of Baking is to export Spine projects to be used without the Spine Runtime (ie: for sale on the Asset Store, or background objects that are animated only with a wind noise generator)" +
"\n\nBaking does not support the following:" +
"\n\tDisabled transform inheritance" +
"\n\tShear" +
"\n\tColor Keys" +
"\n\tDraw Order Keys" +
"\n\tAll Constraint types" +
"\n\nCurves are sampled at 60fps and are not realtime." +
"\nPlease read SkeletonBaker.cs comments for full details.";
EditorGUILayout.HelpBox(BakingWarningMessage, MessageType.Info, true);
EditorGUI.indentLevel++;
bakeAnimations = EditorGUILayout.Toggle("Bake Animations", bakeAnimations);
using (new EditorGUI.DisabledGroupScope(!bakeAnimations)) {
EditorGUI.indentLevel++;
bakeIK = EditorGUILayout.Toggle("Bake IK", bakeIK);
bakeEventOptions = (SendMessageOptions)EditorGUILayout.EnumPopup("Event Options", bakeEventOptions);
EditorGUI.indentLevel--;
}
// Bake Skin buttons.
using (new GUILayout.HorizontalScope()) {
if (GUILayout.Button(new GUIContent("Bake All Skins", Icons.unityIcon), GUILayout.Height(32), GUILayout.Width(150)))
SkeletonBaker.BakeToPrefab(m_skeletonDataAsset, m_skeletonData.Skins, "", bakeAnimations, bakeIK, bakeEventOptions);
if (m_skeletonAnimation != null && m_skeletonAnimation.skeleton != null) {
Skin bakeSkin = m_skeletonAnimation.skeleton.Skin;
string skinName = "<No Skin>";
if (bakeSkin == null) {
skinName = "Default";
bakeSkin = m_skeletonData.Skins.Items[0];
} else
skinName = m_skeletonAnimation.skeleton.Skin.Name;
using (new GUILayout.VerticalScope()) {
if (GUILayout.Button(new GUIContent("Bake \"" + skinName + "\"", Icons.unityIcon), GUILayout.Height(32), GUILayout.Width(250)))
SkeletonBaker.BakeToPrefab(m_skeletonDataAsset, new ExposedList<Skin>(new [] { bakeSkin }), "", bakeAnimations, bakeIK, bakeEventOptions);
using (new GUILayout.HorizontalScope()) {
GUILayout.Label(new GUIContent("Skins", Icons.skinsRoot), GUILayout.Width(50));
if (GUILayout.Button(skinName, EditorStyles.popup, GUILayout.Width(196))) {
DrawSkinDropdown();
}
}
}
}
}
EditorGUI.indentLevel--;
EditorGUI.indentLevel--;
}
#endif
}
void DoReimport () {

View File

@ -42,36 +42,35 @@ using System.Reflection;
using System.IO;
using Spine;
/// <summary>
/// [SUPPORTS]
/// Linear, Constant, and Bezier Curves*
/// Inverse Kinematics*
/// Inherit Rotation
/// Translate Timeline
/// Rotate Timeline
/// Scale Timeline**
/// Event Timeline***
/// Attachment Timeline
///
/// RegionAttachment
/// MeshAttachment
/// SkinnedMeshAttachment
///
/// [LIMITATIONS]
/// *Inverse Kinematics & Bezier Curves are baked into the animation at 60fps and are not realtime. Use bakeIncrement constant to adjust key density if desired.
/// **Non-uniform Scale Keys (ie: if ScaleX and ScaleY are not equal to eachother, it will not be accurate to Spine source)
/// ***Events may only fire 1 type of data per event in Unity safely so priority to String data if present in Spine key, otherwise a Float is sent whether the Spine key was Int or Float with priority given to Int.
///
/// [DOES NOT SUPPORT]
/// FlipX or FlipY (Maybe one day)
/// FFD (Unity does not provide access to BlendShapes with code)
/// Color Keys (Maybe one day when Unity supports full FBX standard and provides access with code)
/// InheritScale (Never. Unity and Spine do scaling very differently)
/// Draw Order Keyframes
/// </summary>
///
namespace Spine.Unity.Editor {
/// <summary>
/// [SUPPORTS]
/// Linear, Constant, and Bezier Curves*
/// Inverse Kinematics*
/// Inherit Rotation
/// Translate Timeline
/// Rotate Timeline
/// Scale Timeline**
/// Event Timeline***
/// Attachment Timeline
///
/// RegionAttachment
/// MeshAttachment
/// SkinnedMeshAttachment
///
/// [LIMITATIONS]
/// *Inverse Kinematics & Bezier Curves are baked into the animation at 60fps and are not realtime. Use bakeIncrement constant to adjust key density if desired.
/// **Non-uniform Scale Keys (ie: if ScaleX and ScaleY are not equal to eachother, it will not be accurate to Spine source)
/// ***Events may only fire 1 type of data per event in Unity safely so priority to String data if present in Spine key, otherwise a Float is sent whether the Spine key was Int or Float with priority given to Int.
///
/// [DOES NOT SUPPORT]
/// FlipX or FlipY (Maybe one day)
/// FFD (Unity does not provide access to BlendShapes with code)
/// Color Keys (Maybe one day when Unity supports full FBX standard and provides access with code)
/// InheritScale (Never. Unity and Spine do scaling very differently)
/// Draw Order Keyframes
/// </summary>
public static class SkeletonBaker {
#region SkeletonAnimator's Mecanim Clips

View File

@ -0,0 +1,121 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace Spine.Unity.Editor {
using Editor = UnityEditor.Editor;
using Icons = SpineEditorUtilities.Icons;
public class SkeletonBakingWindow : EditorWindow {
const bool IsUtilityWindow = true;
[MenuItem("CONTEXT/SkeletonDataAsset/Skeleton Baking", false, 5000)]
public static void Init (MenuCommand command) {
var window = EditorWindow.GetWindow<SkeletonBakingWindow>(IsUtilityWindow);
window.minSize = new Vector2(330f, 530f);
window.maxSize = new Vector2(600f, 1000f);
window.titleContent = new GUIContent("Skeleton Baking", Icons.spine);
window.skeletonDataAsset = command.context as SkeletonDataAsset;
window.Show();
}
public SkeletonDataAsset skeletonDataAsset;
[SpineSkin(dataField:"skeletonDataAsset")]
public string skinToBake = "default";
// Settings
bool bakeAnimations = false;
bool bakeIK = true;
SendMessageOptions bakeEventOptions;
SerializedObject so;
Skin bakeSkin;
void DataAssetChanged () {
bakeSkin = null;
}
void OnGUI () {
so = so ?? new SerializedObject(this);
EditorGUIUtility.wideMode = true;
EditorGUILayout.LabelField("Spine Skeleton Prefab Baking", EditorStyles.boldLabel);
const string BakingWarningMessage = "\nThe main use of Baking is to export Spine projects to be used without the Spine Runtime (ie: for sale on the Asset Store, or background objects that are animated only with a wind noise generator)" +
"\n\nBaking does not support the following:" +
"\n\tDisabled transform inheritance" +
"\n\tShear" +
"\n\tColor Keys" +
"\n\tDraw Order Keys" +
"\n\tAll Constraint types" +
"\n\nCurves are sampled at 60fps and are not realtime." +
"\nPlease read SkeletonBaker.cs comments for full details.\n";
EditorGUILayout.HelpBox(BakingWarningMessage, MessageType.Info, true);
EditorGUI.BeginChangeCheck();
var skeletonDataAssetProperty = so.FindProperty("skeletonDataAsset");
EditorGUILayout.PropertyField(skeletonDataAssetProperty, SpineInspectorUtility.TempContent("SkeletonDataAsset", Icons.spine));
if (EditorGUI.EndChangeCheck()) {
so.ApplyModifiedProperties();
DataAssetChanged();
}
EditorGUILayout.Space();
if (skeletonDataAsset == null) return;
var skeletonData = skeletonDataAsset.GetSkeletonData(false);
if (skeletonData == null) return;
using (new SpineInspectorUtility.BoxScope(false)) {
EditorGUILayout.LabelField(skeletonDataAsset.name, EditorStyles.boldLabel);
using (new SpineInspectorUtility.IndentScope()) {
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Bones: " + skeletonData.Bones.Count, Icons.bone));
int totalAttachments = 0;
foreach (var s in skeletonData.Skins) totalAttachments += s.Attachments.Count;
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Total Attachments: " + totalAttachments, Icons.genericAttachment));
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Current skin attachments: " + (bakeSkin == null ? 0 : bakeSkin.Attachments.Count), Icons.skinPlaceholder));
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent("Animations: " + skeletonData.Animations.Count, Icons.animation));
}
}
using (new SpineInspectorUtility.BoxScope(false)) {
EditorGUILayout.LabelField("Settings", EditorStyles.boldLabel);
using (new SpineInspectorUtility.IndentScope()) {
bakeAnimations = EditorGUILayout.Toggle(SpineInspectorUtility.TempContent("Bake Animations", Icons.animationRoot), bakeAnimations);
bakeIK = EditorGUILayout.Toggle(SpineInspectorUtility.TempContent("Bake IK", Icons.constraintIK), bakeIK);
bakeEventOptions = (SendMessageOptions)EditorGUILayout.EnumPopup(SpineInspectorUtility.TempContent("Event Options", Icons.userEvent), bakeEventOptions);
}
}
EditorGUILayout.Space();
EditorGUI.BeginChangeCheck();
EditorGUILayout.PropertyField(so.FindProperty("skinToBake"));
if (EditorGUI.EndChangeCheck()) {
so.ApplyModifiedProperties();
Repaint();
}
if (!string.IsNullOrEmpty(skinToBake) && UnityEngine.Event.current.type == EventType.Repaint)
bakeSkin = skeletonData.FindSkin(skinToBake) ?? skeletonData.DefaultSkin;
var prefabIcon = EditorGUIUtility.FindTexture("PrefabModel Icon");
if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent(string.Format("Bake Skin ({0})", (bakeSkin == null ? "default" : bakeSkin.Name)), prefabIcon))) {
SkeletonBaker.BakeToPrefab(skeletonDataAsset, new ExposedList<Skin>(new [] { bakeSkin }), "", bakeAnimations, bakeIK, bakeEventOptions);
}
if (skeletonData.Skins.Count > 1) {
if (SpineInspectorUtility.LargeCenteredButton(SpineInspectorUtility.TempContent(string.Format("Bake All ({0} skins)", skeletonData.Skins.Count), prefabIcon))) {
SkeletonBaker.BakeToPrefab(skeletonDataAsset, skeletonData.Skins, "", bakeAnimations, bakeIK, bakeEventOptions);
}
}
}
}
}

View File

@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 868b0caae5b3e65408ece1ab400c4a99
timeCreated: 1495203966
licenseType: Free
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -305,7 +305,7 @@ namespace Spine.Unity.Editor {
prefix = skinPrefix;
for (int i = 0; i < data.Slots.Count; i++) {
if (slotMatch.Length > 0 && !(data.Slots.Items[i].Name.ToLower().Contains(slotMatch)))
if (slotMatch.Length > 0 && !(data.Slots.Items[i].Name.Equals(slotMatch, StringComparison.OrdinalIgnoreCase)))
continue;
attachmentNames.Clear();

View File

@ -200,7 +200,7 @@ namespace Spine.Unity.Editor {
string buttonLabel = box.IsWeighted() ? box.Name + " (!)" : box.Name;
if (GUILayout.Button(buttonLabel, GUILayout.Width(200))) {
utilityBone.bone.Skeleton.UpdateWorldTransform();
var bbTransform = utilityBone.transform.FindChild("[BoundingBox]" + box.Name);
var bbTransform = utilityBone.transform.Find("[BoundingBox]" + box.Name); // Use FindChild in older versions of Unity.
if (bbTransform != null) {
var originalCollider = bbTransform.GetComponent<PolygonCollider2D>();
if (originalCollider != null)

View File

@ -166,7 +166,6 @@ namespace Spine.Unity {
bone.y = Mathf.Lerp(bone.y, pos.y, overrideAlpha);
}
// MITCH
if (rotation) {
float angle = Mathf.LerpAngle(bone.Rotation, Quaternion.LookRotation(Vector3.forward, parentReference.InverseTransformDirection(cachedTransform.up)).eulerAngles.z, overrideAlpha);
bone.Rotation = angle;

View File

@ -144,10 +144,7 @@ namespace Spine.Unity {
public static Spine.Attachment GetAttachment (string attachmentPath, Spine.SkeletonData skeletonData) {
var hierarchy = SpineAttachment.GetHierarchy(attachmentPath);
if (hierarchy.name == "")
return null;
return skeletonData.FindSkin(hierarchy.skin).GetAttachment(skeletonData.FindSlotIndex(hierarchy.slot), hierarchy.name);
return string.IsNullOrEmpty(hierarchy.name) ? null : skeletonData.FindSkin(hierarchy.skin).GetAttachment(skeletonData.FindSlotIndex(hierarchy.slot), hierarchy.name);
}
public static Spine.Attachment GetAttachment (string attachmentPath, SkeletonDataAsset skeletonDataAsset) {