123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505 |
- #pragma warning disable 0168 // variable declared but not used.
- #if ENABLE_ANIMATION_COLLECTION && ENABLE_ANIMATION_BURST
- #define ENABLE_SPRITESKIN_COMPOSITE
- #endif
-
- using System;
- using System.Collections.Generic;
- using UnityEngine.Scripting;
- using UnityEngine.U2D.Common;
- using Unity.Collections;
- using UnityEngine.Rendering;
- using UnityEngine.Scripting.APIUpdating;
-
- namespace UnityEngine.U2D.Animation
- {
- /// <summary>
- /// Represents vertex position.
- /// </summary>
- public struct PositionVertex
- {
- /// <summary>
- /// Vertex position.
- /// </summary>
- public Vector3 position;
- }
-
- /// <summary>
- /// Represents vertex position and tangent.
- /// </summary>
- public struct PositionTangentVertex
- {
- /// <summary>
- /// Vertex position.
- /// </summary>
- public Vector3 position;
-
- /// <summary>
- /// Vertex tangent.
- /// </summary>
- public Vector4 tangent;
- }
-
- /// <summary>
- /// Deforms the Sprite that is currently assigned to the SpriteRenderer in the same GameObject
- /// </summary>
- [Preserve]
- [ExecuteInEditMode]
- [DefaultExecutionOrder(-1)]
- [DisallowMultipleComponent]
- [RequireComponent(typeof(SpriteRenderer))]
- [AddComponentMenu("2D Animation/Sprite Skin")]
- [MovedFrom("UnityEngine.U2D.Experimental.Animation")]
- [HelpURL("https://docs.unity3d.com/Packages/com.unity.2d.animation@7.0/manual/SpriteSkin.html")]
- public sealed partial class SpriteSkin : MonoBehaviour, ISerializationCallbackReceiver
- {
- [SerializeField]
- private Transform m_RootBone;
- [SerializeField]
- private Transform[] m_BoneTransforms = new Transform[0];
- [SerializeField]
- private Bounds m_Bounds;
- [SerializeField]
- private bool m_UseBatching = true;
- [SerializeField]
- private bool m_AlwaysUpdate = true;
- [SerializeField]
- private bool m_AutoRebind = false;
-
- // The deformed m_SpriteVertices stores all 'HOT' channels only in single-stream and essentially depends on Sprite Asset data.
- // The order of storage if present is POSITION, NORMALS, TANGENTS.
- private NativeByteArray m_DeformedVertices;
- private int m_CurrentDeformVerticesLength = 0;
- private SpriteRenderer m_SpriteRenderer;
- private int m_CurrentDeformSprite = 0;
- private bool m_ForceSkinning;
- private bool m_BatchSkinning = false;
- bool m_IsValid = false;
- int m_TransformsHash = 0;
-
- internal bool batchSkinning
- {
- get { return m_BatchSkinning; }
- set { m_BatchSkinning = value; }
- }
-
- internal bool autoRebind
- {
- get => m_AutoRebind;
- set
- {
- m_AutoRebind = value;
- CacheCurrentSprite(m_AutoRebind);
- }
-
- }
-
- #if UNITY_EDITOR
- internal static Events.UnityEvent onDrawGizmos = new Events.UnityEvent();
- private void OnDrawGizmos() { onDrawGizmos.Invoke(); }
-
- private bool m_IgnoreNextSpriteChange = true;
- internal bool ignoreNextSpriteChange
- {
- get { return m_IgnoreNextSpriteChange; }
- set { m_IgnoreNextSpriteChange = value; }
- }
- #endif
-
- private int GetSpriteInstanceID()
- {
- return sprite != null ? sprite.GetInstanceID() : 0;
- }
-
- internal void Awake()
- {
- m_SpriteRenderer = GetComponent<SpriteRenderer>();
- }
-
- void OnEnable()
- {
- Awake();
- m_TransformsHash = 0;
- CacheCurrentSprite(false);
- OnEnableBatch();
- }
-
- internal void OnEditorEnable()
- {
- Awake();
- }
-
- void CacheValidFlag()
- {
- m_IsValid = isValid;
- if(!m_IsValid)
- DeactivateSkinning();
- }
-
- void Reset()
- {
- Awake();
- if (isActiveAndEnabled)
- {
- CacheValidFlag();
- OnResetBatch();
- }
- }
-
- internal void UseBatching(bool value)
- {
- if (m_UseBatching != value)
- {
- m_UseBatching = value;
- UseBatchingBatch();
- }
- }
-
- internal NativeByteArray GetDeformedVertices(int spriteVertexCount)
- {
- if (sprite != null)
- {
- if (m_CurrentDeformVerticesLength != spriteVertexCount)
- {
- m_TransformsHash = 0;
- m_CurrentDeformVerticesLength = spriteVertexCount;
- }
- }
- else
- {
- m_CurrentDeformVerticesLength = 0;
- }
-
- m_DeformedVertices = BufferManager.instance.GetBuffer(GetInstanceID(), m_CurrentDeformVerticesLength);
- return m_DeformedVertices;
- }
-
- /// <summary>
- /// Returns whether this SpriteSkin has currently deformed vertices.
- /// </summary>
- /// <returns>Returns true if this SpriteSkin has currently deformed vertices. Returns false otherwise.</returns>
- public bool HasCurrentDeformedVertices()
- {
- if (!m_IsValid)
- return false;
-
- #if ENABLE_SPRITESKIN_COMPOSITE
- return m_DataIndex >= 0 && SpriteSkinComposite.instance.HasDeformableBufferForSprite(m_DataIndex);
- #else
- return m_CurrentDeformVerticesLength > 0 && m_DeformedVertices.IsCreated;
- #endif
- }
-
- /// <summary>
- /// Gets a byte array to the currently deformed vertices for this SpriteSkin.
- /// </summary>
- /// <returns>Returns a reference to the currently deformed vertices. This is valid only for this calling frame.</returns>
- /// <exception cref="InvalidOperationException">Thrown when there are no currently deformed vertices</exception>
- internal NativeArray<byte> GetCurrentDeformedVertices()
- {
- if (!m_IsValid)
- throw new InvalidOperationException("The SpriteSkin deformation is not valid.");
-
- #if ENABLE_SPRITESKIN_COMPOSITE
- if (m_DataIndex < 0)
- {
- throw new InvalidOperationException("There are no currently deformed vertices.");
- }
- return SpriteSkinComposite.instance.GetDeformableBufferForSprite(m_DataIndex);
- #else
- if (m_CurrentDeformVerticesLength <= 0)
- throw new InvalidOperationException("There are no currently deformed vertices.");
- if (!m_DeformedVertices.IsCreated)
- throw new InvalidOperationException("There are no currently deformed vertices.");
- return m_DeformedVertices.array;
- #endif
- }
-
- /// <summary>
- /// Gets an array of currently deformed position vertices for this SpriteSkin.
- /// </summary>
- /// <returns>Returns a reference to the currently deformed vertices. This is valid only for this calling frame.</returns>
- /// <exception cref="InvalidOperationException">
- /// Thrown when there are no currently deformed vertices or if the deformed vertices does not contain only
- /// position data.
- /// </exception>
- internal NativeSlice<PositionVertex> GetCurrentDeformedVertexPositions()
- {
- if (sprite.HasVertexAttribute(VertexAttribute.Tangent))
- throw new InvalidOperationException("This SpriteSkin has deformed tangents");
- if (!sprite.HasVertexAttribute(VertexAttribute.Position))
- throw new InvalidOperationException("This SpriteSkin does not have deformed positions.");
-
- var deformedBuffer = GetCurrentDeformedVertices();
- return deformedBuffer.Slice().SliceConvert<PositionVertex>();
- }
-
- /// <summary>
- /// Gets an array of currently deformed position and tangent vertices for this SpriteSkin.
- /// </summary>
- /// <returns>
- /// Returns a reference to the currently deformed position and tangent vertices. This is valid only for this calling frame.
- /// </returns>
- /// <exception cref="InvalidOperationException">
- /// Thrown when there are no currently deformed vertices or if the deformed vertices does not contain only
- /// position and tangent data.
- /// </exception>
- internal NativeSlice<PositionTangentVertex> GetCurrentDeformedVertexPositionsAndTangents()
- {
- if (!sprite.HasVertexAttribute(VertexAttribute.Tangent))
- throw new InvalidOperationException("This SpriteSkin does not have deformed tangents");
- if (!sprite.HasVertexAttribute(VertexAttribute.Position))
- throw new InvalidOperationException("This SpriteSkin does not have deformed positions.");
-
- var deformedBuffer = GetCurrentDeformedVertices();
- return deformedBuffer.Slice().SliceConvert<PositionTangentVertex>();
- }
-
- /// <summary>
- /// Gets an enumerable to iterate through all deformed vertex positions of this SpriteSkin.
- /// </summary>
- /// <returns>Returns an IEnumerable to deformed vertex positions.</returns>
- /// <exception cref="InvalidOperationException">Thrown when there is no vertex positions or deformed vertices.</exception>
- public IEnumerable<Vector3> GetDeformedVertexPositionData()
- {
- bool hasPosition = sprite.HasVertexAttribute(Rendering.VertexAttribute.Position);
- if (!hasPosition)
- throw new InvalidOperationException("Sprite does not have vertex position data.");
-
- var rawBuffer = GetCurrentDeformedVertices();
- var rawSlice = rawBuffer.Slice(sprite.GetVertexStreamOffset(VertexAttribute.Position));
- return new NativeCustomSliceEnumerator<Vector3>(rawSlice, sprite.GetVertexCount(), sprite.GetVertexStreamSize());
- }
-
- /// <summary>
- /// Gets an enumerable to iterate through all deformed vertex tangents of this SpriteSkin.
- /// </summary>
- /// <returns>Returns an IEnumerable to deformed vertex tangents.</returns>
- /// <exception cref="InvalidOperationException">Thrown when there is no vertex tangents or deformed vertices.</exception>
- public IEnumerable<Vector4> GetDeformedVertexTangentData()
- {
- bool hasTangent = sprite.HasVertexAttribute(Rendering.VertexAttribute.Tangent);
- if (!hasTangent)
- throw new InvalidOperationException("Sprite does not have vertex tangent data.");
-
- var rawBuffer = GetCurrentDeformedVertices();
- var rawSlice = rawBuffer.Slice(sprite.GetVertexStreamOffset(VertexAttribute.Tangent));
- return new NativeCustomSliceEnumerator<Vector4>(rawSlice, sprite.GetVertexCount(), sprite.GetVertexStreamSize());
- }
-
- void OnDisable()
- {
- DeactivateSkinning();
- BufferManager.instance.ReturnBuffer(GetInstanceID());
- OnDisableBatch();
- }
-
- #if ENABLE_SPRITESKIN_COMPOSITE
- internal void OnLateUpdate()
- #else
- void LateUpdate()
- #endif
- {
- CacheCurrentSprite(m_AutoRebind);
- if (isValid && !batchSkinning && this.enabled && (this.alwaysUpdate || this.spriteRenderer.isVisible))
- {
- var transformHash = SpriteSkinUtility.CalculateTransformHash(this);
- var spriteVertexCount = sprite.GetVertexStreamSize() * sprite.GetVertexCount();
- if (spriteVertexCount > 0 && m_TransformsHash != transformHash)
- {
- var inputVertices = GetDeformedVertices(spriteVertexCount);
- SpriteSkinUtility.Deform(sprite, gameObject.transform.worldToLocalMatrix, boneTransforms, inputVertices.array);
- SpriteSkinUtility.UpdateBounds(this, inputVertices.array);
- InternalEngineBridge.SetDeformableBuffer(spriteRenderer, inputVertices.array);
- m_TransformsHash = transformHash;
- m_CurrentDeformSprite = GetSpriteInstanceID();
- }
- }
- else if(!InternalEngineBridge.IsUsingDeformableBuffer(spriteRenderer, IntPtr.Zero))
- {
- DeactivateSkinning();
- }
- }
-
- void CacheCurrentSprite(bool rebind)
- {
- if (m_CurrentDeformSprite != GetSpriteInstanceID())
- {
- DeactivateSkinning();
- m_CurrentDeformSprite = GetSpriteInstanceID();
- if (rebind && m_CurrentDeformSprite > 0 && rootBone != null)
- {
- var spriteBones = sprite.GetBones();
- var transforms = new Transform[spriteBones.Length];
- if (GetSpriteBonesTransforms(spriteBones, rootBone, transforms))
- boneTransforms = transforms;
- }
- UpdateSpriteDeform();
- CacheValidFlag();
- m_TransformsHash = 0;
- }
- }
-
- internal Sprite sprite => spriteRenderer.sprite;
-
- internal SpriteRenderer spriteRenderer => m_SpriteRenderer;
-
- /// <summary>
- /// Returns the Transform Components that is used for deformation.
- /// Do not modify elements of the returned array.
- /// </summary>
- /// <returns>An array of Transform Components.</returns>
- public Transform[] boneTransforms
- {
- get { return m_BoneTransforms; }
- internal set
- {
- m_BoneTransforms = value;
- CacheValidFlag();
- OnBoneTransformChanged();
- }
- }
-
- /// <summary>
- /// Returns the Transform Component that represents the root bone for deformation
- /// </summary>
- /// <returns>A Transform Component</returns>
- public Transform rootBone
- {
- get { return m_RootBone; }
- internal set
- {
- m_RootBone = value;
- CacheValidFlag();
- OnRootBoneTransformChanged();
- }
- }
-
- internal Bounds bounds
- {
- get { return m_Bounds; }
- set { m_Bounds = value; }
- }
-
- /// <summary>
- /// Determines if the SpriteSkin executes even if the associated
- /// SpriteRenderer has been culled from view.
- /// </summary>
- public bool alwaysUpdate
- {
- get => m_AlwaysUpdate;
- set => m_AlwaysUpdate = value;
- }
-
- internal static bool GetSpriteBonesTransforms(SpriteBone[] spriteBones, Transform rootBone, Transform[] outTransform)
- {
- if(rootBone == null)
- throw new ArgumentException("rootBone parameter cannot be null");
- if(spriteBones == null)
- throw new ArgumentException("spritebone parameter cannot be null");
- if(outTransform == null)
- throw new ArgumentException("outTransform parameter cannot be null");
- if(spriteBones.Length != outTransform.Length)
- throw new ArgumentException("spritebone and outTransform array length must be the same");
-
- var boneObjects = rootBone.GetComponentsInChildren<Bone>();
- if (boneObjects != null && boneObjects.Length >= spriteBones.Length)
- {
- int i = 0;
- for (; i < spriteBones.Length; ++i)
- {
- var boneHash = spriteBones[i].guid;
- var boneTransform = Array.Find(boneObjects, x => (x.guid == boneHash));
- if (boneTransform == null)
- break;
-
- outTransform[i] = boneTransform.transform;
- }
- if(i >= spriteBones.Length)
- return true;
- }
-
- // If unable to successfuly map via guid, fall back to path
- return GetSpriteBonesTranformFromPath(spriteBones, rootBone, outTransform);
- }
-
-
- static bool GetSpriteBonesTranformFromPath(SpriteBone[] spriteBones, Transform rootBone, Transform[] outNewBoneTransform)
- {
- var bonePath = new string[spriteBones.Length];
- for (int i = 0; i < spriteBones.Length; ++i)
- {
- if (bonePath[i] == null)
- CalculateBoneTransformsPath(i, spriteBones, bonePath);
- if (rootBone.name == spriteBones[i].name)
- outNewBoneTransform[i] = rootBone;
- else
- {
- var bone = rootBone.Find(bonePath[i]);
- if (bone == null)
- return false;
- outNewBoneTransform[i] = bone;
- }
- }
-
- return true;
- }
-
- private static void CalculateBoneTransformsPath(int index, SpriteBone[] spriteBones, string[] paths)
- {
- var spriteBone = spriteBones[index];
- var parentId = spriteBone.parentId;
- var bonePath = spriteBone.name;
- if (parentId != -1 && spriteBones[parentId].parentId != -1)
- {
- if (paths[parentId] == null)
- CalculateBoneTransformsPath(spriteBone.parentId, spriteBones, paths);
- paths[index] = string.Format("{0}/{1}", paths[parentId], bonePath);
- }
- else
- paths[index] = bonePath;
- }
-
- internal bool isValid
- {
- get { return this.Validate() == SpriteSkinValidationResult.Ready; }
- }
-
- void OnDestroy()
- {
- DeactivateSkinning();
- }
-
- internal void DeactivateSkinning()
- {
- var sprite = spriteRenderer.sprite;
- if (sprite != null)
- InternalEngineBridge.SetLocalAABB(spriteRenderer, sprite.bounds);
-
- spriteRenderer.DeactivateDeformableBuffer();
- m_TransformsHash = 0;
- }
-
- internal void ResetSprite()
- {
- m_CurrentDeformSprite = 0;
- CacheValidFlag();
- }
-
- /// <summary>
- /// Called before object is serialized.
- /// </summary>
- public void OnBeforeSerialize()
- {
- OnBeforeSerializeBatch();
- }
-
- /// <summary>
- /// Called after object is deserialized.
- /// </summary>
- public void OnAfterDeserialize()
- {
- OnAfterSerializeBatch();
- }
- }
- }
|