#pragma warning disable 0168 // variable declared but not used. using System; using System.Collections.Generic; using System.Runtime.CompilerServices; using UnityEngine.Scripting; using UnityEngine.U2D.Common; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Profiling; using UnityEngine.Rendering; using UnityEngine.Scripting.APIUpdating; namespace UnityEngine.U2D.Animation { /// /// Represents vertex position. /// internal struct PositionVertex { /// /// Vertex position. /// public Vector3 position; } /// /// Represents vertex position and tangent. /// internal struct PositionTangentVertex { /// /// Vertex position. /// public Vector3 position; /// /// Vertex tangent. /// public Vector4 tangent; } /// /// The state of the Sprite Skin. /// public enum SpriteSkinState { /// /// Sprite Renderer doesn't contain a sprite. /// SpriteNotFound, /// /// Sprite referenced in the Sprite Renderer doesn't have skinning information. /// SpriteHasNoSkinningInformation, /// /// Sprite referenced in the Sprite Renderer doesn't have weights. /// SpriteHasNoWeights, /// /// Root transform is not assigned. /// RootTransformNotFound, /// /// Bone transform array is not assigned. /// InvalidTransformArray, /// /// Bone transform array has incorrect length. /// InvalidTransformArrayLength, /// /// One or more bone transforms is not assigned. /// TransformArrayContainsNull, /// /// Bone weights are invalid. /// InvalidBoneWeights, /// /// Sprite Skin is ready for deformation. /// Ready } /// /// Deforms the Sprite that is currently assigned to the SpriteRenderer in the same GameObject. /// [Preserve] [ExecuteInEditMode] [DefaultExecutionOrder(UpdateOrder.spriteSkinUpdateOrder)] [DisallowMultipleComponent] [RequireComponent(typeof(SpriteRenderer))] [AddComponentMenu("2D Animation/Sprite Skin")] [IconAttribute(IconUtility.IconPath + "Animation.SpriteSkin.png")] [MovedFrom("UnityEngine.U2D.Experimental.Animation")] [HelpURL("https://docs.unity3d.com/Packages/com.unity.2d.animation@latest/index.html?subfolder=/manual/SpriteSkin.html")] public sealed class SpriteSkin : MonoBehaviour, IPreviewable, ISerializationCallbackReceiver { internal static class Profiling { public static readonly ProfilerMarker cacheCurrentSprite = new ProfilerMarker("SpriteSkin.CacheCurrentSprite"); public static readonly ProfilerMarker cacheHierarchy = new ProfilerMarker("SpriteSkin.CacheHierarchy"); public static readonly ProfilerMarker getSpriteBonesTransformFromGuid = new ProfilerMarker("SpriteSkin.GetSpriteBoneTransformsFromGuid"); public static readonly ProfilerMarker getSpriteBonesTransformFromPath = new ProfilerMarker("SpriteSkin.GetSpriteBoneTransformsFromPath"); } internal struct TransformData { public string fullName; public Transform transform; } [SerializeField] Transform m_RootBone; [SerializeField] Transform[] m_BoneTransforms = Array.Empty(); [SerializeField] Bounds m_Bounds; [SerializeField] bool m_AlwaysUpdate = true; [SerializeField] 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. NativeByteArray m_DeformedVertices; int m_CurrentDeformVerticesLength = 0; SpriteRenderer m_SpriteRenderer; int m_CurrentDeformSprite = 0; int m_SpriteId = -1; bool m_IsValid = false; SpriteSkinState m_State; int m_TransformsHash = 0; bool m_ForceCpuDeformation = false; int m_TransformId; NativeArray m_BoneTransformId; int m_RootBoneTransformId; NativeCustomSlice m_SpriteUVs; NativeCustomSlice m_SpriteVertices; NativeCustomSlice m_SpriteTangents; NativeCustomSlice m_SpriteBoneWeights; NativeCustomSlice m_SpriteBindPoses; NativeCustomSlice m_BoneTransformIdNativeSlice; bool m_SpriteHasTangents; int m_SpriteVertexStreamSize; int m_SpriteVertexCount; int m_SpriteTangentVertexOffset; int m_DataIndex = -1; bool m_BoneCacheUpdateToDate = false; internal Dictionary> m_HierarchyCache = new Dictionary>(); NativeArray m_OutlineIndexCache; NativeArray m_StaticOutlineVertexCache; NativeArray m_DeformedOutlineVertexCache; int m_VertexDeformationHash = 0; Sprite m_Sprite; internal NativeArray boneTransformId => m_BoneTransformId; internal int rootBoneTransformId => m_RootBoneTransformId; internal DeformationMethods currentDeformationMethod { get; private set; } internal BaseDeformationSystem deformationSystem { get; private set; } #if ENABLE_URP /// /// Returns an array of the outline indices. /// The indices are sorted and laid out with line topology. /// internal NativeArray outlineIndices => m_OutlineIndexCache; /// /// Returns an array of the deformed outline vertices. /// internal NativeArray outlineVertices => m_DeformedOutlineVertexCache; #endif /// /// Returns a hash which is updated every time the mesh is deformed. /// internal int vertexDeformationHash => m_VertexDeformationHash; internal Sprite sprite => m_Sprite; internal SpriteRenderer spriteRenderer => m_SpriteRenderer; internal NativeCustomSlice spriteBoneWeights => m_SpriteBoneWeights; /// /// Gets the index of the SpriteSkin in the SpriteSkinComposite. /// internal int dataIndex => m_DataIndex; /// /// Get and set the Auto Rebind property. /// When enabled, Sprite Skin attempts to automatically locate the Transform that is needed for the current Sprite assigned to the Sprite Renderer. /// public bool autoRebind { get => m_AutoRebind; set { m_AutoRebind = value; if (isActiveAndEnabled) { CacheHierarchy(); CacheCurrentSprite(m_AutoRebind); } } } /// /// Returns the Transform Components that are used for deformation. /// Do not modify elements of the returned array. /// /// An array of Transform Components. public Transform[] boneTransforms => m_BoneTransforms; /// /// Sets the Transform Components that are used for deformation. /// /// Array of new bone Transforms. /// The state of the Sprite Skin. public SpriteSkinState SetBoneTransforms(Transform[] boneTransformsArray) { m_BoneTransforms = boneTransformsArray; var result = CacheValidFlag(); if (isActiveAndEnabled) OnBoneTransformChanged(); return result; } /// /// Returns the Transform Component that represents the root bone for deformation. /// /// A Transform Component. public Transform rootBone => m_RootBone; /// /// Sets the Transform Component that represents the root bone for deformation. /// /// Root bone Transform Component. /// The state of the Sprite Skin. public SpriteSkinState SetRootBone(Transform rootBoneTransform) { m_RootBone = rootBoneTransform; var result = CacheValidFlag(); if (isActiveAndEnabled) { CacheHierarchy(); OnRootBoneTransformChanged(); } return result; } internal Bounds bounds { get => m_Bounds; set => m_Bounds = value; } /// /// Determines if the SpriteSkin executes even if the associated /// SpriteRenderer has been culled from view. /// public bool alwaysUpdate { get => m_AlwaysUpdate; set => m_AlwaysUpdate = value; } /// /// Always run a deformation pass on the CPU.
/// If GPU deformation is enabled, enabling forceCpuDeformation will cause the deformation to run twice, one time on the CPU and one time on the GPU. ///
public bool forceCpuDeformation { get => m_ForceCpuDeformation; set { if (m_ForceCpuDeformation == value) return; m_ForceCpuDeformation = value; if (isActiveAndEnabled) { UpdateSpriteDeformationData(); DeformationManager.instance.CopyToSpriteSkinData(this); } } } /// /// Resets the bone transforms to the bind pose. /// /// True if successful. public bool ResetBindPose() { if (!isValid) return false; var spriteBones = spriteRenderer.sprite.GetBones(); for (var i = 0; i < boneTransforms.Length; ++i) { var boneTransform = boneTransforms[i]; var spriteBone = spriteBones[i]; if (spriteBone.parentId != -1) { boneTransform.localPosition = spriteBone.position; boneTransform.localRotation = spriteBone.rotation; boneTransform.localScale = Vector3.one; } } return true; } internal bool isValid => this.Validate() == SpriteSkinState.Ready; #if UNITY_EDITOR internal static Events.UnityEvent onDrawGizmos = new Events.UnityEvent(); void OnDrawGizmos() => onDrawGizmos.Invoke(); internal bool ignoreNextSpriteChange { get; set; } = true; #endif internal void Awake() { m_SpriteRenderer = GetComponent(); m_Sprite = m_SpriteRenderer.sprite; m_SpriteId = m_Sprite != null ? m_Sprite.GetInstanceID() : 0; } void OnEnable() { m_TransformId = gameObject.transform.GetInstanceID(); m_TransformsHash = 0; currentDeformationMethod = SpriteSkinUtility.CanSpriteSkinUseGpuDeformation(this) ? DeformationMethods.Gpu : DeformationMethods.Cpu; Awake(); CacheCurrentSprite(false); UpdateSpriteDeformationData(); if (m_HierarchyCache.Count == 0) CacheHierarchy(); RefreshBoneTransforms(); DeformationManager.instance.AddSpriteSkin(this); SpriteSkinContainer.instance.AddSpriteSkin(this); m_SpriteRenderer.RegisterSpriteChangeCallback(OnSpriteChanged); } void OnDisable() { DeactivateSkinning(); BufferManager.instance.ReturnBuffer(GetInstanceID()); deformationSystem?.RemoveSpriteSkin(this); deformationSystem = null; SpriteSkinContainer.instance.RemoveSpriteSkin(this); ResetBoneTransformIdCache(); DisposeOutlineCaches(); } void RefreshBoneTransforms() { DeformationManager.instance.RemoveBoneTransforms(this); CacheBoneTransformIds(); DeformationManager.instance.AddSpriteSkinBoneTransform(this); CacheValidFlag(); DeformationManager.instance.CopyToSpriteSkinData(this); } void OnSpriteChanged(SpriteRenderer updatedSpriteRenderer) { m_Sprite = updatedSpriteRenderer.sprite; m_SpriteId = m_Sprite != null ? m_Sprite.GetInstanceID() : 0; } void CacheBoneTransformIds() { m_BoneCacheUpdateToDate = true; var boneCount = 0; for (var i = 0; i < boneTransforms?.Length; ++i) { if (boneTransforms[i] != null) ++boneCount; } if (m_BoneTransformId != default && m_BoneTransformId.IsCreated) NativeArrayHelpers.ResizeIfNeeded(ref m_BoneTransformId, boneCount); else m_BoneTransformId = new NativeArray(boneCount, Allocator.Persistent); m_RootBoneTransformId = rootBone != null ? rootBone.GetInstanceID() : 0; m_BoneTransformIdNativeSlice = new NativeCustomSlice(m_BoneTransformId); for (int i = 0, j = 0; i < boneTransforms?.Length; ++i) { if (boneTransforms[i] != null) { m_BoneTransformId[j] = boneTransforms[i].GetInstanceID(); ++j; } } } void OnBoneTransformChanged() { RefreshBoneTransforms(); SpriteSkinContainer.instance.BoneTransformsChanged(this); } void OnRootBoneTransformChanged() { RefreshBoneTransforms(); SpriteSkinContainer.instance.BoneTransformsChanged(this); } /// /// Called before object is serialized. /// public void OnBeforeSerialize() { OnBeforeSerializeBatch(); } /// /// Called after object is deserialized. /// public void OnAfterDeserialize() { OnAfterSerializeBatch(); } void OnBeforeSerializeBatch() { } void OnAfterSerializeBatch() { #if UNITY_EDITOR m_BoneCacheUpdateToDate = false; #endif } internal void OnEditorEnable() { Awake(); } SpriteSkinState CacheValidFlag() { m_State = this.Validate(); m_IsValid = m_State == SpriteSkinState.Ready; if (!m_IsValid) DeactivateSkinning(); return m_State; } internal bool BatchValidate() { if (!m_BoneCacheUpdateToDate) { RefreshBoneTransforms(); } CacheCurrentSprite(m_AutoRebind); var hasSprite = m_CurrentDeformSprite != 0; return m_IsValid && hasSprite && m_SpriteRenderer.enabled && (alwaysUpdate || m_SpriteRenderer.isVisible); } void Reset() { Awake(); if (isActiveAndEnabled) { CacheValidFlag(); if (!m_BoneCacheUpdateToDate) { RefreshBoneTransforms(); } DeformationManager.instance.CopyToSpriteSkinData(this); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] void ResetBoneTransformIdCache() { m_BoneTransformId.DisposeIfCreated(); m_BoneTransformId = default; m_RootBoneTransformId = -1; m_BoneCacheUpdateToDate = false; } 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; } /// /// Returns whether this SpriteSkin has currently deformed vertices. /// /// Returns true if this SpriteSkin has currently deformed vertices. Returns false otherwise. public bool HasCurrentDeformedVertices() { if (!m_IsValid) return false; return m_DataIndex >= 0 && deformationSystem != null && deformationSystem.IsSpriteSkinActiveForDeformation(this); } /// /// Gets a byte array to the currently deformed vertices for this SpriteSkin. /// /// Returns a reference to the currently deformed vertices. This is valid only for this calling frame. /// /// Thrown when there are no currently deformed vertices. /// HasCurrentDeformedVertices can be used to verify if there are any deformed vertices available. /// internal NativeArray GetCurrentDeformedVertices() { if (!m_IsValid) throw new InvalidOperationException("The SpriteSkin deformation is not valid."); if (m_DataIndex < 0) throw new InvalidOperationException("There are no currently deformed vertices."); var buffer = deformationSystem?.GetDeformableBufferForSpriteSkin(this) ?? default; if (buffer == default) throw new InvalidOperationException("There are no currently deformed vertices."); return buffer; } /// /// Gets an array of currently deformed position vertices for this SpriteSkin. /// /// Returns a reference to the currently deformed vertices. This is valid only for this calling frame. /// /// Thrown when there are no currently deformed vertices or if the deformed vertices does not contain only /// position data. HasCurrentDeformedVertices can be used to verify if there are any deformed vertices available. /// internal NativeSlice GetCurrentDeformedVertexPositions() { if (!m_IsValid) throw new InvalidOperationException("The SpriteSkin deformation is not valid."); 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(); } /// /// Gets an array of currently deformed position and tangent vertices for this SpriteSkin. /// /// /// Returns a reference to the currently deformed position and tangent vertices. This is valid only for this calling frame. /// /// /// Thrown when there are no currently deformed vertices or if the deformed vertices does not contain only /// position and tangent data. HasCurrentDeformedVertices can be used to verify if there are any deformed vertices available. /// internal NativeSlice GetCurrentDeformedVertexPositionsAndTangents() { if (!m_IsValid) throw new InvalidOperationException("The SpriteSkin deformation is not valid."); 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(); } /// /// Gets an enumerable to iterate through all deformed vertex positions of this SpriteSkin. /// /// Returns an IEnumerable to deformed vertex positions. /// /// Thrown when there is no vertex positions or deformed vertices. /// HasCurrentDeformedVertices can be used to verify if there are any deformed vertices available. /// public IEnumerable GetDeformedVertexPositionData() { if (!m_IsValid) throw new InvalidOperationException("The SpriteSkin deformation is not valid."); var hasPosition = sprite.HasVertexAttribute(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(rawSlice, m_SpriteVertexCount, m_SpriteVertexStreamSize); } /// /// Gets an enumerable to iterate through all deformed vertex tangents of this SpriteSkin. /// /// Returns an IEnumerable to deformed vertex tangents. /// /// Thrown when there is no vertex tangents or deformed vertices. /// HasCurrentDeformedVertices can be used to verify if there are any deformed vertices available. /// public IEnumerable GetDeformedVertexTangentData() { if (!m_IsValid) throw new InvalidOperationException("The SpriteSkin deformation is not valid."); var hasTangent = sprite.HasVertexAttribute(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(rawSlice, m_SpriteVertexCount, m_SpriteVertexStreamSize); } void DisposeOutlineCaches() { m_OutlineIndexCache.DisposeIfCreated(); m_StaticOutlineVertexCache.DisposeIfCreated(); m_DeformedOutlineVertexCache.DisposeIfCreated(); m_OutlineIndexCache = default; m_StaticOutlineVertexCache = default; m_DeformedOutlineVertexCache = default; } /// /// Used by the animation clip preview window. /// Recommended to not use outside of this purpose. /// public void OnPreviewUpdate() { #if UNITY_EDITOR if (IsInGUIUpdateLoop()) Deform(); #endif } static bool IsInGUIUpdateLoop() => Event.current != null; void Deform() { CacheCurrentSprite(m_AutoRebind); if (isValid && enabled && (alwaysUpdate || m_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 = m_SpriteId; PostDeform(true); } } else if (!InternalEngineBridge.IsUsingDeformableBuffer(spriteRenderer, IntPtr.Zero)) { DeactivateSkinning(); } } internal void PostDeform(bool didDeform) { if (didDeform) { #if ENABLE_URP UpdateDeformedOutlineCache(); #endif m_VertexDeformationHash = Time.frameCount; } } void CacheCurrentSprite(bool rebind) { if (m_CurrentDeformSprite == m_SpriteId) return; using (Profiling.cacheCurrentSprite.Auto()) { DeactivateSkinning(); m_CurrentDeformSprite = m_SpriteId; if (rebind && m_CurrentDeformSprite > 0 && rootBone != null) { if (!SpriteSkinHelpers.GetSpriteBonesTransforms(this, out var transforms)) Debug.LogWarning($"Rebind failed for {name}. Could not find all bones required by the Sprite: {sprite.name}."); SetBoneTransforms(transforms); } UpdateSpriteDeformationData(); DeformationManager.instance.CopyToSpriteSkinData(this); CacheValidFlag(); m_TransformsHash = 0; } } void UpdateSpriteDeformationData() { #if ENABLE_URP CacheSpriteOutline(); #endif if (sprite == null) { m_SpriteUVs = NativeCustomSlice.Default(); m_SpriteVertices = NativeCustomSlice.Default(); m_SpriteTangents = NativeCustomSlice.Default(); m_SpriteBoneWeights = NativeCustomSlice.Default(); m_SpriteBindPoses = NativeCustomSlice.Default(); m_SpriteHasTangents = false; m_SpriteVertexStreamSize = 0; m_SpriteVertexCount = 0; m_SpriteTangentVertexOffset = 0; } else { var cacheFullMesh = currentDeformationMethod == DeformationMethods.Cpu || forceCpuDeformation; if (cacheFullMesh) { m_SpriteVertices = new NativeCustomSlice(sprite.GetVertexAttribute(VertexAttribute.Position)); m_SpriteVertexCount = sprite.GetVertexCount(); m_SpriteVertexStreamSize = sprite.GetVertexStreamSize(); m_SpriteTangents = new NativeCustomSlice(sprite.GetVertexAttribute(VertexAttribute.Tangent)); m_SpriteHasTangents = sprite.HasVertexAttribute(VertexAttribute.Tangent); m_SpriteTangentVertexOffset = sprite.GetVertexStreamOffset(VertexAttribute.Tangent); } else { m_SpriteVertices = new NativeCustomSlice(m_StaticOutlineVertexCache); m_SpriteVertexCount = m_SpriteVertices.length; m_SpriteVertexStreamSize = sizeof(float) * 3; m_SpriteTangents = new NativeCustomSlice(sprite.GetVertexAttribute(VertexAttribute.Tangent)); m_SpriteHasTangents = false; m_SpriteTangentVertexOffset = 0; } m_SpriteUVs = new NativeCustomSlice(sprite.GetVertexAttribute(VertexAttribute.TexCoord0)); m_SpriteBoneWeights = new NativeCustomSlice(sprite.GetVertexAttribute(VertexAttribute.BlendWeight)); m_SpriteBindPoses = new NativeCustomSlice(sprite.GetBindPoses()); } } #if ENABLE_URP void UpdateDeformedOutlineCache() { if (sprite == null) return; if (!m_OutlineIndexCache.IsCreated || !m_DeformedOutlineVertexCache.IsCreated) return; if (!HasCurrentDeformedVertices()) return; var buffer = GetCurrentDeformedVertices(); var indexCache = m_OutlineIndexCache; var vertexCache = m_DeformedOutlineVertexCache; BurstedSpriteSkinUtilities.SetVertexPositionFromByteBuffer(in buffer, in indexCache, ref vertexCache, m_SpriteVertexStreamSize); m_DeformedOutlineVertexCache = vertexCache; } void CacheSpriteOutline() { DisposeOutlineCaches(); if (sprite == null) return; CacheOutlineIndices(out var maxIndex); var cacheSize = maxIndex + 1; CacheOutlineVertices(cacheSize); } void CacheOutlineIndices(out int maxIndex) { var indices = sprite.GetIndices(); var edgeNativeArr = MeshUtilities.GetOutlineEdges(in indices); m_OutlineIndexCache = new NativeArray(edgeNativeArr.Length * 2, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); maxIndex = 0; for (var i = 0; i < edgeNativeArr.Length; ++i) { var indexX = edgeNativeArr[i].x; var indexY = edgeNativeArr[i].y; m_OutlineIndexCache[i * 2] = indexX; m_OutlineIndexCache[(i * 2) + 1] = indexY; if (indexX > maxIndex) maxIndex = indexX; if (indexY > maxIndex) maxIndex = indexY; } edgeNativeArr.Dispose(); } void CacheOutlineVertices(int cacheSize) { m_DeformedOutlineVertexCache = new NativeArray(cacheSize, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); m_StaticOutlineVertexCache = new NativeArray(cacheSize, Allocator.Persistent); var vertices = sprite.GetVertexAttribute(VertexAttribute.Position); var vertexCache = m_StaticOutlineVertexCache; for (var i = 0; i < m_OutlineIndexCache.Length; ++i) { var index = m_OutlineIndexCache[i]; vertexCache[index] = vertices[index]; } m_StaticOutlineVertexCache = vertexCache; } #endif internal void CopyToSpriteSkinData(ref SpriteSkinData data, int spriteSkinIndex) { if (!m_BoneCacheUpdateToDate) { RefreshBoneTransforms(); } CacheCurrentSprite(m_AutoRebind); data.vertices = m_SpriteVertices; data.boneWeights = m_SpriteBoneWeights; data.bindPoses = m_SpriteBindPoses; data.tangents = m_SpriteTangents; data.hasTangents = m_SpriteHasTangents; data.spriteVertexStreamSize = m_SpriteVertexStreamSize; data.spriteVertexCount = m_SpriteVertexCount; data.tangentVertexOffset = m_SpriteTangentVertexOffset; data.transformId = m_TransformId; data.boneTransformId = m_BoneTransformIdNativeSlice; m_DataIndex = spriteSkinIndex; } internal bool NeedToUpdateDeformationCache() { unsafe { var iptr = new IntPtr(sprite.GetVertexAttribute(VertexAttribute.TexCoord0).GetUnsafeReadOnlyPtr()); var rs = m_SpriteUVs.data != iptr; if (rs) { UpdateSpriteDeformationData(); deformationSystem.CopyToSpriteSkinData(this); DeformationManager.instance.CopyToSpriteSkinData(this); } return rs; } } internal void CacheHierarchy() { using (Profiling.cacheHierarchy.Auto()) { m_HierarchyCache.Clear(); if (rootBone == null || !m_AutoRebind) return; var boneCount = CountChildren(rootBone); m_HierarchyCache.EnsureCapacity(boneCount + 1); SpriteSkinHelpers.CacheChildren(rootBone, m_HierarchyCache); foreach (var entry in m_HierarchyCache) { if (entry.Value.Count == 1) continue; var count = entry.Value.Count; for (var i = 0; i < count; ++i) { var transformEntry = entry.Value[i]; transformEntry.fullName = SpriteSkinHelpers.GenerateTransformPath(rootBone, transformEntry.transform); entry.Value[i] = transformEntry; } } } } internal void DeactivateSkinning() { if (m_SpriteRenderer != null) { var currentSprite = sprite; if (currentSprite != null) InternalEngineBridge.SetLocalAABB(m_SpriteRenderer, currentSprite.bounds); m_SpriteRenderer.DeactivateDeformableBuffer(); } m_TransformsHash = 0; } internal void ResetSprite() { m_CurrentDeformSprite = 0; CacheValidFlag(); } internal void SetDeformationSystem(BaseDeformationSystem newDeformationSystem) { deformationSystem = newDeformationSystem; currentDeformationMethod = deformationSystem.deformationMethod; } static int CountChildren(Transform transform) { var childCount = transform.childCount; var count = childCount; for (var i = 0; i < childCount; ++i) count += CountChildren(transform.GetChild(i)); return count; } } }