mirror of
https://gitgud.io/AbstractConcept/rimworld-animation-studio.git
synced 2024-08-15 00:43:27 +00:00
Initial commit
This commit is contained in:
commit
3c7cc0c973
8391 changed files with 704313 additions and 0 deletions
|
@ -0,0 +1,332 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
[Serializable]
|
||||
internal struct Pose
|
||||
{
|
||||
public Vector3 position;
|
||||
public Quaternion rotation;
|
||||
public Matrix4x4 matrix
|
||||
{
|
||||
get { return Matrix4x4.TRS(position, rotation, Vector3.one); }
|
||||
}
|
||||
|
||||
public static Pose Create(Vector3 p, Quaternion r)
|
||||
{
|
||||
var pose = new Pose()
|
||||
{
|
||||
position = p,
|
||||
rotation = r
|
||||
};
|
||||
|
||||
return pose;
|
||||
}
|
||||
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
return other is Pose && this == (Pose)other;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return position.GetHashCode() ^ rotation.GetHashCode();
|
||||
}
|
||||
|
||||
public static bool operator==(Pose p1, Pose p2)
|
||||
{
|
||||
return p1.position == p2.position && p1.rotation == p2.rotation;
|
||||
}
|
||||
|
||||
public static bool operator!=(Pose p1, Pose p2)
|
||||
{
|
||||
return !(p1 == p2);
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal struct BonePose
|
||||
{
|
||||
public Pose pose;
|
||||
public float length;
|
||||
public static BonePose Create(Pose p, float l)
|
||||
{
|
||||
var pose = new BonePose()
|
||||
{
|
||||
pose = p,
|
||||
length = l
|
||||
};
|
||||
|
||||
return pose;
|
||||
}
|
||||
|
||||
public override bool Equals(object other)
|
||||
{
|
||||
return other is BonePose && this == (BonePose)other;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return pose.GetHashCode() ^ length.GetHashCode();
|
||||
}
|
||||
|
||||
public static bool operator==(BonePose p1, BonePose p2)
|
||||
{
|
||||
return p1.pose == p2.pose && p1.length == p2.length;
|
||||
}
|
||||
|
||||
public static bool operator!=(BonePose p1, BonePose p2)
|
||||
{
|
||||
return !(p1 == p2);
|
||||
}
|
||||
}
|
||||
|
||||
internal class BoneCache : TransformCache
|
||||
{
|
||||
[SerializeField]
|
||||
Color m_BindPoseColor;
|
||||
[SerializeField]
|
||||
private Pose m_BindPose;
|
||||
[SerializeField]
|
||||
private BonePose m_DefaultPose;
|
||||
[SerializeField]
|
||||
private BoneCache m_ChainedChild;
|
||||
[SerializeField]
|
||||
private float m_Depth;
|
||||
[SerializeField]
|
||||
private float m_LocalLength = 1f;
|
||||
[SerializeField]
|
||||
private bool m_IsVisible = true;
|
||||
|
||||
public bool NotInDefaultPose()
|
||||
{
|
||||
return localPosition != m_DefaultPose.pose.position
|
||||
|| localRotation != m_DefaultPose.pose.rotation
|
||||
|| localLength != m_DefaultPose.length;
|
||||
}
|
||||
|
||||
public bool isVisible
|
||||
{
|
||||
get { return m_IsVisible; }
|
||||
set { m_IsVisible = value; }
|
||||
}
|
||||
|
||||
public Color bindPoseColor
|
||||
{
|
||||
get { return m_BindPoseColor; }
|
||||
set { m_BindPoseColor = value; }
|
||||
}
|
||||
|
||||
public virtual BoneCache parentBone
|
||||
{
|
||||
get { return parent as BoneCache; }
|
||||
}
|
||||
|
||||
public SkeletonCache skeleton
|
||||
{
|
||||
get
|
||||
{
|
||||
var skeleton = parent as SkeletonCache;
|
||||
|
||||
if (skeleton != null)
|
||||
return skeleton;
|
||||
|
||||
if (parentBone != null)
|
||||
return parentBone.skeleton;
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual BoneCache chainedChild
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_ChainedChild != null && m_ChainedChild.parentBone == this)
|
||||
return m_ChainedChild;
|
||||
|
||||
return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (m_ChainedChild != value)
|
||||
{
|
||||
if (value == null || value.parentBone == this)
|
||||
{
|
||||
m_ChainedChild = value;
|
||||
if(m_ChainedChild != null)
|
||||
OrientToChainedChild(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 localEndPosition
|
||||
{
|
||||
get { return Vector3.right * localLength; }
|
||||
}
|
||||
|
||||
public Vector3 endPosition
|
||||
{
|
||||
get { return localToWorldMatrix.MultiplyPoint3x4(localEndPosition); }
|
||||
set
|
||||
{
|
||||
if (chainedChild == null)
|
||||
{
|
||||
var direction = value - position;
|
||||
right = direction;
|
||||
length = direction.magnitude;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public BonePose localPose
|
||||
{
|
||||
get { return BonePose.Create(Pose.Create(localPosition, localRotation), localLength); }
|
||||
set
|
||||
{
|
||||
localPosition = value.pose.position;
|
||||
localRotation = value.pose.rotation;
|
||||
localLength = value.length;
|
||||
}
|
||||
}
|
||||
|
||||
public BonePose worldPose
|
||||
{
|
||||
get { return BonePose.Create(Pose.Create(position, rotation), length); }
|
||||
set
|
||||
{
|
||||
position = value.pose.position;
|
||||
rotation = value.pose.rotation;
|
||||
length = value.length;
|
||||
}
|
||||
}
|
||||
|
||||
public Pose bindPose
|
||||
{
|
||||
get { return m_BindPose; }
|
||||
set { m_BindPose = value; }
|
||||
}
|
||||
|
||||
public float depth
|
||||
{
|
||||
get { return m_Depth; }
|
||||
set { m_Depth = value; }
|
||||
}
|
||||
public float localLength
|
||||
{
|
||||
get { return m_LocalLength; }
|
||||
set { m_LocalLength = Mathf.Max(0f, value); }
|
||||
}
|
||||
|
||||
public float length
|
||||
{
|
||||
get { return localToWorldMatrix.MultiplyVector(localEndPosition).magnitude; }
|
||||
set { m_LocalLength = worldToLocalMatrix.MultiplyVector(right * Mathf.Max(0f, value)).magnitude; }
|
||||
}
|
||||
|
||||
internal Pose[] GetChildrenWoldPose()
|
||||
{
|
||||
return Array.ConvertAll(children, c => Pose.Create(c.position, c.rotation));
|
||||
}
|
||||
|
||||
internal void SetChildrenWorldPose(Pose[] worldPose)
|
||||
{
|
||||
var childrenArray = children;
|
||||
|
||||
Debug.Assert(childrenArray.Length == worldPose.Length);
|
||||
|
||||
for (var i = 0; i < childrenArray.Length; ++i)
|
||||
{
|
||||
var child = childrenArray[i];
|
||||
var pose= worldPose[i];
|
||||
|
||||
child.position = pose.position;
|
||||
child.rotation = pose.rotation;
|
||||
}
|
||||
}
|
||||
|
||||
internal override void OnDestroy()
|
||||
{
|
||||
base.OnDestroy();
|
||||
m_ChainedChild = null;
|
||||
}
|
||||
|
||||
new public void SetParent(TransformCache newParent)
|
||||
{
|
||||
SetParent(newParent, true);
|
||||
}
|
||||
|
||||
new public void SetParent(TransformCache newParent, bool worldPositionStays)
|
||||
{
|
||||
if (parentBone != null && parentBone.chainedChild == this)
|
||||
parentBone.chainedChild = null;
|
||||
|
||||
base.SetParent(newParent, worldPositionStays);
|
||||
|
||||
if (parentBone != null && parentBone.chainedChild == null && (parentBone.endPosition - position).sqrMagnitude < 0.001f)
|
||||
parentBone.chainedChild = this;
|
||||
}
|
||||
|
||||
public void OrientToChainedChild(bool freezeChildren)
|
||||
{
|
||||
Debug.Assert(chainedChild != null);
|
||||
|
||||
var childPosition = chainedChild.position;
|
||||
var childRotation = chainedChild.rotation;
|
||||
|
||||
Pose[] childrenWorldPose = null;
|
||||
|
||||
if (freezeChildren)
|
||||
childrenWorldPose = GetChildrenWoldPose();
|
||||
|
||||
right = childPosition - position;
|
||||
|
||||
if (freezeChildren)
|
||||
{
|
||||
SetChildrenWorldPose(childrenWorldPose);
|
||||
}
|
||||
else
|
||||
{
|
||||
chainedChild.position = childPosition;
|
||||
chainedChild.rotation = childRotation;
|
||||
}
|
||||
|
||||
length = (childPosition - position).magnitude;
|
||||
}
|
||||
|
||||
public void SetDefaultPose()
|
||||
{
|
||||
m_DefaultPose = localPose;
|
||||
|
||||
if (IsUnscaled())
|
||||
m_BindPose = worldPose.pose;
|
||||
else
|
||||
throw new Exception("BindPose cannot be set under global scale");
|
||||
}
|
||||
|
||||
public void RestoreDefaultPose()
|
||||
{
|
||||
localPose = m_DefaultPose;
|
||||
}
|
||||
|
||||
private bool IsUnscaled()
|
||||
{
|
||||
var currentTransform = this as TransformCache;
|
||||
|
||||
while (currentTransform != null)
|
||||
{
|
||||
var scale = currentTransform.localScale;
|
||||
var isUnscaled = Mathf.Approximately(scale.x, 1f) && Mathf.Approximately(scale.y, 1f) && Mathf.Approximately(scale.z, 1f);
|
||||
|
||||
if (!isUnscaled)
|
||||
return false;
|
||||
|
||||
currentTransform = currentTransform.parent;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 262d646365ba9344aa9e63c3d60c4522
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,130 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
internal static class BoneCacheExtensions
|
||||
{
|
||||
public static BoneCache[] ToCharacterIfNeeded(this BoneCache[] bones)
|
||||
{
|
||||
return Array.ConvertAll(bones, b => ToCharacterIfNeeded(b));
|
||||
}
|
||||
|
||||
public static BoneCache[] ToSpriteSheetIfNeeded(this BoneCache[] bones)
|
||||
{
|
||||
return Array.ConvertAll(bones, b => ToSpriteSheetIfNeeded(b));
|
||||
}
|
||||
|
||||
public static BoneCache ToCharacterIfNeeded(this BoneCache bone)
|
||||
{
|
||||
if (bone == null)
|
||||
return null;
|
||||
|
||||
var skinningCache = bone.skinningCache;
|
||||
|
||||
if (skinningCache.hasCharacter)
|
||||
{
|
||||
if (bone.skeleton != skinningCache.character.skeleton)
|
||||
{
|
||||
var selectedSprite = skinningCache.selectedSprite;
|
||||
|
||||
if (selectedSprite == null)
|
||||
return null;
|
||||
|
||||
var skeleton = selectedSprite.GetSkeleton();
|
||||
var characterPart = selectedSprite.GetCharacterPart();
|
||||
|
||||
Debug.Assert(skeleton != null);
|
||||
Debug.Assert(characterPart != null);
|
||||
Debug.Assert(bone.skeleton == skeleton);
|
||||
Debug.Assert(skeleton.BoneCount == characterPart.BoneCount);
|
||||
|
||||
var index = skeleton.IndexOf(bone);
|
||||
|
||||
if (index == -1)
|
||||
bone = null;
|
||||
else
|
||||
bone = characterPart.GetBone(index);
|
||||
}
|
||||
}
|
||||
|
||||
return bone;
|
||||
}
|
||||
|
||||
public static BoneCache ToSpriteSheetIfNeeded(this BoneCache bone)
|
||||
{
|
||||
if (bone == null)
|
||||
return null;
|
||||
|
||||
var skinningCache = bone.skinningCache;
|
||||
|
||||
if (skinningCache.hasCharacter && skinningCache.mode == SkinningMode.SpriteSheet)
|
||||
{
|
||||
var selectedSprite = skinningCache.selectedSprite;
|
||||
|
||||
if (selectedSprite == null)
|
||||
return null;
|
||||
|
||||
var characterSkeleton = skinningCache.character.skeleton;
|
||||
|
||||
Debug.Assert(bone.skeleton == characterSkeleton);
|
||||
|
||||
var skeleton = selectedSprite.GetSkeleton();
|
||||
var characterPart = selectedSprite.GetCharacterPart();
|
||||
|
||||
Debug.Assert(skeleton != null);
|
||||
Debug.Assert(characterPart != null);
|
||||
Debug.Assert(skeleton.BoneCount == characterPart.BoneCount);
|
||||
|
||||
var index = characterPart.IndexOf(bone);
|
||||
|
||||
if (index == -1)
|
||||
bone = null;
|
||||
else
|
||||
bone = skeleton.GetBone(index);
|
||||
}
|
||||
|
||||
return bone;
|
||||
}
|
||||
|
||||
public static UnityEngine.U2D.SpriteBone ToSpriteBone(this BoneCache bone, Matrix4x4 rootTransform, int parentId)
|
||||
{
|
||||
var position = bone.localPosition;
|
||||
var rotation = bone.localRotation;
|
||||
|
||||
if (parentId == -1)
|
||||
{
|
||||
rotation = bone.rotation;
|
||||
position = rootTransform.inverse.MultiplyPoint3x4(bone.position);
|
||||
}
|
||||
|
||||
return new UnityEngine.U2D.SpriteBone()
|
||||
{
|
||||
name = bone.name,
|
||||
position = new Vector3(position.x, position.y, bone.depth),
|
||||
rotation = rotation,
|
||||
length = bone.localLength,
|
||||
parentId = parentId
|
||||
};
|
||||
}
|
||||
|
||||
public static UnityEngine.U2D.SpriteBone[] ToSpriteBone(this BoneCache[] bones, Matrix4x4 rootTransform)
|
||||
{
|
||||
var spriteBones = new List<UnityEngine.U2D.SpriteBone>();
|
||||
|
||||
foreach (var bone in bones)
|
||||
{
|
||||
var parentId = -1;
|
||||
|
||||
if (ArrayUtility.Contains(bones, bone.parentBone))
|
||||
parentId = Array.IndexOf(bones, bone.parentBone);
|
||||
|
||||
spriteBones.Add(bone.ToSpriteBone(rootTransform, parentId));
|
||||
}
|
||||
|
||||
return spriteBones.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d50b4f1248a256c4d96a6b0e9f346671
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,53 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
internal class CharacterCache : SkinningObject, IEnumerable<CharacterPartCache>
|
||||
{
|
||||
[SerializeField]
|
||||
private SkeletonCache m_Skeleton;
|
||||
[SerializeField]
|
||||
private List<CharacterPartCache> m_Parts = new List<CharacterPartCache>();
|
||||
[SerializeField]
|
||||
private Vector2Int m_Dimension;
|
||||
[SerializeField]
|
||||
private List<CharacterGroupCache> m_Groups = new List<CharacterGroupCache>();
|
||||
|
||||
public SkeletonCache skeleton
|
||||
{
|
||||
get { return m_Skeleton; }
|
||||
set { m_Skeleton = value; }
|
||||
}
|
||||
|
||||
public virtual CharacterPartCache[] parts
|
||||
{
|
||||
get { return m_Parts.ToArray(); }
|
||||
set { m_Parts = new List<CharacterPartCache>(value); }
|
||||
}
|
||||
|
||||
public virtual CharacterGroupCache[] groups
|
||||
{
|
||||
get { return m_Groups.ToArray(); }
|
||||
set { m_Groups = new List<CharacterGroupCache>(value); }
|
||||
}
|
||||
|
||||
public Vector2Int dimension
|
||||
{
|
||||
get { return m_Dimension; }
|
||||
set { m_Dimension = value; }
|
||||
}
|
||||
|
||||
public IEnumerator<CharacterPartCache> GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<CharacterPartCache>)m_Parts).GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return ((IEnumerable<CharacterPartCache>)m_Parts).GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7fcfe3c97703ff145afae98c5b358e95
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,99 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
[Serializable]
|
||||
internal class CharacterGroupCache : SkinningObject, ICharacterOrder
|
||||
{
|
||||
[SerializeField]
|
||||
public int parentGroup;
|
||||
[SerializeField]
|
||||
private bool m_IsVisible = true;
|
||||
[SerializeField]
|
||||
private int m_Order = -1;
|
||||
|
||||
public bool isVisible
|
||||
{
|
||||
get => m_IsVisible;
|
||||
set
|
||||
{
|
||||
m_IsVisible = value;
|
||||
skinningCache.GroupVisibilityChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual int order
|
||||
{
|
||||
get => m_Order;
|
||||
set => m_Order = value;
|
||||
}
|
||||
}
|
||||
|
||||
internal class CharacterPartCache : TransformCache, ICharacterOrder
|
||||
{
|
||||
[SerializeField]
|
||||
private SpriteCache m_Sprite;
|
||||
[SerializeField]
|
||||
private List<BoneCache> m_Bones = new List<BoneCache>();
|
||||
[SerializeField]
|
||||
private bool m_IsVisible = true;
|
||||
[SerializeField]
|
||||
private int m_ParentGroup = -1;
|
||||
[SerializeField]
|
||||
private int m_Order = -1;
|
||||
|
||||
public virtual int order
|
||||
{
|
||||
get => m_Order;
|
||||
set => m_Order = value;
|
||||
}
|
||||
|
||||
public int parentGroup
|
||||
{
|
||||
get { return m_ParentGroup; }
|
||||
set { m_ParentGroup = value; }
|
||||
}
|
||||
|
||||
public virtual bool isVisible
|
||||
{
|
||||
get { return m_IsVisible; }
|
||||
set
|
||||
{
|
||||
m_IsVisible = value;
|
||||
if (skinningCache != null)
|
||||
skinningCache.SpriteVisibilityChanged(this);
|
||||
}
|
||||
}
|
||||
|
||||
public int BoneCount { get { return m_Bones.Count; } }
|
||||
|
||||
public virtual SpriteCache sprite
|
||||
{
|
||||
get { return m_Sprite; }
|
||||
set { m_Sprite = value; }
|
||||
}
|
||||
|
||||
public BoneCache[] bones
|
||||
{
|
||||
get { return m_Bones.ToArray(); }
|
||||
set { m_Bones = new List<BoneCache>(value); }
|
||||
}
|
||||
|
||||
public BoneCache GetBone(int index)
|
||||
{
|
||||
return m_Bones[index];
|
||||
}
|
||||
|
||||
public int IndexOf(BoneCache bone)
|
||||
{
|
||||
return m_Bones.IndexOf(bone);
|
||||
}
|
||||
|
||||
public bool Contains(BoneCache bone)
|
||||
{
|
||||
return m_Bones.Contains(bone);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6ad9a0e8a9171a24abf3f2b88bec2bfa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,79 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
internal static class CharacterPartCacheExtensions
|
||||
{
|
||||
public static void SyncSpriteSheetSkeleton(this CharacterPartCache characterPart)
|
||||
{
|
||||
var skinningCache = characterPart.skinningCache;
|
||||
var character = skinningCache.character;
|
||||
var characterSkeleton = character.skeleton;
|
||||
var spriteSkeleton = characterPart.sprite.GetSkeleton();
|
||||
var spriteSkeletonBones = spriteSkeleton.bones;
|
||||
var characterPartBones = characterPart.bones;
|
||||
|
||||
if (spriteSkeletonBones.Length != characterPartBones.Length)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < characterPartBones.Length; ++i)
|
||||
{
|
||||
var spriteBone = spriteSkeletonBones[i];
|
||||
var characterBone = characterPartBones[i];
|
||||
var childWorldPose = spriteBone.GetChildrenWoldPose();
|
||||
|
||||
spriteBone.position = spriteSkeleton.localToWorldMatrix.MultiplyPoint3x4(
|
||||
characterPart.worldToLocalMatrix.MultiplyPoint3x4(characterBone.position));
|
||||
spriteBone.rotation = characterBone.rotation;
|
||||
spriteBone.length = characterBone.length;
|
||||
spriteBone.name = characterBone.name;
|
||||
spriteBone.depth = characterBone.depth;
|
||||
spriteBone.bindPoseColor = characterBone.bindPoseColor;
|
||||
|
||||
spriteBone.SetChildrenWorldPose(childWorldPose);
|
||||
}
|
||||
|
||||
if (characterSkeleton.isPosePreview)
|
||||
spriteSkeleton.SetPosePreview();
|
||||
else
|
||||
spriteSkeleton.SetDefaultPose();
|
||||
}
|
||||
|
||||
public static void DeassociateUnusedBones(this CharacterPartCache characterPart)
|
||||
{
|
||||
var skinningCache = characterPart.skinningCache;
|
||||
var bones = characterPart.bones;
|
||||
|
||||
if (bones.Length == 0)
|
||||
return;
|
||||
|
||||
Debug.Assert(characterPart.sprite != null);
|
||||
|
||||
var mesh = characterPart.sprite.GetMesh();
|
||||
|
||||
Debug.Assert(mesh != null);
|
||||
|
||||
var vertices = mesh.vertices;
|
||||
var newBonesSet = new HashSet<BoneCache>();
|
||||
|
||||
foreach (var vertex in vertices)
|
||||
{
|
||||
var boneWeight = vertex.editableBoneWeight;
|
||||
|
||||
foreach (BoneWeightChannel channel in boneWeight)
|
||||
if (channel.enabled)
|
||||
newBonesSet.Add(bones[channel.boneIndex]);
|
||||
}
|
||||
|
||||
bones = new List<BoneCache>(newBonesSet).ToArray();
|
||||
|
||||
characterPart.bones = bones;
|
||||
|
||||
characterPart.sprite.UpdateMesh(bones);
|
||||
|
||||
skinningCache.events.characterPartChanged.Invoke(characterPart);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 08c6298ccaa77394ab7bed9478eb9a9a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,203 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEditor.U2D.Sprites;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
internal class MeshCache : SkinningObject, ISpriteMeshData
|
||||
{
|
||||
[SerializeField]
|
||||
private SpriteCache m_Sprite;
|
||||
[SerializeField]
|
||||
private List<Vertex2D> m_Vertices = new List<Vertex2D>();
|
||||
[SerializeField]
|
||||
private List<int> m_Indices = new List<int>();
|
||||
[SerializeField]
|
||||
private List<Edge> m_Edges = new List<Edge>();
|
||||
[SerializeField]
|
||||
private List<BoneCache> m_Bones = new List<BoneCache>();
|
||||
public ITextureDataProvider textureDataProvider { get; set; }
|
||||
|
||||
public SpriteCache sprite
|
||||
{
|
||||
get { return m_Sprite; }
|
||||
set { m_Sprite = value; }
|
||||
}
|
||||
|
||||
public List<Vertex2D> vertices
|
||||
{
|
||||
get { return m_Vertices; }
|
||||
set { m_Vertices = value; }
|
||||
}
|
||||
|
||||
public List<Vector3> vertexPositionOverride { get; set; }
|
||||
|
||||
public List<Edge> edges
|
||||
{
|
||||
get { return m_Edges; }
|
||||
set { m_Edges = value; }
|
||||
}
|
||||
|
||||
public List<int> indices
|
||||
{
|
||||
get { return m_Indices; }
|
||||
set { m_Indices = value; }
|
||||
}
|
||||
|
||||
public BoneCache[] bones
|
||||
{
|
||||
get { return m_Bones.ToArray(); }
|
||||
set { SetBones(value); }
|
||||
}
|
||||
|
||||
Rect ISpriteMeshData.frame
|
||||
{
|
||||
get { return sprite.textureRect; }
|
||||
set {}
|
||||
}
|
||||
|
||||
public int vertexCount
|
||||
{
|
||||
get { return m_Vertices.Count; }
|
||||
}
|
||||
|
||||
public int boneCount
|
||||
{
|
||||
get { return m_Bones.Count; }
|
||||
}
|
||||
|
||||
public Vector2 GetPosition(int index)
|
||||
{
|
||||
if (vertexPositionOverride != null)
|
||||
return vertexPositionOverride[index];
|
||||
|
||||
return m_Vertices[index].position;
|
||||
}
|
||||
|
||||
public void SetPosition(int index, Vector2 position)
|
||||
{
|
||||
if (vertexPositionOverride != null)
|
||||
return;
|
||||
|
||||
m_Vertices[index].position = position;
|
||||
}
|
||||
|
||||
public EditableBoneWeight GetWeight(int index)
|
||||
{
|
||||
return m_Vertices[index].editableBoneWeight;
|
||||
}
|
||||
|
||||
public void SetWeight(int index, EditableBoneWeight weight)
|
||||
{
|
||||
m_Vertices[index].editableBoneWeight = weight;
|
||||
}
|
||||
|
||||
public void AddVertex(Vector2 position, BoneWeight weight)
|
||||
{
|
||||
m_Vertices.Add(new Vertex2D(position, weight));
|
||||
}
|
||||
|
||||
public void RemoveVertex(int index)
|
||||
{
|
||||
m_Vertices.RemoveAt(index);
|
||||
}
|
||||
|
||||
SpriteBoneData ISpriteMeshData.GetBoneData(int index)
|
||||
{
|
||||
var worldToLocalMatrix = sprite.worldToLocalMatrix;
|
||||
|
||||
//We expect m_Bones to contain character's bones references if character exists. Sprite's skeleton bones otherwise.
|
||||
if (skinningCache.hasCharacter)
|
||||
worldToLocalMatrix = sprite.GetCharacterPart().worldToLocalMatrix;
|
||||
|
||||
SpriteBoneData spriteBoneData = null;
|
||||
var bone = m_Bones[index];
|
||||
|
||||
if (bone == null)
|
||||
spriteBoneData = new SpriteBoneData();
|
||||
else
|
||||
{
|
||||
spriteBoneData = new SpriteBoneData()
|
||||
{
|
||||
name = bone.name,
|
||||
parentId = bone.parentBone == null ? -1 : m_Bones.IndexOf(bone.parentBone),
|
||||
localPosition = bone.localPosition,
|
||||
localRotation = bone.localRotation,
|
||||
position = worldToLocalMatrix.MultiplyPoint3x4(bone.position),
|
||||
endPosition = worldToLocalMatrix.MultiplyPoint3x4(bone.endPosition),
|
||||
depth = bone.depth,
|
||||
length = bone.localLength
|
||||
};
|
||||
}
|
||||
|
||||
return spriteBoneData;
|
||||
}
|
||||
|
||||
float ISpriteMeshData.GetBoneDepth(int index)
|
||||
{
|
||||
return m_Bones[index].depth;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
m_Vertices.Clear();
|
||||
m_Indices.Clear();
|
||||
m_Edges.Clear();
|
||||
}
|
||||
|
||||
public bool ContainsBone(BoneCache bone)
|
||||
{
|
||||
return m_Bones.Contains(bone);
|
||||
}
|
||||
|
||||
public void SetCompatibleBoneSet(BoneCache[] bones)
|
||||
{
|
||||
m_Bones = new List<BoneCache>(bones);
|
||||
}
|
||||
|
||||
private void SetBones(BoneCache[] bones)
|
||||
{
|
||||
FixWeights(bones);
|
||||
SetCompatibleBoneSet(bones);
|
||||
}
|
||||
|
||||
private void FixWeights(BoneCache[] newBones)
|
||||
{
|
||||
var newBonesList = new List<BoneCache>(newBones);
|
||||
var indexMap = new Dictionary<int, int>();
|
||||
|
||||
for (var i = 0; i < m_Bones.Count; ++i)
|
||||
{
|
||||
var bone = m_Bones[i];
|
||||
var newIndex = newBonesList.IndexOf(bone);
|
||||
|
||||
if (newIndex != -1)
|
||||
indexMap.Add(i, newIndex);
|
||||
}
|
||||
|
||||
foreach (Vertex2D vertex in vertices)
|
||||
{
|
||||
var boneWeight = vertex.editableBoneWeight;
|
||||
|
||||
for (var i = 0; i < boneWeight.Count; ++i)
|
||||
{
|
||||
var newIndex = 0;
|
||||
var boneRemoved = indexMap.TryGetValue(boneWeight[i].boneIndex, out newIndex) == false;
|
||||
|
||||
if (boneRemoved)
|
||||
{
|
||||
boneWeight[i].weight = 0f;
|
||||
boneWeight[i].enabled = false;
|
||||
}
|
||||
|
||||
boneWeight[i].boneIndex = newIndex;
|
||||
|
||||
if (boneRemoved)
|
||||
boneWeight.CompensateOtherChannels(i);
|
||||
}
|
||||
|
||||
boneWeight.UnifyChannelsWithSameBoneIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ec847c6dc93e9e6459ad61443ca36507
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,370 @@
|
|||
using UnityEngine;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
internal class MeshPreviewCache : SkinningObject
|
||||
{
|
||||
private const int kNiceColorCount = 6;
|
||||
|
||||
[SerializeField]
|
||||
private SpriteCache m_Sprite;
|
||||
[SerializeField]
|
||||
private Mesh m_Mesh;
|
||||
[SerializeField]
|
||||
private Mesh m_DefaultMesh;
|
||||
private List<Vector3> m_SkinnedVertices = new List<Vector3>();
|
||||
private List<Vector3> m_Vertices = new List<Vector3>();
|
||||
private List<BoneWeight> m_Weights = new List<BoneWeight>();
|
||||
private List<Vector2> m_TexCoords = new List<Vector2>();
|
||||
private List<Color> m_Colors = new List<Color>();
|
||||
private List<Matrix4x4> m_SkinningMatrices = new List<Matrix4x4>();
|
||||
private bool m_MeshDirty;
|
||||
private bool m_VerticesDirty;
|
||||
private bool m_SkinningDirty;
|
||||
private bool m_WeightsDirty;
|
||||
private bool m_IndicesDirty;
|
||||
private bool m_ColorsDirty;
|
||||
private bool m_EnableSkinning;
|
||||
|
||||
public SpriteCache sprite
|
||||
{
|
||||
get { return m_Sprite; }
|
||||
set
|
||||
{
|
||||
m_Sprite = value;
|
||||
InitializeDefaultMesh();
|
||||
SetMeshDirty();
|
||||
}
|
||||
}
|
||||
|
||||
public Mesh mesh { get { return m_Mesh; } }
|
||||
public Mesh defaultMesh { get { return m_DefaultMesh; } }
|
||||
|
||||
public bool enableSkinning
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_EnableSkinning;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (m_EnableSkinning != value)
|
||||
{
|
||||
m_EnableSkinning = value;
|
||||
SetSkinningDirty();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool canSkin
|
||||
{
|
||||
get { return CanSkin(); }
|
||||
}
|
||||
|
||||
public List<Vector3> vertices
|
||||
{
|
||||
get
|
||||
{
|
||||
if (enableSkinning && canSkin)
|
||||
return m_SkinnedVertices;
|
||||
|
||||
return m_Vertices;
|
||||
}
|
||||
}
|
||||
|
||||
private bool CanSkin()
|
||||
{
|
||||
if (m_Vertices.Count == 0 || m_Vertices.Count != m_Weights.Count)
|
||||
return false;
|
||||
|
||||
var bones = sprite.GetBonesFromMode();
|
||||
|
||||
Debug.Assert(bones != null);
|
||||
|
||||
if (bones.Length == 0)
|
||||
return false;
|
||||
|
||||
foreach (var weight in m_Weights)
|
||||
{
|
||||
if (weight.boneIndex0 < 0 || weight.boneIndex0 >= bones.Length ||
|
||||
weight.boneIndex1 < 0 || weight.boneIndex1 >= bones.Length ||
|
||||
weight.boneIndex2 < 0 || weight.boneIndex2 >= bones.Length ||
|
||||
weight.boneIndex3 < 0 || weight.boneIndex3 >= bones.Length)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
internal override void OnCreate()
|
||||
{
|
||||
m_Mesh = CreateMesh();
|
||||
m_DefaultMesh = CreateMesh();
|
||||
}
|
||||
|
||||
internal override void OnDestroy()
|
||||
{
|
||||
DestroyImmediate(m_Mesh);
|
||||
DestroyImmediate(m_DefaultMesh);
|
||||
}
|
||||
|
||||
private Mesh CreateMesh()
|
||||
{
|
||||
var mesh = new Mesh();
|
||||
mesh.MarkDynamic();
|
||||
mesh.hideFlags = HideFlags.DontSave;
|
||||
|
||||
return mesh;
|
||||
}
|
||||
|
||||
private void InitializeDefaultMesh()
|
||||
{
|
||||
Debug.Assert(sprite != null);
|
||||
Debug.Assert(m_DefaultMesh != null);
|
||||
|
||||
var meshCache = sprite.GetMesh();
|
||||
|
||||
Debug.Assert(meshCache != null);
|
||||
|
||||
int width, height;
|
||||
meshCache.textureDataProvider.GetTextureActualWidthAndHeight(out width, out height);
|
||||
|
||||
var uvScale = new Vector2(1f / width, 1f / height);
|
||||
Vector3 position = sprite.textureRect.position;
|
||||
var size = sprite.textureRect.size;
|
||||
|
||||
var vertices = new List<Vector3>()
|
||||
{
|
||||
Vector3.zero,
|
||||
new Vector3(0f, size.y, 0f),
|
||||
new Vector3(size.x, 0f, 0f),
|
||||
size,
|
||||
};
|
||||
|
||||
var uvs = new List<Vector2>()
|
||||
{
|
||||
Vector3.Scale(vertices[0] + position, uvScale),
|
||||
Vector3.Scale(vertices[1] + position, uvScale),
|
||||
Vector3.Scale(vertices[2] + position, uvScale),
|
||||
Vector3.Scale(vertices[3] + position, uvScale),
|
||||
};
|
||||
|
||||
m_DefaultMesh.SetVertices(vertices);
|
||||
m_DefaultMesh.SetUVs(0, uvs);
|
||||
m_DefaultMesh.SetColors(new List<Color>
|
||||
{
|
||||
Color.black,
|
||||
Color.black,
|
||||
Color.black,
|
||||
Color.black
|
||||
});
|
||||
m_DefaultMesh.SetIndices(new int[]
|
||||
{
|
||||
0, 1, 3, 0, 3, 2
|
||||
},
|
||||
MeshTopology.Triangles, 0);
|
||||
|
||||
m_DefaultMesh.UploadMeshData(false);
|
||||
}
|
||||
|
||||
public void SetMeshDirty()
|
||||
{
|
||||
m_MeshDirty = true;
|
||||
}
|
||||
|
||||
public void SetVerticesDirty()
|
||||
{
|
||||
m_VerticesDirty = true;
|
||||
}
|
||||
|
||||
public void SetSkinningDirty()
|
||||
{
|
||||
m_SkinningDirty = true;
|
||||
}
|
||||
|
||||
public void SetWeightsDirty()
|
||||
{
|
||||
m_WeightsDirty = true;
|
||||
}
|
||||
|
||||
public void SetIndicesDirty()
|
||||
{
|
||||
m_IndicesDirty = true;
|
||||
}
|
||||
|
||||
public void SetColorsDirty()
|
||||
{
|
||||
m_ColorsDirty = true;
|
||||
}
|
||||
|
||||
public void Prepare()
|
||||
{
|
||||
var meshChanged = false;
|
||||
var meshCache = sprite.GetMesh();
|
||||
|
||||
Debug.Assert(meshCache != null);
|
||||
|
||||
m_MeshDirty |= m_Vertices.Count != meshCache.vertices.Count;
|
||||
|
||||
if (m_MeshDirty)
|
||||
{
|
||||
m_Mesh.Clear();
|
||||
m_VerticesDirty = true;
|
||||
m_WeightsDirty = true;
|
||||
m_IndicesDirty = true;
|
||||
m_SkinningDirty = true;
|
||||
m_MeshDirty = false;
|
||||
}
|
||||
|
||||
if (m_VerticesDirty)
|
||||
{
|
||||
m_Vertices.Clear();
|
||||
m_TexCoords.Clear();
|
||||
|
||||
int width, height;
|
||||
meshCache.textureDataProvider.GetTextureActualWidthAndHeight(out width, out height);
|
||||
|
||||
var uvScale = new Vector2(1f / width, 1f / height);
|
||||
|
||||
foreach (var vertex in meshCache.vertices)
|
||||
{
|
||||
m_Vertices.Add(vertex.position);
|
||||
m_TexCoords.Add(Vector2.Scale(vertex.position + sprite.textureRect.position, uvScale));
|
||||
}
|
||||
|
||||
m_Mesh.SetVertices(m_Vertices);
|
||||
m_Mesh.SetUVs(0, m_TexCoords);
|
||||
meshChanged = true;
|
||||
m_VerticesDirty = false;
|
||||
}
|
||||
|
||||
if (m_WeightsDirty)
|
||||
{
|
||||
m_Weights.Clear();
|
||||
|
||||
for (int i = 0; i < meshCache.vertices.Count; ++i)
|
||||
{
|
||||
var vertex = meshCache.vertices[i];
|
||||
m_Weights.Add(vertex.editableBoneWeight.ToBoneWeight(true));
|
||||
}
|
||||
|
||||
SetColorsDirty();
|
||||
meshChanged = true;
|
||||
m_WeightsDirty = false;
|
||||
}
|
||||
|
||||
if (m_ColorsDirty)
|
||||
{
|
||||
PrepareColors();
|
||||
|
||||
m_Mesh.SetColors(m_Colors);
|
||||
meshChanged = true;
|
||||
m_ColorsDirty = false;
|
||||
}
|
||||
|
||||
if (m_IndicesDirty)
|
||||
{
|
||||
m_Mesh.SetTriangles(meshCache.indices, 0);
|
||||
meshChanged = true;
|
||||
m_IndicesDirty = false;
|
||||
}
|
||||
|
||||
if (m_SkinningDirty)
|
||||
{
|
||||
if (enableSkinning && canSkin)
|
||||
{
|
||||
SkinVertices();
|
||||
m_Mesh.SetVertices(m_SkinnedVertices);
|
||||
meshChanged = true;
|
||||
}
|
||||
|
||||
m_SkinningDirty = false;
|
||||
}
|
||||
|
||||
if (meshChanged)
|
||||
{
|
||||
m_Mesh.UploadMeshData(false);
|
||||
m_Mesh.RecalculateBounds();
|
||||
skinningCache.events.meshPreviewChanged.Invoke(this);
|
||||
}
|
||||
}
|
||||
|
||||
private void PrepareColors()
|
||||
{
|
||||
var bones = sprite.GetBonesFromMode();
|
||||
|
||||
Debug.Assert(bones != null);
|
||||
|
||||
m_Colors.Clear();
|
||||
|
||||
for (var i = 0; i < m_Weights.Count; ++i)
|
||||
{
|
||||
var boneWeight = m_Weights[i];
|
||||
var weightSum = 0f;
|
||||
var color = Color.black;
|
||||
|
||||
for (var j = 0; j < 4; ++j)
|
||||
{
|
||||
var boneIndex = boneWeight.GetBoneIndex(j);
|
||||
var weight = boneWeight.GetWeight(j);
|
||||
|
||||
if (boneIndex >= 0 && boneIndex < bones.Length)
|
||||
color += bones[boneIndex].bindPoseColor * weight;
|
||||
|
||||
weightSum += weight;
|
||||
}
|
||||
|
||||
color.a = 1f;
|
||||
|
||||
m_Colors.Add(Color.Lerp(Color.black, color, weightSum));
|
||||
}
|
||||
}
|
||||
|
||||
private void SkinVertices()
|
||||
{
|
||||
Debug.Assert(canSkin);
|
||||
Debug.Assert(sprite != null);
|
||||
|
||||
var bones = sprite.GetBonesFromMode();
|
||||
|
||||
var originMatrix = Matrix4x4.TRS(sprite.pivotRectSpace, Quaternion.identity, Vector3.one);
|
||||
var originInverseMatrix = originMatrix.inverse;
|
||||
var spriteMatrix = sprite.GetLocalToWorldMatrixFromMode();
|
||||
var spriteMatrixInv = spriteMatrix.inverse;
|
||||
|
||||
m_SkinnedVertices.Clear();
|
||||
m_SkinningMatrices.Clear();
|
||||
|
||||
for (int i = 0; i < bones.Length; ++i)
|
||||
m_SkinningMatrices.Add(spriteMatrixInv * originInverseMatrix * bones[i].localToWorldMatrix * bones[i].bindPose.matrix.inverse * spriteMatrix);
|
||||
|
||||
for (int i = 0; i < m_Vertices.Count; ++i)
|
||||
{
|
||||
var position = m_Vertices[i];
|
||||
BoneWeight boneWeight = m_Weights[i];
|
||||
float weightSum = boneWeight.weight0 + boneWeight.weight1 + boneWeight.weight2 + boneWeight.weight3;
|
||||
|
||||
if (weightSum > 0f)
|
||||
{
|
||||
var weightSumInv = 1f / weightSum;
|
||||
var skinnedPosition = m_SkinningMatrices[boneWeight.boneIndex0].MultiplyPoint3x4(position) * boneWeight.weight0 * weightSumInv +
|
||||
m_SkinningMatrices[boneWeight.boneIndex1].MultiplyPoint3x4(position) * boneWeight.weight1 * weightSumInv +
|
||||
m_SkinningMatrices[boneWeight.boneIndex2].MultiplyPoint3x4(position) * boneWeight.weight2 * weightSumInv +
|
||||
m_SkinningMatrices[boneWeight.boneIndex3].MultiplyPoint3x4(position) * boneWeight.weight3 * weightSumInv;
|
||||
|
||||
position = Vector3.Lerp(position, skinnedPosition, weightSum);
|
||||
}
|
||||
|
||||
m_SkinnedVertices.Add(position);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnAfterDeserialize()
|
||||
{
|
||||
SetMeshDirty();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 22143b1295b3a684d8118f7fa6c0403d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,192 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
internal class SkeletonCache : TransformCache
|
||||
{
|
||||
[SerializeField]
|
||||
private bool m_IsPosePreview = false;
|
||||
[SerializeField]
|
||||
private List<BoneCache> m_Bones = new List<BoneCache>();
|
||||
|
||||
public bool isPosePreview { get { return m_IsPosePreview; } }
|
||||
|
||||
public int BoneCount { get { return m_Bones.Count; } }
|
||||
|
||||
public virtual BoneCache[] bones
|
||||
{
|
||||
get { return m_Bones.ToArray(); }
|
||||
}
|
||||
|
||||
public void AddBone(BoneCache bone)
|
||||
{
|
||||
AddBone(bone, true);
|
||||
}
|
||||
|
||||
public void AddBone(BoneCache bone, bool worldPositionStays)
|
||||
{
|
||||
Debug.Assert(bone != null);
|
||||
Debug.Assert(!Contains(bone));
|
||||
|
||||
if (bone.parent == null)
|
||||
bone.SetParent(this, worldPositionStays);
|
||||
|
||||
m_Bones.Add(bone);
|
||||
}
|
||||
|
||||
public void ReorderBones(IEnumerable<BoneCache> boneCache)
|
||||
{
|
||||
if (boneCache.Count() == m_Bones.Count)
|
||||
{
|
||||
foreach (var b in m_Bones)
|
||||
{
|
||||
if (!boneCache.Contains(b))
|
||||
return;
|
||||
}
|
||||
m_Bones = boneCache.ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public void DestroyBone(BoneCache bone)
|
||||
{
|
||||
Debug.Assert(bone != null);
|
||||
Debug.Assert(Contains(bone));
|
||||
|
||||
m_Bones.Remove(bone);
|
||||
|
||||
var children = bone.children;
|
||||
foreach (var child in children)
|
||||
child.SetParent(bone.parent);
|
||||
|
||||
skinningCache.Destroy(bone);
|
||||
}
|
||||
|
||||
public void SetDefaultPose()
|
||||
{
|
||||
foreach (var bone in m_Bones)
|
||||
bone.SetDefaultPose();
|
||||
|
||||
m_IsPosePreview = false;
|
||||
}
|
||||
|
||||
public void RestoreDefaultPose()
|
||||
{
|
||||
foreach (var bone in m_Bones)
|
||||
bone.RestoreDefaultPose();
|
||||
|
||||
m_IsPosePreview = false;
|
||||
skinningCache.events.skeletonPreviewPoseChanged.Invoke(this);
|
||||
}
|
||||
|
||||
public void SetPosePreview()
|
||||
{
|
||||
m_IsPosePreview = true;
|
||||
}
|
||||
|
||||
public BonePose[] GetLocalPose()
|
||||
{
|
||||
var pose = new List<BonePose>();
|
||||
|
||||
foreach (var bone in m_Bones)
|
||||
pose.Add(bone.localPose);
|
||||
|
||||
return pose.ToArray();
|
||||
}
|
||||
|
||||
public void SetLocalPose(BonePose[] pose)
|
||||
{
|
||||
Debug.Assert(m_Bones.Count == pose.Length);
|
||||
|
||||
for (var i = 0; i < m_Bones.Count; ++i)
|
||||
m_Bones[i].localPose = pose[i];
|
||||
|
||||
m_IsPosePreview = true;
|
||||
}
|
||||
|
||||
public BonePose[] GetWorldPose()
|
||||
{
|
||||
var pose = new List<BonePose>();
|
||||
|
||||
foreach (var bone in m_Bones)
|
||||
pose.Add(bone.worldPose);
|
||||
|
||||
return pose.ToArray();
|
||||
}
|
||||
|
||||
public void SetWorldPose(BonePose[] pose)
|
||||
{
|
||||
Debug.Assert(m_Bones.Count == pose.Length);
|
||||
|
||||
for (var i = 0; i < m_Bones.Count; ++i)
|
||||
{
|
||||
var bone = m_Bones[i];
|
||||
var childWoldPose = bone.GetChildrenWoldPose();
|
||||
bone.worldPose = pose[i];
|
||||
bone.SetChildrenWorldPose(childWoldPose);
|
||||
}
|
||||
|
||||
m_IsPosePreview = true;
|
||||
}
|
||||
|
||||
public BoneCache GetBone(int index)
|
||||
{
|
||||
return m_Bones[index];
|
||||
}
|
||||
|
||||
public int IndexOf(BoneCache bone)
|
||||
{
|
||||
return m_Bones.IndexOf(bone);
|
||||
}
|
||||
|
||||
public bool Contains(BoneCache bone)
|
||||
{
|
||||
return m_Bones.Contains(bone);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
var roots = children;
|
||||
|
||||
foreach (var root in roots)
|
||||
DestroyHierarchy(root);
|
||||
|
||||
m_Bones.Clear();
|
||||
}
|
||||
|
||||
public string GetUniqueName(BoneCache bone)
|
||||
{
|
||||
Debug.Assert(Contains(bone));
|
||||
|
||||
var boneName = bone.name;
|
||||
var names = m_Bones.ConvertAll(b => b.name);
|
||||
var index = IndexOf(bone);
|
||||
var count = 0;
|
||||
|
||||
Debug.Assert(index < names.Count);
|
||||
|
||||
for (var i = 0; i < index; ++i)
|
||||
if (names[i].Equals(boneName))
|
||||
++count;
|
||||
|
||||
if (count == 0)
|
||||
return boneName;
|
||||
|
||||
return string.Format("{0} ({1})", boneName, count + 1);
|
||||
}
|
||||
|
||||
private void DestroyHierarchy(TransformCache root)
|
||||
{
|
||||
Debug.Assert(root != null);
|
||||
|
||||
var children = root.children;
|
||||
|
||||
foreach (var child in children)
|
||||
DestroyHierarchy(child);
|
||||
|
||||
skinningCache.Destroy(root);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9fd71ece24e4d504ba204588a27de2cc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,181 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
internal static class SkeletonCacheExtensions
|
||||
{
|
||||
public static void RotateBones(this SkeletonCache skeleton, BoneCache[] bones, float deltaAngle)
|
||||
{
|
||||
Debug.Assert(skeleton != null);
|
||||
|
||||
foreach (var bone in bones)
|
||||
{
|
||||
Debug.Assert(bone != null);
|
||||
Debug.Assert(skeleton.Contains(bone));
|
||||
|
||||
bone.localRotation *= Quaternion.AngleAxis(deltaAngle, Vector3.forward);
|
||||
}
|
||||
}
|
||||
|
||||
public static void MoveBones(this SkeletonCache skeleton, BoneCache[] bones, Vector3 deltaPosition)
|
||||
{
|
||||
Debug.Assert(skeleton != null);
|
||||
|
||||
foreach (var bone in bones)
|
||||
{
|
||||
Debug.Assert(bone != null);
|
||||
Debug.Assert(skeleton.Contains(bone));
|
||||
|
||||
bone.position += deltaPosition;
|
||||
|
||||
if (bone.parentBone != null && bone.parentBone.chainedChild == bone)
|
||||
bone.parentBone.OrientToChainedChild(false);
|
||||
}
|
||||
}
|
||||
|
||||
public static void FreeMoveBones(this SkeletonCache skeleton, BoneCache[] bones, Vector3 deltaPosition)
|
||||
{
|
||||
Debug.Assert(skeleton != null);
|
||||
|
||||
foreach (var bone in bones)
|
||||
{
|
||||
Debug.Assert(bone != null);
|
||||
Debug.Assert(skeleton.Contains(bone));
|
||||
|
||||
var childrenWorldPose = bone.GetChildrenWoldPose();
|
||||
|
||||
if (bone.chainedChild != null && ArrayUtility.Contains(bones, bone.chainedChild) == false)
|
||||
bone.chainedChild = null;
|
||||
|
||||
if (bone.parentBone != null && bone.parentBone.chainedChild == bone && ArrayUtility.Contains(bones, bone.parentBone) == false)
|
||||
bone.parentBone.chainedChild = null;
|
||||
|
||||
bone.position += deltaPosition;
|
||||
|
||||
bone.SetChildrenWorldPose(childrenWorldPose);
|
||||
}
|
||||
}
|
||||
|
||||
public static void MoveJoints(this SkeletonCache skeleton, BoneCache[] bones, Vector3 deltaPosition)
|
||||
{
|
||||
Debug.Assert(skeleton != null);
|
||||
|
||||
foreach (var bone in bones)
|
||||
{
|
||||
Debug.Assert(bone != null);
|
||||
Debug.Assert(skeleton.Contains(bone));
|
||||
|
||||
var childrenWorldPose = bone.GetChildrenWoldPose();
|
||||
var endPosition = bone.endPosition;
|
||||
|
||||
bone.position += deltaPosition;
|
||||
|
||||
if (bone.localLength > 0f)
|
||||
bone.endPosition = endPosition;
|
||||
|
||||
if (bone.parentBone != null && bone.parentBone.chainedChild == bone)
|
||||
bone.parentBone.OrientToChainedChild(true);
|
||||
|
||||
bone.SetChildrenWorldPose(childrenWorldPose);
|
||||
|
||||
if (bone.chainedChild != null)
|
||||
bone.OrientToChainedChild(true);
|
||||
}
|
||||
}
|
||||
|
||||
public static void SetEndPosition(this SkeletonCache skeleton, BoneCache bone, Vector3 endPosition)
|
||||
{
|
||||
Debug.Assert(skeleton != null);
|
||||
Debug.Assert(bone != null);
|
||||
Debug.Assert(skeleton.Contains(bone));
|
||||
|
||||
var childrenStorage = bone.GetChildrenWoldPose();
|
||||
bone.endPosition = endPosition;
|
||||
bone.SetChildrenWorldPose(childrenStorage);
|
||||
}
|
||||
|
||||
public static BoneCache SplitBone(this SkeletonCache skeleton, BoneCache boneToSplit, float splitLength, string name)
|
||||
{
|
||||
Debug.Assert(skeleton.Contains(boneToSplit));
|
||||
Debug.Assert(boneToSplit.length > splitLength);
|
||||
|
||||
var endPosition = boneToSplit.endPosition;
|
||||
var chainedChild = boneToSplit.chainedChild;
|
||||
var splitPosition = boneToSplit.position + boneToSplit.right * splitLength;
|
||||
|
||||
boneToSplit.length = splitLength;
|
||||
|
||||
var bone = skeleton.CreateBone(boneToSplit, splitPosition, endPosition, true, name);
|
||||
|
||||
if (chainedChild != null)
|
||||
{
|
||||
chainedChild.SetParent(bone);
|
||||
bone.chainedChild = chainedChild;
|
||||
}
|
||||
|
||||
return bone;
|
||||
}
|
||||
|
||||
public static BoneCache CreateBone(this SkeletonCache skeleton, BoneCache parentBone, Vector3 position, Vector3 endPosition, bool isChained, string name)
|
||||
{
|
||||
Debug.Assert(skeleton != null);
|
||||
|
||||
if (parentBone != null)
|
||||
Debug.Assert(skeleton.Contains(parentBone));
|
||||
|
||||
var bone = skeleton.skinningCache.CreateCache<BoneCache>();
|
||||
|
||||
bone.SetParent(parentBone);
|
||||
bone.name = name;
|
||||
bone.bindPoseColor = ModuleUtility.CalculateNiceColor(skeleton.BoneCount, 6);
|
||||
bone.position = position;
|
||||
bone.endPosition = endPosition;
|
||||
|
||||
if (isChained && parentBone != null)
|
||||
parentBone.chainedChild = bone;
|
||||
|
||||
skeleton.AddBone(bone);
|
||||
|
||||
|
||||
return bone;
|
||||
}
|
||||
|
||||
public static void SetBones(this SkeletonCache skeleton, BoneCache[] bones)
|
||||
{
|
||||
skeleton.SetBones(bones, true);
|
||||
}
|
||||
|
||||
public static void SetBones(this SkeletonCache skeleton, BoneCache[] bones, bool worldPositionStays)
|
||||
{
|
||||
skeleton.Clear();
|
||||
skeleton.AddBones(bones, worldPositionStays);
|
||||
skeleton.SetDefaultPose();
|
||||
}
|
||||
|
||||
public static void AddBones(this SkeletonCache skeleton, BoneCache[] bones)
|
||||
{
|
||||
skeleton.AddBones(bones, true);
|
||||
}
|
||||
|
||||
public static void AddBones(this SkeletonCache skeleton, BoneCache[] bones, bool worldPositionStays)
|
||||
{
|
||||
foreach (var bone in bones)
|
||||
skeleton.AddBone(bone, worldPositionStays);
|
||||
}
|
||||
|
||||
public static void DestroyBones(this SkeletonCache skeleton, BoneCache[] bones)
|
||||
{
|
||||
Debug.Assert(skeleton != null);
|
||||
|
||||
foreach (var bone in bones)
|
||||
{
|
||||
Debug.Assert(bone != null);
|
||||
Debug.Assert(skeleton.Contains(bone));
|
||||
|
||||
skeleton.DestroyBone(bone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0a2dae245e3ce6444a467f0c55afd6f2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 85b7a96bd2d82844391585d64f46742b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,270 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
internal interface ISkinningCachePersistentState
|
||||
{
|
||||
String lastSpriteId
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
Tools lastUsedTool
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
List<int> lastBoneSelectionIds
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
Texture2D lastTexture
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
SerializableDictionary<int, BonePose> lastPreviewPose
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
SerializableDictionary<int, bool> lastBoneVisibility
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
SerializableDictionary<int, bool> lastBoneExpansion
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
SerializableDictionary<string, bool> lastSpriteVisibility
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
SerializableDictionary<int, bool> lastGroupVisibility
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
SkinningMode lastMode
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
bool lastVisibilityToolActive
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
int lastVisibilityToolIndex
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
IndexedSelection lastVertexSelection
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
float lastBrushSize
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
float lastBrushHardness
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
float lastBrushStep
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
internal class SkinningCachePersistentState
|
||||
: ScriptableSingleton<SkinningCachePersistentState>
|
||||
, ISkinningCachePersistentState
|
||||
{
|
||||
[SerializeField] private Tools m_LastUsedTool = Tools.EditPose;
|
||||
|
||||
[SerializeField] private SkinningMode m_LastMode = SkinningMode.Character;
|
||||
|
||||
[SerializeField] private string m_LastSpriteId = String.Empty;
|
||||
|
||||
[SerializeField] private List<int> m_LastBoneSelectionIds = new List<int>();
|
||||
|
||||
[SerializeField] private Texture2D m_LastTexture;
|
||||
|
||||
[SerializeField]
|
||||
private SerializableDictionary<int, BonePose> m_SkeletonPreviewPose =
|
||||
new SerializableDictionary<int, BonePose>();
|
||||
|
||||
[SerializeField]
|
||||
private SerializableDictionary<int, bool> m_BoneVisibility =
|
||||
new SerializableDictionary<int, bool>();
|
||||
|
||||
[SerializeField]
|
||||
private SerializableDictionary<int, bool> m_BoneExpansion =
|
||||
new SerializableDictionary<int, bool>();
|
||||
|
||||
[SerializeField]
|
||||
private SerializableDictionary<string, bool> m_SpriteVisibility =
|
||||
new SerializableDictionary<string, bool>();
|
||||
|
||||
[SerializeField]
|
||||
private SerializableDictionary<int, bool> m_GroupVisibility =
|
||||
new SerializableDictionary<int, bool>();
|
||||
|
||||
[SerializeField] private IndexedSelection m_VertexSelection;
|
||||
|
||||
[SerializeField] private bool m_VisibilityToolActive;
|
||||
[SerializeField] private int m_VisibilityToolIndex = -1;
|
||||
|
||||
[SerializeField] private float m_LastBrushSize = 25f;
|
||||
[SerializeField] private float m_LastBrushHardness = 1f;
|
||||
[SerializeField] private float m_LastBrushStep = 20f;
|
||||
|
||||
public SkinningCachePersistentState()
|
||||
{
|
||||
m_VertexSelection = new IndexedSelection();
|
||||
}
|
||||
|
||||
public void SetDefault()
|
||||
{
|
||||
m_LastUsedTool = Tools.EditPose;
|
||||
m_LastMode = SkinningMode.Character;
|
||||
m_LastSpriteId = String.Empty;
|
||||
m_LastBoneSelectionIds.Clear();
|
||||
m_LastTexture = null;
|
||||
m_VertexSelection.Clear();
|
||||
m_SkeletonPreviewPose.Clear();
|
||||
m_BoneVisibility.Clear();
|
||||
m_BoneExpansion.Clear();
|
||||
m_SpriteVisibility.Clear();
|
||||
m_GroupVisibility.Clear();
|
||||
m_VisibilityToolActive = false;
|
||||
m_VisibilityToolIndex = -1;
|
||||
}
|
||||
|
||||
public string lastSpriteId
|
||||
{
|
||||
get { return m_LastSpriteId; }
|
||||
set { m_LastSpriteId = value; }
|
||||
}
|
||||
|
||||
public Tools lastUsedTool
|
||||
{
|
||||
get { return m_LastUsedTool; }
|
||||
set { m_LastUsedTool = value; }
|
||||
}
|
||||
|
||||
public List<int> lastBoneSelectionIds
|
||||
{
|
||||
get { return m_LastBoneSelectionIds; }
|
||||
}
|
||||
|
||||
public Texture2D lastTexture
|
||||
{
|
||||
get { return m_LastTexture; }
|
||||
set
|
||||
{
|
||||
if (value != m_LastTexture)
|
||||
{
|
||||
m_LastMode = SkinningMode.Character;
|
||||
m_LastSpriteId = String.Empty;
|
||||
m_LastBoneSelectionIds.Clear();
|
||||
m_VertexSelection.Clear();
|
||||
m_SkeletonPreviewPose.Clear();
|
||||
m_BoneVisibility.Clear();
|
||||
m_BoneExpansion.Clear();
|
||||
m_SpriteVisibility.Clear();
|
||||
m_GroupVisibility.Clear();
|
||||
}
|
||||
|
||||
m_LastTexture = value;
|
||||
}
|
||||
}
|
||||
|
||||
public SerializableDictionary<int, BonePose> lastPreviewPose
|
||||
{
|
||||
get { return m_SkeletonPreviewPose; }
|
||||
}
|
||||
|
||||
public SerializableDictionary<int, bool> lastBoneVisibility
|
||||
{
|
||||
get { return m_BoneVisibility; }
|
||||
}
|
||||
|
||||
public SerializableDictionary<int, bool> lastBoneExpansion
|
||||
{
|
||||
get { return m_BoneExpansion; }
|
||||
}
|
||||
|
||||
public SerializableDictionary<string, bool> lastSpriteVisibility
|
||||
{
|
||||
get { return m_SpriteVisibility; }
|
||||
}
|
||||
|
||||
public SerializableDictionary<int, bool> lastGroupVisibility
|
||||
{
|
||||
get { return m_GroupVisibility; }
|
||||
}
|
||||
|
||||
public SkinningMode lastMode
|
||||
{
|
||||
get { return m_LastMode; }
|
||||
set { m_LastMode = value; }
|
||||
}
|
||||
|
||||
public bool lastVisibilityToolActive
|
||||
{
|
||||
get { return m_VisibilityToolActive; }
|
||||
set { m_VisibilityToolActive = value; }
|
||||
}
|
||||
|
||||
public int lastVisibilityToolIndex
|
||||
{
|
||||
get { return m_VisibilityToolIndex; }
|
||||
set { m_VisibilityToolIndex = value; }
|
||||
}
|
||||
|
||||
public IndexedSelection lastVertexSelection
|
||||
{
|
||||
get { return m_VertexSelection; }
|
||||
}
|
||||
|
||||
public float lastBrushSize
|
||||
{
|
||||
get { return m_LastBrushSize; }
|
||||
set { m_LastBrushSize = value; }
|
||||
}
|
||||
|
||||
public float lastBrushHardness
|
||||
{
|
||||
get { return m_LastBrushHardness; }
|
||||
set { m_LastBrushHardness = value; }
|
||||
}
|
||||
|
||||
public float lastBrushStep
|
||||
{
|
||||
get { return m_LastBrushStep; }
|
||||
set { m_LastBrushStep = value; }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 51167ca4da0b28040a7d5f7d97f77e86
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,32 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
internal enum SkinningMode
|
||||
{
|
||||
SpriteSheet,
|
||||
Character
|
||||
}
|
||||
|
||||
internal enum Tools
|
||||
{
|
||||
EditGeometry,
|
||||
CreateVertex,
|
||||
CreateEdge,
|
||||
SplitEdge,
|
||||
GenerateGeometry,
|
||||
EditPose,
|
||||
EditJoints,
|
||||
CreateBone,
|
||||
SplitBone,
|
||||
ReparentBone,
|
||||
WeightSlider,
|
||||
WeightBrush,
|
||||
GenerateWeights,
|
||||
BoneInfluence,
|
||||
CopyPaste,
|
||||
Visibility,
|
||||
SwitchMode
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3a361ade0d5860841861f16877a7a43d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,67 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
internal class SkinningEvents
|
||||
{
|
||||
public class SpriteEvent : UnityEvent<SpriteCache> {}
|
||||
public class SkeletonEvent : UnityEvent<SkeletonCache> {}
|
||||
public class MeshEvent : UnityEvent<MeshCache> {}
|
||||
public class MeshPreviewEvent : UnityEvent<MeshPreviewCache> {}
|
||||
public class SkinningModuleModeEvent : UnityEvent<SkinningMode> {}
|
||||
public class BoneSelectionEvent : UnityEvent {}
|
||||
public class BoneEvent : UnityEvent<BoneCache> {}
|
||||
public class CharacterPartEvent : UnityEvent<CharacterPartCache> {}
|
||||
public class ToolChangeEvent : UnityEvent<ITool> {}
|
||||
public class RestoreBindPoseEvent : UnityEvent {}
|
||||
public class CopyEvent : UnityEvent {}
|
||||
public class PasteEvent : UnityEvent<bool, bool, bool, bool> {}
|
||||
public class ShortcutEvent : UnityEvent<string> {}
|
||||
public class BoneVisibilityEvent : UnityEvent<string> {}
|
||||
public class SpriteLibraryEvent : UnityEvent {}
|
||||
public class MeshPreviewBehaviourChangeEvent : UnityEvent<IMeshPreviewBehaviour> {}
|
||||
|
||||
private SpriteEvent m_SelectedSpriteChanged = new SpriteEvent();
|
||||
private SkeletonEvent m_SkeletonPreviewPoseChanged = new SkeletonEvent();
|
||||
private SkeletonEvent m_SkeletonBindPoseChanged = new SkeletonEvent();
|
||||
private SkeletonEvent m_SkeletonTopologyChanged = new SkeletonEvent();
|
||||
private MeshEvent m_MeshChanged = new MeshEvent();
|
||||
private MeshPreviewEvent m_MeshPreviewChanged = new MeshPreviewEvent();
|
||||
private SkinningModuleModeEvent m_SkinningModuleModeChanged = new SkinningModuleModeEvent();
|
||||
private BoneSelectionEvent m_BoneSelectionChangedEvent = new BoneSelectionEvent();
|
||||
private BoneEvent m_BoneNameChangedEvent = new BoneEvent();
|
||||
private BoneEvent m_BoneDepthChangedEvent = new BoneEvent();
|
||||
private CharacterPartEvent m_CharacterPartChanged = new CharacterPartEvent();
|
||||
private ToolChangeEvent m_ToolChanged = new ToolChangeEvent();
|
||||
private RestoreBindPoseEvent m_RestoreBindPose = new RestoreBindPoseEvent();
|
||||
private CopyEvent m_CopyEvent = new CopyEvent();
|
||||
private PasteEvent m_PasteEvent = new PasteEvent();
|
||||
private ShortcutEvent m_ShortcutEvent = new ShortcutEvent();
|
||||
private BoneVisibilityEvent m_BoneVisibilityEvent = new BoneVisibilityEvent();
|
||||
private SpriteLibraryEvent m_SpriteLibraryEvent = new SpriteLibraryEvent();
|
||||
private MeshPreviewBehaviourChangeEvent m_MeshPreviewBehaviourChange = new MeshPreviewBehaviourChangeEvent();
|
||||
|
||||
//Setting them as virtual so that we can create mock them
|
||||
public virtual SpriteEvent selectedSpriteChanged { get { return m_SelectedSpriteChanged; } }
|
||||
public virtual SkeletonEvent skeletonPreviewPoseChanged { get { return m_SkeletonPreviewPoseChanged; } }
|
||||
public virtual SkeletonEvent skeletonBindPoseChanged { get { return m_SkeletonBindPoseChanged; } }
|
||||
public virtual SkeletonEvent skeletonTopologyChanged { get { return m_SkeletonTopologyChanged; } }
|
||||
public virtual MeshEvent meshChanged { get { return m_MeshChanged; } }
|
||||
public virtual MeshPreviewEvent meshPreviewChanged { get { return m_MeshPreviewChanged; } }
|
||||
public virtual SkinningModuleModeEvent skinningModeChanged { get { return m_SkinningModuleModeChanged; } }
|
||||
public virtual BoneSelectionEvent boneSelectionChanged { get { return m_BoneSelectionChangedEvent; } }
|
||||
public virtual BoneEvent boneNameChanged { get { return m_BoneNameChangedEvent; } }
|
||||
public virtual BoneEvent boneDepthChanged { get { return m_BoneDepthChangedEvent; } }
|
||||
public virtual CharacterPartEvent characterPartChanged { get { return m_CharacterPartChanged; } }
|
||||
public virtual ToolChangeEvent toolChanged { get { return m_ToolChanged; } }
|
||||
public virtual RestoreBindPoseEvent restoreBindPose { get { return m_RestoreBindPose; } }
|
||||
public virtual CopyEvent copy { get { return m_CopyEvent; } }
|
||||
public virtual PasteEvent paste { get { return m_PasteEvent; } }
|
||||
public virtual ShortcutEvent shortcut { get { return m_ShortcutEvent; } }
|
||||
public virtual BoneVisibilityEvent boneVisibility { get { return m_BoneVisibilityEvent; } }
|
||||
public virtual SpriteLibraryEvent spriteLibraryChanged { get { return m_SpriteLibraryEvent; } }
|
||||
public virtual MeshPreviewBehaviourChangeEvent meshPreviewBehaviourChange { get { return m_MeshPreviewBehaviourChange; } }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 39d177597cd8a914ab266d4dec677b74
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,44 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
internal class SpriteCache : TransformCache
|
||||
{
|
||||
[SerializeField]
|
||||
private string m_ID;
|
||||
[SerializeField]
|
||||
private Rect m_TextureRect;
|
||||
[SerializeField]
|
||||
private Vector2 m_PivotNormalized;
|
||||
|
||||
public string id
|
||||
{
|
||||
get { return m_ID; }
|
||||
internal set { m_ID = value; }
|
||||
}
|
||||
|
||||
public Rect textureRect
|
||||
{
|
||||
get { return m_TextureRect; }
|
||||
set { m_TextureRect = value; }
|
||||
}
|
||||
|
||||
public Vector2 pivotNormalized
|
||||
{
|
||||
get { return m_PivotNormalized; }
|
||||
set { m_PivotNormalized = value; }
|
||||
}
|
||||
|
||||
public Vector2 pivotRectSpace
|
||||
{
|
||||
get { return Vector2.Scale(textureRect.size, pivotNormalized); }
|
||||
}
|
||||
|
||||
public Vector2 pivotTextureSpace
|
||||
{
|
||||
get { return localToWorldMatrix.MultiplyPoint3x4(pivotRectSpace); }
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 10f309ec2a0fbf64e80346fdd64cb6b1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,325 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
internal static class SpriteCacheExtensions
|
||||
{
|
||||
public static MeshCache GetMesh(this SpriteCache sprite)
|
||||
{
|
||||
if (sprite != null)
|
||||
return sprite.skinningCache.GetMesh(sprite);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static MeshPreviewCache GetMeshPreview(this SpriteCache sprite)
|
||||
{
|
||||
if (sprite != null)
|
||||
return sprite.skinningCache.GetMeshPreview(sprite);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static SkeletonCache GetSkeleton(this SpriteCache sprite)
|
||||
{
|
||||
if (sprite != null)
|
||||
return sprite.skinningCache.GetSkeleton(sprite);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static CharacterPartCache GetCharacterPart(this SpriteCache sprite)
|
||||
{
|
||||
if (sprite != null)
|
||||
return sprite.skinningCache.GetCharacterPart(sprite);
|
||||
return null;
|
||||
}
|
||||
|
||||
public static bool IsVisible(this SpriteCache sprite)
|
||||
{
|
||||
var isVisible = true;
|
||||
var characterPart = sprite.GetCharacterPart();
|
||||
|
||||
if (sprite.skinningCache.mode == SkinningMode.Character && characterPart != null)
|
||||
isVisible = characterPart.isVisible;
|
||||
|
||||
return isVisible;
|
||||
}
|
||||
|
||||
public static Matrix4x4 GetLocalToWorldMatrixFromMode(this SpriteCache sprite)
|
||||
{
|
||||
var skinningCache = sprite.skinningCache;
|
||||
|
||||
if (skinningCache.mode == SkinningMode.SpriteSheet)
|
||||
return sprite.localToWorldMatrix;
|
||||
|
||||
var characterPart = sprite.GetCharacterPart();
|
||||
|
||||
Debug.Assert(characterPart != null);
|
||||
|
||||
return characterPart.localToWorldMatrix;
|
||||
}
|
||||
|
||||
public static BoneCache[] GetBonesFromMode(this SpriteCache sprite)
|
||||
{
|
||||
var skinningCache = sprite.skinningCache;
|
||||
|
||||
if (skinningCache.mode == SkinningMode.SpriteSheet)
|
||||
return sprite.GetSkeleton().bones;
|
||||
|
||||
var characterPart = sprite.GetCharacterPart();
|
||||
Debug.Assert(characterPart != null);
|
||||
return characterPart.bones;
|
||||
}
|
||||
|
||||
public static void UpdateMesh(this SpriteCache sprite, BoneCache[] bones)
|
||||
{
|
||||
var mesh = sprite.GetMesh();
|
||||
var previewMesh = sprite.GetMeshPreview();
|
||||
|
||||
Debug.Assert(mesh != null);
|
||||
Debug.Assert(previewMesh != null);
|
||||
|
||||
mesh.bones = bones;
|
||||
|
||||
previewMesh.SetWeightsDirty();
|
||||
}
|
||||
|
||||
public static void SmoothFill(this SpriteCache sprite)
|
||||
{
|
||||
var mesh = sprite.GetMesh();
|
||||
|
||||
if (mesh == null)
|
||||
return;
|
||||
|
||||
var controller = new SpriteMeshDataController();
|
||||
controller.spriteMeshData = mesh;
|
||||
controller.SmoothFill();
|
||||
}
|
||||
|
||||
public static void RestoreBindPose(this SpriteCache sprite)
|
||||
{
|
||||
var skinningCache = sprite.skinningCache;
|
||||
var skeleton = sprite.GetSkeleton();
|
||||
Debug.Assert(skeleton != null);
|
||||
skeleton.RestoreDefaultPose();
|
||||
skinningCache.events.skeletonPreviewPoseChanged.Invoke(skeleton);
|
||||
}
|
||||
|
||||
public static bool AssociateAllBones(this SpriteCache sprite)
|
||||
{
|
||||
var skinningCache = sprite.skinningCache;
|
||||
|
||||
if (skinningCache.mode == SkinningMode.SpriteSheet)
|
||||
return false;
|
||||
|
||||
var character = skinningCache.character;
|
||||
Debug.Assert(character != null);
|
||||
Debug.Assert(character.skeleton != null);
|
||||
|
||||
var characterPart = sprite.GetCharacterPart();
|
||||
|
||||
Debug.Assert(characterPart != null);
|
||||
|
||||
var bones = character.skeleton.bones.Where(x => x.isVisible).ToArray();
|
||||
characterPart.bones = bones;
|
||||
|
||||
characterPart.sprite.UpdateMesh(bones);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool AssociatePossibleBones(this SpriteCache sprite)
|
||||
{
|
||||
var skinningCache = sprite.skinningCache;
|
||||
|
||||
if (skinningCache.mode == SkinningMode.SpriteSheet)
|
||||
return false;
|
||||
|
||||
var character = skinningCache.character;
|
||||
Debug.Assert(character != null);
|
||||
Debug.Assert(character.skeleton != null);
|
||||
|
||||
var characterPart = sprite.GetCharacterPart();
|
||||
|
||||
Debug.Assert(characterPart != null);
|
||||
|
||||
var bones = character.skeleton.bones.Where(x => x.isVisible).ToArray();
|
||||
var possibleBones = new List<BoneCache>();
|
||||
// check if any of the bones overlapped
|
||||
BoneCache shortestBoneDistance = null;
|
||||
var minDistances = float.MaxValue;
|
||||
var characterSpriteRect = new Rect(characterPart.position.x , characterPart.position.y, characterPart.sprite.textureRect.width, characterPart.sprite.textureRect.height);
|
||||
foreach (var bone in bones)
|
||||
{
|
||||
var startPoint = bone.position;
|
||||
var endPoint = bone.endPosition;
|
||||
if (IntersectsSegment(characterSpriteRect, startPoint, endPoint))
|
||||
possibleBones.Add(bone);
|
||||
if (possibleBones.Count == 0)
|
||||
{
|
||||
// compare bone start end with rect's 4 line
|
||||
// compare rect point with bone line
|
||||
var points = new Vector2[] { startPoint, endPoint };
|
||||
var rectLinePoints = new []
|
||||
{
|
||||
new Vector2Int(0, 1),
|
||||
new Vector2Int(0, 2),
|
||||
new Vector2Int(1, 3),
|
||||
new Vector2Int(2, 3),
|
||||
};
|
||||
var rectPoints = new []
|
||||
{
|
||||
new Vector2(characterSpriteRect.xMin, characterSpriteRect.yMin),
|
||||
new Vector2(characterSpriteRect.xMin, characterSpriteRect.yMax),
|
||||
new Vector2(characterSpriteRect.xMax, characterSpriteRect.yMin),
|
||||
new Vector2(characterSpriteRect.xMax, characterSpriteRect.yMax)
|
||||
};
|
||||
foreach (var point in points)
|
||||
{
|
||||
foreach (var rectLine in rectLinePoints)
|
||||
{
|
||||
var distance = PointToLineSegmentDistance(point, rectPoints[rectLine.x], rectPoints[rectLine.y]);
|
||||
if (distance < minDistances)
|
||||
{
|
||||
minDistances = distance;
|
||||
shortestBoneDistance = bone;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var rectPoint in rectPoints)
|
||||
{
|
||||
var distance = PointToLineSegmentDistance(rectPoint, startPoint, endPoint);
|
||||
if (distance < minDistances)
|
||||
{
|
||||
minDistances = distance;
|
||||
shortestBoneDistance = bone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// if none overlapped, we use the bone that is closest to us
|
||||
if (possibleBones.Count == 0 && shortestBoneDistance != null)
|
||||
{
|
||||
possibleBones.Add(shortestBoneDistance);
|
||||
}
|
||||
characterPart.bones = possibleBones.ToArray();
|
||||
|
||||
characterPart.sprite.UpdateMesh(possibleBones.ToArray());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static float PointToLineSegmentDistance(Vector2 p, Vector2 a, Vector2 b)
|
||||
{
|
||||
Vector2 n = b - a;
|
||||
Vector2 pa = a - p;
|
||||
|
||||
float c = Vector2.Dot(n, pa);
|
||||
|
||||
// Closest point is a
|
||||
if (c > 0.0f)
|
||||
return Vector2.Dot(pa, pa);
|
||||
|
||||
Vector2 bp = p - b;
|
||||
|
||||
// Closest point is b
|
||||
if (Vector2.Dot(n, bp) > 0.0f)
|
||||
return Vector2.Dot(bp, bp);
|
||||
|
||||
// Closest point is between a and b
|
||||
Vector2 e = pa - n * (c / Vector2.Dot(n, n));
|
||||
return Vector2.Dot( e, e );
|
||||
}
|
||||
|
||||
static bool IntersectsSegment(Rect rect, Vector2 p1, Vector2 p2)
|
||||
{
|
||||
float minX = Mathf.Min(p1.x, p2.x);
|
||||
float maxX = Mathf.Max(p1.x, p2.x);
|
||||
|
||||
if (maxX > rect.xMax)
|
||||
{
|
||||
maxX = rect.xMax;
|
||||
}
|
||||
|
||||
if (minX < rect.xMin)
|
||||
{
|
||||
minX = rect.xMin;
|
||||
}
|
||||
|
||||
if (minX > maxX)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
float minY = Mathf.Min(p1.y, p2.y);
|
||||
float maxY = Mathf.Max(p1.y, p2.y);
|
||||
|
||||
float dx = p2.x - p1.x;
|
||||
|
||||
if (Mathf.Abs(dx) > float.Epsilon)
|
||||
{
|
||||
float a = (p2.y - p1.y) / dx;
|
||||
float b = p1.y - a * p1.x;
|
||||
minY = a * minX + b;
|
||||
maxY = a * maxX + b;
|
||||
}
|
||||
|
||||
if (minY > maxY)
|
||||
{
|
||||
float tmp = maxY;
|
||||
maxY = minY;
|
||||
minY = tmp;
|
||||
}
|
||||
|
||||
if (maxY > rect.yMax)
|
||||
{
|
||||
maxY = rect.yMax;
|
||||
}
|
||||
|
||||
if (minY < rect.yMin)
|
||||
{
|
||||
minY = rect.yMin;
|
||||
}
|
||||
|
||||
if (minY > maxY)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void DeassociateUnusedBones(this SpriteCache sprite)
|
||||
{
|
||||
var skinningCache = sprite.skinningCache;
|
||||
|
||||
Debug.Assert(skinningCache.mode == SkinningMode.Character);
|
||||
|
||||
var characterPart = sprite.GetCharacterPart();
|
||||
|
||||
Debug.Assert(characterPart != null);
|
||||
|
||||
characterPart.DeassociateUnusedBones();
|
||||
}
|
||||
|
||||
public static void DeassociateAllBones(this SpriteCache sprite)
|
||||
{
|
||||
var skinningCache = sprite.skinningCache;
|
||||
|
||||
if (skinningCache.mode == SkinningMode.SpriteSheet)
|
||||
return;
|
||||
|
||||
var part = sprite.GetCharacterPart();
|
||||
if (part.bones.Length == 0)
|
||||
return;
|
||||
|
||||
Debug.Assert(part.sprite != null);
|
||||
|
||||
part.bones = new BoneCache[0];
|
||||
part.sprite.UpdateMesh(part.bones);
|
||||
|
||||
skinningCache.events.characterPartChanged.Invoke(part);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 503b817aa45fa4a43abb42801b56b1e3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,287 @@
|
|||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
internal class TransformCache : SkinningObject, IEnumerable<TransformCache>
|
||||
{
|
||||
[SerializeField]
|
||||
private TransformCache m_Parent;
|
||||
[SerializeField]
|
||||
private List<TransformCache> m_Children = new List<TransformCache>();
|
||||
[SerializeField]
|
||||
private Vector3 m_LocalPosition;
|
||||
[SerializeField]
|
||||
private Quaternion m_LocalRotation = Quaternion.identity;
|
||||
[SerializeField]
|
||||
private Vector3 m_LocalScale = Vector3.one;
|
||||
[SerializeField]
|
||||
private Matrix4x4 m_LocalToWorldMatrix = Matrix4x4.identity;
|
||||
|
||||
public TransformCache parent
|
||||
{
|
||||
get { return m_Parent; }
|
||||
}
|
||||
|
||||
public TransformCache[] children
|
||||
{
|
||||
get { return m_Children.ToArray(); }
|
||||
}
|
||||
|
||||
internal virtual int siblingIndex
|
||||
{
|
||||
get { return GetSiblingIndex(); }
|
||||
set { SetSiblingIndex(value); }
|
||||
}
|
||||
|
||||
public int ChildCount
|
||||
{
|
||||
get { return m_Children.Count; }
|
||||
}
|
||||
|
||||
public Vector3 localPosition
|
||||
{
|
||||
get { return m_LocalPosition; }
|
||||
set
|
||||
{
|
||||
m_LocalPosition = value;
|
||||
Update();
|
||||
}
|
||||
}
|
||||
|
||||
public Quaternion localRotation
|
||||
{
|
||||
get { return m_LocalRotation; }
|
||||
set
|
||||
{
|
||||
m_LocalRotation = MathUtility.NormalizeQuaternion(value);
|
||||
Update();
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 localScale
|
||||
{
|
||||
get { return m_LocalScale; }
|
||||
set
|
||||
{
|
||||
m_LocalScale = value;
|
||||
Update();
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 position
|
||||
{
|
||||
get { return parentMatrix.MultiplyPoint3x4(localPosition); }
|
||||
set { localPosition = parentMatrix.inverse.MultiplyPoint3x4(value); }
|
||||
}
|
||||
|
||||
public Quaternion rotation
|
||||
{
|
||||
get { return GetGlobalRotation(); }
|
||||
set { SetGlobalRotation(value); }
|
||||
}
|
||||
|
||||
public Vector3 right
|
||||
{
|
||||
get { return localToWorldMatrix.MultiplyVector(Vector3.right).normalized; }
|
||||
set { MatchDirection(Vector3.right, value); }
|
||||
}
|
||||
|
||||
public Vector3 up
|
||||
{
|
||||
get { return localToWorldMatrix.MultiplyVector(Vector3.up).normalized; }
|
||||
set { MatchDirection(Vector3.up, value); }
|
||||
}
|
||||
|
||||
public Vector3 forward
|
||||
{
|
||||
get { return localToWorldMatrix.MultiplyVector(Vector3.forward).normalized; }
|
||||
set { MatchDirection(Vector3.forward, value); }
|
||||
}
|
||||
|
||||
public Matrix4x4 localToWorldMatrix
|
||||
{
|
||||
get { return m_LocalToWorldMatrix; }
|
||||
}
|
||||
|
||||
public Matrix4x4 worldToLocalMatrix
|
||||
{
|
||||
get { return localToWorldMatrix.inverse; }
|
||||
}
|
||||
|
||||
private Matrix4x4 parentMatrix
|
||||
{
|
||||
get
|
||||
{
|
||||
var parentMatrix = Matrix4x4.identity;
|
||||
|
||||
if (parent != null)
|
||||
parentMatrix = parent.localToWorldMatrix;
|
||||
|
||||
return parentMatrix;
|
||||
}
|
||||
}
|
||||
|
||||
internal override void OnDestroy()
|
||||
{
|
||||
if (parent != null)
|
||||
parent.RemoveChild(this);
|
||||
|
||||
m_Parent = null;
|
||||
m_Children.Clear();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
m_LocalToWorldMatrix = parentMatrix * Matrix4x4.TRS(localPosition, localRotation, localScale);
|
||||
|
||||
foreach (var child in m_Children)
|
||||
child.Update();
|
||||
}
|
||||
|
||||
private void AddChild(TransformCache transform)
|
||||
{
|
||||
m_Children.Add(transform);
|
||||
}
|
||||
|
||||
private void InsertChildAt(int index, TransformCache transform)
|
||||
{
|
||||
m_Children.Insert(index, transform);
|
||||
}
|
||||
|
||||
private void RemoveChild(TransformCache transform)
|
||||
{
|
||||
m_Children.Remove(transform);
|
||||
}
|
||||
|
||||
private void RemoveChildAt(int index)
|
||||
{
|
||||
m_Children.RemoveAt(index);
|
||||
}
|
||||
|
||||
private int GetSiblingIndex()
|
||||
{
|
||||
if (parent == null)
|
||||
return -1;
|
||||
|
||||
return parent.m_Children.IndexOf(this);
|
||||
}
|
||||
private void SetSiblingIndex(int index)
|
||||
{
|
||||
if (parent != null)
|
||||
{
|
||||
var currentIndex = parent.m_Children.IndexOf(this);
|
||||
var indexToRemove = index < currentIndex ? currentIndex + 1 : currentIndex;
|
||||
parent.InsertChildAt(index, this);
|
||||
parent.RemoveChildAt(indexToRemove);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetParent(TransformCache newParent)
|
||||
{
|
||||
SetParent(newParent, true);
|
||||
}
|
||||
|
||||
public void SetParent(TransformCache newParent, bool worldPositionStays)
|
||||
{
|
||||
if (m_Parent == newParent)
|
||||
return;
|
||||
|
||||
var oldPosition = position;
|
||||
var oldRotation = rotation;
|
||||
|
||||
if (m_Parent != null)
|
||||
m_Parent.RemoveChild(this);
|
||||
|
||||
m_Parent = newParent;
|
||||
|
||||
if (m_Parent != null)
|
||||
m_Parent.AddChild(this);
|
||||
|
||||
if (worldPositionStays)
|
||||
{
|
||||
position = oldPosition;
|
||||
rotation = oldRotation;
|
||||
}
|
||||
else
|
||||
{
|
||||
Update();
|
||||
}
|
||||
}
|
||||
|
||||
private Quaternion GetGlobalRotation()
|
||||
{
|
||||
var globalRotation = localRotation;
|
||||
var currentParent = parent;
|
||||
|
||||
while (currentParent != null)
|
||||
{
|
||||
globalRotation = ScaleMulQuat(currentParent.localScale, globalRotation);
|
||||
globalRotation = currentParent.localRotation * globalRotation;
|
||||
currentParent = currentParent.parent;
|
||||
}
|
||||
|
||||
return globalRotation;
|
||||
}
|
||||
|
||||
private void SetGlobalRotation(Quaternion r)
|
||||
{
|
||||
if (parent != null)
|
||||
r = parent.InverseTransformRotation(r);
|
||||
localRotation = r;
|
||||
}
|
||||
|
||||
private Quaternion InverseTransformRotation(Quaternion r)
|
||||
{
|
||||
if (parent != null)
|
||||
r = parent.InverseTransformRotation(r);
|
||||
|
||||
r = Quaternion.Inverse(localRotation) * r;
|
||||
r = ScaleMulQuat(localScale, r);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
private Quaternion ScaleMulQuat(Vector3 scale, Quaternion q)
|
||||
{
|
||||
var s = new Vector3(Chgsign(1f, scale.x), Chgsign(1f, scale.y), Chgsign(1f, scale.z));
|
||||
q.x = Chgsign(q.x, s.y * s.z);
|
||||
q.y = Chgsign(q.y, s.x * s.z);
|
||||
q.z = Chgsign(q.z, s.x * s.y);
|
||||
return q;
|
||||
}
|
||||
|
||||
private float Chgsign(float x, float y)
|
||||
{
|
||||
return y < 0f ? -x : x;
|
||||
}
|
||||
|
||||
private void MatchDirection(Vector3 localDirection, Vector3 worldDirection)
|
||||
{
|
||||
var direction = worldToLocalMatrix.MultiplyVector(worldDirection);
|
||||
direction = Matrix4x4.TRS(Vector3.zero, localRotation, localScale).MultiplyVector(direction);
|
||||
var scaledLocalDirection = Vector3.Scale(localDirection, localScale);
|
||||
var deltaRotation = Quaternion.identity;
|
||||
|
||||
if (scaledLocalDirection.sqrMagnitude > 0f)
|
||||
{
|
||||
var axis = Vector3.Cross(scaledLocalDirection, direction);
|
||||
var angle = Vector3.SignedAngle(scaledLocalDirection, direction, axis);
|
||||
deltaRotation = Quaternion.AngleAxis(angle, axis);
|
||||
}
|
||||
|
||||
localRotation = deltaRotation;
|
||||
}
|
||||
|
||||
IEnumerator<TransformCache> IEnumerable<TransformCache>.GetEnumerator()
|
||||
{
|
||||
return m_Children.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return (IEnumerator)m_Children.GetEnumerator();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a43eacb849c08fa47b752df4f2e05c7a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,43 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Animation
|
||||
{
|
||||
internal static class TransformCacheExtensions
|
||||
{
|
||||
internal static bool IsDescendant<T>(this T transform, T ancestor) where T : TransformCache
|
||||
{
|
||||
if (ancestor != null)
|
||||
{
|
||||
var parent = transform.parent;
|
||||
|
||||
while (parent != null)
|
||||
{
|
||||
if (parent == ancestor)
|
||||
return true;
|
||||
|
||||
parent = parent.parent;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
internal static bool IsDescendant<T>(this T transform, T[] ancestors) where T : TransformCache
|
||||
{
|
||||
return ancestors.FirstOrDefault( t => transform.IsDescendant<T>(t) ) != null;
|
||||
}
|
||||
|
||||
internal static T[] FindRoots<T>(this T[] transforms) where T : TransformCache
|
||||
{
|
||||
return transforms.Where(t => t.IsDescendant(transforms) == false).ToArray();
|
||||
}
|
||||
|
||||
internal static T FindRoot<T>(this T transform, T[] transforms) where T : TransformCache
|
||||
{
|
||||
var roots = transforms.FindRoots<T>();
|
||||
return roots.FirstOrDefault( r => transform == r || IsDescendant<T>(transform, r) );
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 51ee03bc936f1bf4489c0ee8696ebab7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue