diff --git a/CHANGELOG.md b/CHANGELOG.md index 408b850..d97cf09 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,22 @@ # Changelog +## [10.1.4] - 2024-10-07 +### Fixed +- Animation Preview window sometimes does not display deformed Sprites. (DANB-705) +- Sprite Resolver missing sprite previews when dealing with large number of entries. (DANB-714) +- Misaligned label previews in Sprite Resolver's inspector. (DANB-722) +- Sprite Resolver component not updated after Sprite Library Asset has been modified. (DANB-727) +- Sprite Skin breaks in the animation preview window after sprite swap. (DANB-743) +- IK gizmos are displayed in the SceneView when IKManager2D is active in Animation Preview window. (DANB-738) +- IK solvers are misaligned when bones have different depths. (DANB-753) +- Rendering issues with SRP Batching and Sprite mask. (DANB-760) +- Unable to drag sprites into empty rows of the Sprite Library Editor. (DANB-749) +- Sprite Skin deformation systems have outdated data after sprite swap. (DANB-766) +- Setting incorrect computer buffer size. (DANB-768) +- Reenable editor tests. +- Bone buffer binding issues. +- Sprite changed callback listeners. + ## [10.1.3] - 2024-07-26 ### Fixed - Sprite Swap overlay Label selection not reacting to mouse clicks. (case DANB-627) @@ -14,6 +31,7 @@ - Fixed SpriteSkin's playmode test failures. (case DANB-678) - Modifying the Sprite Skin component through public API. - Skinning Editor bone and mesh Visibility sliders too short. (case DANB-681) +- Fixed an issue where opening a Sprite Library Asset, when it is a sub asset, in the Sprite Library Editor, would throw an exception. ## [10.1.2] - 2024-05-06 ### Fixed diff --git a/Editor/SpriteLib/SpriteLibraryEditor/DragAndDropManipulator.cs b/Editor/SpriteLib/SpriteLibraryEditor/DragAndDropManipulator.cs index a481219..e736179 100644 --- a/Editor/SpriteLib/SpriteLibraryEditor/DragAndDropManipulator.cs +++ b/Editor/SpriteLib/SpriteLibraryEditor/DragAndDropManipulator.cs @@ -61,6 +61,46 @@ void OnDragEnter(DragEnterEvent evt) TryStartDrag(); } + void OnDragUpdate(DragUpdatedEvent evt) + { + if (evt.currentTarget == evt.target) + TryStartDrag(); + + m_IsChildDragged = evt.currentTarget != evt.target; + + if (isActiveDrag) + DragAndDrop.visualMode = DragAndDropVisualMode.Copy; + + UpdateVisuals(); + if (isActiveDrag) + evt.StopImmediatePropagation(); + } + + void OnDragExit(DragExitedEvent evt) + { + StopDragging(); + } + + void OnDragLeave(DragLeaveEvent evt) + { + StopDragging(); + } + + void OnDragPerform(DragPerformEvent evt) + { + if (!isActiveDrag) + return; + + DragAndDrop.AcceptDrag(); + var spritesData = RetrieveDraggedSprites(DragAndDrop.objectReferences); + if (spritesData.Count > 0) + onDragPerform?.Invoke(spritesData, evt.altKey); + + DragAndDrop.objectReferences = new Object[] { }; + + StopDragging(); + } + void TryStartDrag() { if (m_IsDragging) @@ -70,8 +110,7 @@ void TryStartDrag() if (DragAndDrop.GetGenericData("user_data") != null) return; - var spritesData = RetrieveDraggedSprites(DragAndDrop.objectReferences); - if (spritesData.Count == 0) + if (!HasAnyDraggedSprites(DragAndDrop.objectReferences)) return; if (!m_CanStartDrag()) @@ -92,45 +131,60 @@ void StopDragging() UpdateVisuals(); } - void OnDragUpdate(DragUpdatedEvent evt) + void UpdateVisuals() { - m_IsChildDragged = evt.currentTarget != evt.target; - - if (isActiveDrag) - DragAndDrop.visualMode = DragAndDropVisualMode.Copy; - - UpdateVisuals(); - if (isActiveDrag) - evt.StopImmediatePropagation(); + m_OverlayVisual.EnableInClassList(k_DragOverAddClassName, isActiveDrag); } - void OnDragExit(DragExitedEvent evt) + static bool HasAnyDraggedSprites(Object[] objectReferences) { - StopDragging(); - } + if (objectReferences == null || objectReferences.Length == 0) + return false; - void OnDragLeave(DragLeaveEvent evt) - { - StopDragging(); - } + foreach (var objectReference in objectReferences) + { + switch (objectReference) + { + case Sprite: + return true; + case Texture2D texture2D: + { + var texturePath = AssetDatabase.GetAssetPath(texture2D); + foreach (var obj in AssetDatabase.LoadAllAssetsAtPath(texturePath)) + { + if (obj is Sprite) + return true; + } - void UpdateVisuals() - { - m_OverlayVisual.EnableInClassList(k_DragOverAddClassName, isActiveDrag); - } + break; + } + case GameObject gameObject: + { + var isPsdGameObjectRoot = gameObject.transform.parent != null; + if (isPsdGameObjectRoot) + continue; - void OnDragPerform(DragPerformEvent evt) - { - if (!isActiveDrag) - return; + var psdFilePath = AssetDatabase.GetAssetPath(gameObject); + if (string.IsNullOrEmpty(psdFilePath)) + continue; - StopDragging(); + var ext = Path.GetExtension(psdFilePath); + if (k_SupportedPsdExtensions.Contains(ext)) + { + foreach (var obj in AssetDatabase.LoadAllAssetsAtPath(psdFilePath)) + { + var spriteObj = obj as Sprite; + if (spriteObj != null) + return true; + } + } - var spritesData = RetrieveDraggedSprites(DragAndDrop.objectReferences); - if (spritesData.Count == 0) - return; + break; + } + } + } - onDragPerform?.Invoke(spritesData, evt.altKey); + return true; } static List RetrieveDraggedSprites(Object[] objectReferences) diff --git a/Editor/SpriteLib/SpriteLibraryEditor/UI/CategoriesTab.cs b/Editor/SpriteLib/SpriteLibraryEditor/UI/CategoriesTab.cs index 1704970..596f0e8 100644 --- a/Editor/SpriteLib/SpriteLibraryEditor/UI/CategoriesTab.cs +++ b/Editor/SpriteLib/SpriteLibraryEditor/UI/CategoriesTab.cs @@ -76,6 +76,8 @@ public void BindElements(ControllerEvents controllerEvents, ViewEvents viewEvent m_CategoryListsScrollContainer = this.Q("CategoryListsScrollView"); m_CategoryListsScrollContainer.pickingMode = PickingMode.Ignore; m_CategoryListsScrollContainer.Q("unity-content-and-vertical-scroll-container").pickingMode = PickingMode.Ignore; + m_CategoryListsScrollContainer.contentContainer.pickingMode = PickingMode.Ignore; + m_CategoryListsContainer = new VisualElement { name = "CategoryListsContainer", pickingMode = PickingMode.Ignore }; m_CategoryListsScrollContainer.Add(m_CategoryListsContainer); diff --git a/Editor/SpriteLib/SpriteLibraryEditor/UI/CustomElements/GridView.cs b/Editor/SpriteLib/SpriteLibraryEditor/UI/CustomElements/GridView.cs index e0262a6..7b864e4 100644 --- a/Editor/SpriteLib/SpriteLibraryEditor/UI/CustomElements/GridView.cs +++ b/Editor/SpriteLib/SpriteLibraryEditor/UI/CustomElements/GridView.cs @@ -1221,7 +1221,7 @@ void ClearSelectionWithoutValidation() VisualElement CreateDummyItemElement() { - var item = new VisualElement(); + var item = new VisualElement { pickingMode = PickingMode.Ignore }; SetupItemElement(item); return item; } @@ -1905,6 +1905,9 @@ internal class RecycledRow : VisualElement public RecycledRow(float height) { AddToClassList(k_RowUssClassName); + + pickingMode = PickingMode.Ignore; + style.height = height; indices = new List(); diff --git a/Editor/SpriteLib/SpriteLibraryEditor/WindowController.cs b/Editor/SpriteLib/SpriteLibraryEditor/WindowController.cs index 98cc0c8..bf1e3d5 100644 --- a/Editor/SpriteLib/SpriteLibraryEditor/WindowController.cs +++ b/Editor/SpriteLib/SpriteLibraryEditor/WindowController.cs @@ -136,6 +136,11 @@ public void RevertChanges() public void SelectAsset(SpriteLibraryAsset asset, bool modifiedExternally = false) { + // Only allow .spriteLib files to be used in the editor. + // This is to prevent the user from opening the editor with .psd or .psb containing spriteLibs. + if (!AssetDatabase.GetAssetPath(asset).EndsWith(".spriteLib")) + return; + if (!modifiedExternally) { if (asset == null || asset == m_Model.selectedAsset) diff --git a/Editor/SpriteLib/SpriteResolverInspector.cs b/Editor/SpriteLib/SpriteResolverInspector.cs index 4de0f35..69d3e77 100644 --- a/Editor/SpriteLib/SpriteResolverInspector.cs +++ b/Editor/SpriteLib/SpriteResolverInspector.cs @@ -45,6 +45,8 @@ struct SpriteCategorySelectionList public void OnEnable() { + m_SpriteSelectorWidget.Initialize(GetInstanceID()); + m_SpriteHash = serializedObject.FindProperty("m_SpriteHash"); m_SpriteKey = serializedObject.FindProperty("m_SpriteKey"); m_LabelHash = serializedObject.FindProperty("m_labelHash"); @@ -61,6 +63,11 @@ void OnDisable() EditorApplication.focusChanged -= OnEditorFocusChanged; } + void OnDestroy() + { + m_SpriteSelectorWidget.Dispose(); + } + void SpriteResolverDeserializedCallback() { if (!m_IgnoreNextDeserializeCallback) @@ -270,7 +277,7 @@ public override void OnInspectorGUI() } ApplyModifiedProperty(); - if (m_SpriteSelectorWidget.NeedUpdatePreview()) + if (m_SpriteSelectorWidget.UpdateSpritePreviews()) this.Repaint(); } diff --git a/Editor/SpriteLib/SpriteSelectionWidget.cs b/Editor/SpriteLib/SpriteSelectionWidget.cs index 59b0cd7..1a1c71d 100644 --- a/Editor/SpriteLib/SpriteSelectionWidget.cs +++ b/Editor/SpriteLib/SpriteSelectionWidget.cs @@ -1,5 +1,7 @@ +using System; using UnityEngine; using System.Collections.Generic; +using UnityEditor.U2D.Common; namespace UnityEditor.U2D.Animation { @@ -11,40 +13,82 @@ class Styles public Styles() { - gridListStyle = new GUIStyle("GridList"); - gridListStyle.alignment = GUI.skin.button.alignment; + gridListStyle = new GUIStyle("GridList") + { + alignment = GUI.skin.button.alignment, + padding = new RectOffset(k_GridCellPadding, k_GridCellPadding, k_GridCellPadding, k_GridCellPadding), + fixedHeight = k_TargetPreviewSize, + fixedWidth = k_TargetPreviewSize + }; } } - Sprite[] m_SpriteList = new Sprite[0]; - Texture2D[] m_SpritePreviews = new Texture2D[0]; - List m_SpritePreviewNeedFetching = new List(); + static Texture2D spriteLoadingThumbnail + { + get + { + if (s_LoadingSpriteTexture == null) + s_LoadingSpriteTexture = AssetPreview.GetMiniTypeThumbnail(typeof(Sprite)); + return s_LoadingSpriteTexture; + } + } + + static Texture2D s_LoadingSpriteTexture; + + const int k_TargetPreviewSize = 64; + const int k_GridCellPadding = 2; + const int k_ScrollbarWidthOffset = 10; + + List m_SpritePreviewNeedFetching = new(); + + Sprite[] m_SpriteList = Array.Empty(); + Texture2D[] m_SpritePreviews = Array.Empty(); + + int m_ClientId = 0; + int m_PreviewCacheSize = 0; + Vector2 m_ScrollPos; Styles m_Style; - const int kTargetPreviewSize = 64; - public SpriteSelectorWidget() { } + + + public void Initialize(int clientId) + { + m_ClientId = clientId; + } + + public void Dispose() + { + if (m_ClientId != 0) + { + InternalEditorBridge.ClearAssetPreviews(m_ClientId); + m_ClientId = 0; + } + } public void UpdateContents(Sprite[] sprites) { + m_SpritePreviewNeedFetching.Clear(); + + InternalEditorBridge.ClearAssetPreviews(m_ClientId); + var spriteCount = sprites.Length; + m_PreviewCacheSize = spriteCount + 1; + InternalEditorBridge.SetAssetPreviewTextureCacheSize(m_PreviewCacheSize, m_ClientId); + m_SpriteList = sprites; m_SpritePreviews = new Texture2D[spriteCount]; - m_SpritePreviewNeedFetching.Clear(); + m_SpritePreviewNeedFetching.Capacity = spriteCount; for (var i = 0; i < spriteCount; ++i) m_SpritePreviewNeedFetching.Add(i); - UpdateSpritePreviews(); } - public int ShowGUI(int selectedIndex) { if (m_Style == null) m_Style = new Styles(); - UpdateSpritePreviews(); - - var drawRect = EditorGUILayout.GetControlRect(false, kTargetPreviewSize + 10f, new[] { GUILayout.ExpandWidth(true) }); + var drawRect = EditorGUILayout.GetControlRect(false, k_TargetPreviewSize + 10f, new[] { GUILayout.ExpandWidth(true) }); if (Event.current.type == EventType.Repaint) GUI.skin.box.Draw(drawRect, false, false, false, false); if (m_SpriteList == null || m_SpriteList.Length == 0) @@ -54,54 +98,68 @@ public int ShowGUI(int selectedIndex) selectedIndex = (selectedIndex > m_SpriteList.Length) ? 0 : selectedIndex; - float columnF; - int columnCount, rowCount; - GetRowColumnCount(drawRect.width - 20, kTargetPreviewSize, m_SpriteList.Length, out columnCount, out rowCount, out columnF); + var widthMargin = (m_Style.gridListStyle.margin.left + m_Style.gridListStyle.margin.right) * 0.5f; + var heightMargin = (m_Style.gridListStyle.margin.top + m_Style.gridListStyle.margin.bottom) * 0.5f; + GetRowColumnCount(drawRect.width - k_ScrollbarWidthOffset, k_TargetPreviewSize + Mathf.RoundToInt(widthMargin), m_SpriteList.Length, out var columnCount, out var rowCount); if (columnCount > 0 && rowCount > 0) { - float contentSize = (columnF * kTargetPreviewSize) / columnCount; - var gridRect = new Rect(drawRect.x, drawRect.y, drawRect.width - 20, rowCount * contentSize); - m_ScrollPos = GUI.BeginScrollView(drawRect, m_ScrollPos, gridRect, false, false, GUIStyle.none, GUI.skin.verticalScrollbar); + var height = rowCount * (k_TargetPreviewSize + heightMargin); + var width = columnCount * (k_TargetPreviewSize + widthMargin); + var scrollViewRect = new Rect(drawRect.x - k_ScrollbarWidthOffset, drawRect.y, width, height); + m_ScrollPos = GUI.BeginScrollView(drawRect, m_ScrollPos, scrollViewRect, false, false, GUIStyle.none, GUI.skin.verticalScrollbar); - m_Style.gridListStyle.fixedWidth = contentSize; - m_Style.gridListStyle.fixedHeight = contentSize; + var gridRect = scrollViewRect; + gridRect.x += (drawRect.width - width - k_ScrollbarWidthOffset) * 0.5f; selectedIndex = GUI.SelectionGrid(gridRect, selectedIndex, m_SpritePreviews, columnCount, m_Style.gridListStyle); + GUI.EndScrollView(); } return selectedIndex; } - static void GetRowColumnCount(float drawWidth, int size, int contentCount, out int column, out int row, out float columnf) + static void GetRowColumnCount(float drawWidth, int size, int contentCount, out int columnCount, out int rowCount) { - columnf = drawWidth / size; - column = (int)Mathf.Floor(columnf); - if (column == 0) - row = 0; + columnCount = (int)drawWidth / size; + if (columnCount == 0) + rowCount = 0; else - row = (int)Mathf.Ceil((contentCount + column) / column); + rowCount = Math.Max(1, Mathf.CeilToInt((float)contentCount / columnCount)); } - public bool NeedUpdatePreview() + public bool UpdateSpritePreviews() { - return m_SpritePreviewNeedFetching.Count > 0; - } + var remainingPreviewCount = m_SpritePreviewNeedFetching.Count; + if (remainingPreviewCount == 0) + return false; - void UpdateSpritePreviews() - { - for (int i = 0; i < m_SpritePreviewNeedFetching.Count; ++i) + for (var i = remainingPreviewCount - 1; i >= 0; --i) { var index = m_SpritePreviewNeedFetching[i]; if (m_SpriteList[index] == null) + { m_SpritePreviews[index] = EditorGUIUtility.Load("icons/console.warnicon.png") as Texture2D; + m_SpritePreviewNeedFetching.RemoveAt(i); + } else - m_SpritePreviews[index] = AssetPreview.GetAssetPreview(m_SpriteList[index]); - if (m_SpritePreviews[index] != null) { - m_SpritePreviewNeedFetching.RemoveAt(i); - --i; + var spriteId = m_SpriteList[index].GetInstanceID(); + var spritePreview = InternalEditorBridge.GetAssetPreview(spriteId, m_ClientId); + if (spritePreview != null) + { + m_SpritePreviews[index] = spritePreview; + m_SpritePreviewNeedFetching.RemoveAt(i); + } + else + { + m_SpritePreviews[index] = spriteLoadingThumbnail; + if (!InternalEditorBridge.IsLoadingAssetPreview(spriteId, m_ClientId)) + m_SpritePreviewNeedFetching.RemoveAt(i); + } } } + + return remainingPreviewCount != m_SpritePreviewNeedFetching.Count; } } } diff --git a/IK/Editor/IKEditorManager.cs b/IK/Editor/IKEditorManager.cs index 2581608..dd58603 100644 --- a/IK/Editor/IKEditorManager.cs +++ b/IK/Editor/IKEditorManager.cs @@ -287,7 +287,18 @@ private void OnSceneGUI(SceneView sceneView) foreach (var ikManager2D in m_IKManagers) { if (ikManager2D != null && ikManager2D.isActiveAndEnabled) - IKGizmos.instance.DoSolversGUI(ikManager2D); + { + if (!EditorSceneManager.IsPreviewSceneObject(ikManager2D)) + { + if (PrefabStageUtility.GetCurrentPrefabStage() == null) + IKGizmos.instance.DoSolversGUI(ikManager2D); + } + else + { + if (PrefabStageUtility.GetCurrentPrefabStage()?.scene == ikManager2D.gameObject.scene) + IKGizmos.instance.DoSolversGUI(ikManager2D); + } + } } if (!IKGizmos.instance.isDragging && IsDraggingATool()) diff --git a/IK/Runtime/IKChain2D.cs b/IK/Runtime/IKChain2D.cs index 087b1d8..7f0049a 100644 --- a/IK/Runtime/IKChain2D.cs +++ b/IK/Runtime/IKChain2D.cs @@ -167,8 +167,9 @@ void PrepareLengths() while (currentTransform && index >= 0) { - if (currentTransform.parent && index > 0) - m_Lengths[index - 1] = (currentTransform.position - currentTransform.parent.position).magnitude; + var parent = currentTransform.parent; + if (parent && index > 0) + m_Lengths[index - 1] = parent.TransformVector((Vector2)currentTransform.localPosition).magnitude; currentTransform = currentTransform.parent; --index; diff --git a/Runtime/BatchedDeformation/BaseDeformationSystem.cs b/Runtime/BatchedDeformation/BaseDeformationSystem.cs index 4e0c4b0..9a9ccb5 100644 --- a/Runtime/BatchedDeformation/BaseDeformationSystem.cs +++ b/Runtime/BatchedDeformation/BaseDeformationSystem.cs @@ -80,6 +80,7 @@ internal void AddBoneTransforms(SpriteSkin spriteSkin) } } } + internal virtual void UpdateMaterial(SpriteSkin spriteSkin) { } internal virtual bool AddSpriteSkin(SpriteSkin spriteSkin) @@ -101,20 +102,18 @@ internal virtual bool AddSpriteSkin(SpriteSkin spriteSkin) internal void CopyToSpriteSkinData(SpriteSkin spriteSkin) { - CopyToSpriteSkinDataAtIndex(spriteSkin, spriteSkin.dataIndex); - } - - void CopyToSpriteSkinDataAtIndex(SpriteSkin spriteSkin, int index) - { - if (index < 0 || index >= m_SpriteSkins.Count) - return; if (!m_SpriteSkinData.IsCreated) + throw new InvalidOperationException("Sprite Skin Data not initialized."); + + var dataIndex = spriteSkin.dataIndex; + if(dataIndex < 0 || dataIndex >= m_SpriteSkinData.Length) return; var spriteSkinData = default(SpriteSkinData); - spriteSkin.CopyToSpriteSkinData(ref spriteSkinData, index); - m_SpriteSkinData[index] = spriteSkinData; - m_SpriteRenderers[index] = spriteSkin.spriteRenderer; + spriteSkin.CopyToSpriteSkinData(ref spriteSkinData); + + m_SpriteSkinData[dataIndex] = spriteSkinData; + m_SpriteRenderers[dataIndex] = spriteSkin.spriteRenderer; } internal void RemoveSpriteSkin(SpriteSkin spriteSkin) @@ -156,7 +155,9 @@ internal void Initialize(int objectId) var count = 0; foreach (var spriteSkin in m_SpriteSkins) { - CopyToSpriteSkinDataAtIndex(spriteSkin, count++); + spriteSkin.SetDataIndex(count++); + + CopyToSpriteSkinData(spriteSkin); } } @@ -198,7 +199,10 @@ protected void BatchRemoveSpriteSkins() var count = 0; foreach (var spriteSkin in m_SpriteSkins) - CopyToSpriteSkinDataAtIndex(spriteSkin, count++); + { + spriteSkin.SetDataIndex(count++); + CopyToSpriteSkinData(spriteSkin); + } Array.Resize(ref m_SpriteRenderers, updatedCount); ResizeAndCopyArrays(updatedCount); @@ -212,10 +216,12 @@ protected void BatchAddSpriteSkins() if (m_SpriteSkinsToAdd.Count == 0) return; + if (!m_IsSpriteSkinActiveForDeform.IsCreated) + throw new InvalidOperationException("SpriteSkinActiveForDeform not initialized."); + var updatedCount = m_SpriteSkins.Count + m_SpriteSkinsToAdd.Count; Array.Resize(ref m_SpriteRenderers, updatedCount); - if (m_IsSpriteSkinActiveForDeform.IsCreated) - ResizeAndCopyArrays(updatedCount); + ResizeAndCopyArrays(updatedCount); foreach (var spriteSkin in m_SpriteSkinsToAdd) { @@ -232,11 +238,10 @@ protected void BatchAddSpriteSkins() m_SpriteRenderers[count - 1] = spriteSkin.spriteRenderer; m_WorldToLocalTransformAccessJob.AddTransform(spriteSkin.transform); - if (m_IsSpriteSkinActiveForDeform.IsCreated) - { - AddBoneTransforms(spriteSkin); - CopyToSpriteSkinDataAtIndex(spriteSkin, count - 1); - } + AddBoneTransforms(spriteSkin); + + spriteSkin.SetDataIndex(count - 1); + CopyToSpriteSkinData(spriteSkin); } m_SpriteSkinsToAdd.Clear(); @@ -302,15 +307,12 @@ protected void PrepareDataForDeformation(out JobHandle localToWorldJobHandle, ou void ValidateSpriteSkinData() { - var count = 0; foreach (var spriteSkin in m_SpriteSkins) { - var i = count++; - m_IsSpriteSkinActiveForDeform[i] = spriteSkin.BatchValidate(); - if (m_IsSpriteSkinActiveForDeform[i] && spriteSkin.NeedToUpdateDeformationCache()) - { - CopyToSpriteSkinDataAtIndex(spriteSkin, i); - } + var index = spriteSkin.dataIndex; + m_IsSpriteSkinActiveForDeform[index] = spriteSkin.BatchValidate(); + if (m_IsSpriteSkinActiveForDeform[index] && spriteSkin.NeedToUpdateDeformationCache()) + CopyToSpriteSkinData(spriteSkin); } } @@ -428,4 +430,4 @@ internal unsafe NativeArray GetDeformableBufferForSpriteSkin(SpriteSkin sp internal TransformAccessJob GetLocalToWorldTransformAccessJob() => m_LocalToWorldTransformAccessJob; #endif } -} \ No newline at end of file +} diff --git a/Runtime/BatchedDeformation/DeformationManager.cs b/Runtime/BatchedDeformation/DeformationManager.cs index 35d9bcf..96d0812 100644 --- a/Runtime/BatchedDeformation/DeformationManager.cs +++ b/Runtime/BatchedDeformation/DeformationManager.cs @@ -184,17 +184,6 @@ internal void RemoveBoneTransforms(SpriteSkin spriteSkin) m_DeformationSystems[i].RemoveBoneTransforms(spriteSkin); } - internal void CopyToSpriteSkinData(SpriteSkin spriteSkin) - { - if (spriteSkin == null) - return; - var system = spriteSkin.deformationSystem; - if (system == null) - return; - - system.CopyToSpriteSkinData(spriteSkin); - } - internal void AddSpriteSkinBoneTransform(SpriteSkin spriteSkin) { if (spriteSkin == null) diff --git a/Runtime/BatchedDeformation/GpuDeformationSystem.cs b/Runtime/BatchedDeformation/GpuDeformationSystem.cs index e097f86..84cdd2e 100644 --- a/Runtime/BatchedDeformation/GpuDeformationSystem.cs +++ b/Runtime/BatchedDeformation/GpuDeformationSystem.cs @@ -13,12 +13,29 @@ internal class GpuDeformationSystem : BaseDeformationSystem { const string k_GpuSkinningShaderKeyword = "SKINNED_SPRITE"; const string k_GlobalSpriteBoneBufferId = "_SpriteBoneTransforms"; - const int k_DefaultComputeBufferSize = 64; readonly Dictionary m_KeywordEnabledMaterials = new Dictionary(); NativeArray m_BoneTransformBufferSizes; ComputeBuffer m_BoneTransformsComputeBuffer; + static ComputeBuffer s_FallbackBuffer; + + [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)] + static void CreateFallbackBuffer() + { + if (s_FallbackBuffer == null) + s_FallbackBuffer = new ComputeBuffer(UnsafeUtility.SizeOf(), UnsafeUtility.SizeOf(), ComputeBufferType.Default); + + Shader.SetGlobalBuffer(k_GlobalSpriteBoneBufferId, s_FallbackBuffer); + } + + static void ClearFallbackBuffer() + { + if(s_FallbackBuffer != null) + s_FallbackBuffer.Release(); + + s_FallbackBuffer = null; + } public override DeformationMethods deformationMethod => DeformationMethods.Gpu; @@ -49,6 +66,8 @@ protected override void InitializeArrays() const int startingCount = 0; m_BoneTransformBuffers = new NativeArray(startingCount, Allocator.Persistent); m_BoneTransformBufferSizes = new NativeArray(startingCount, Allocator.Persistent); + + CreateFallbackBuffer(); } internal override void Cleanup() @@ -59,6 +78,8 @@ internal override void Cleanup() m_BoneTransformBufferSizes.DisposeIfCreated(); CleanupComputeResources(); + + ClearFallbackBuffer(); } protected override void ResizeAndCopyArrays(int updatedCount) @@ -80,6 +101,7 @@ void CleanupComputeResources() foreach (var material in m_KeywordEnabledMaterials.Values) material.DisableKeyword(k_GpuSkinningShaderKeyword); m_KeywordEnabledMaterials.Clear(); + Shader.SetGlobalBuffer(k_GlobalSpriteBoneBufferId, s_FallbackBuffer); } internal override void UpdateMaterial(SpriteSkin spriteSkin) @@ -100,9 +122,6 @@ internal override bool AddSpriteSkin(SpriteSkin spriteSkin) m_KeywordEnabledMaterials.TryAdd(sharedMaterial.GetInstanceID(), sharedMaterial); } - if (!IsComputeBufferValid(m_BoneTransformsComputeBuffer)) - CreateComputeBuffer(k_DefaultComputeBufferSize); - return success; } @@ -163,7 +182,6 @@ internal override void Update() foreach (var spriteSkin in m_SpriteSkins) { - var didDeform = m_IsSpriteSkinActiveForDeform[spriteSkin.dataIndex]; spriteSkin.PostDeform(didDeform); } @@ -214,4 +232,4 @@ unsafe JobHandle ScheduleCopySpriteRendererBoneTransformBuffersJob(JobHandle job return copySpriteRendererBoneTransformBuffersJob.Schedule(batchCount, 16, jobHandle); } } -} \ No newline at end of file +} diff --git a/Runtime/SpriteLib/SpriteResolver.cs b/Runtime/SpriteLib/SpriteResolver.cs index 1143d55..4d8cab6 100644 --- a/Runtime/SpriteLib/SpriteResolver.cs +++ b/Runtime/SpriteLib/SpriteResolver.cs @@ -48,10 +48,12 @@ public partial class SpriteResolver : MonoBehaviour, IPreviewable int m_PreviousSpriteKeyInt; int m_PreviousSpriteHash; +#if UNITY_INCLUDE_TESTS /// /// Raised when resolved to a new value. /// internal event Action onResolvedSprite; +#endif void Reset() { @@ -175,8 +177,11 @@ public void OnPreviewUpdate() { } static bool IsInGUIUpdateLoop() => Event.current != null; - void LateUpdate() + internal void LateUpdate() { +#if UNITY_EDITOR + LateUpdateEditor(); +#endif ResolveUpdatedValue(); } @@ -266,7 +271,9 @@ public bool ResolveSpriteToSpriteRenderer() if (sr != null && (sprite != null || validEntry)) sr.sprite = sprite; +#if UNITY_INCLUDE_TESTS onResolvedSprite?.Invoke(this); +#endif return validEntry; } diff --git a/Runtime/SpriteLib/SpriteResolverEditor.cs b/Runtime/SpriteLib/SpriteResolverEditor.cs index e252771..b3ac11f 100644 --- a/Runtime/SpriteLib/SpriteResolverEditor.cs +++ b/Runtime/SpriteLib/SpriteResolverEditor.cs @@ -14,6 +14,20 @@ public partial class SpriteResolver : ISerializationCallbackReceiver /// public event Action onDeserializedCallback = () => { }; + long m_SpriteLibraryModificationHash; + internal long spriteLibraryModificationHash => m_SpriteLibraryModificationHash; + + void LateUpdateEditor() + { + var newSpriteLibraryModificationHash = GetCurrentSpriteLibraryAssetModificationHash(); + if (m_SpriteLibraryModificationHash != newSpriteLibraryModificationHash) + { + ResolveSpriteToSpriteRenderer(); + spriteLibChanged = true; + m_SpriteLibraryModificationHash = newSpriteLibraryModificationHash; + } + } + void OnDidApplyAnimationProperties() { if (IsInGUIUpdateLoop()) @@ -38,6 +52,18 @@ void ISerializationCallbackReceiver.OnAfterDeserialize() { onDeserializedCallback(); } + + long GetCurrentSpriteLibraryAssetModificationHash() + { + if (spriteLibrary != null) + { + var spriteLibraryAsset = spriteLibrary.spriteLibraryAsset; + if (spriteLibraryAsset != null) + return spriteLibraryAsset.modificationHash; + } + + return 0; + } } } #endif diff --git a/Runtime/SpriteSkin.cs b/Runtime/SpriteSkin.cs index f9537a9..95506c8 100644 --- a/Runtime/SpriteSkin.cs +++ b/Runtime/SpriteSkin.cs @@ -136,7 +136,7 @@ internal struct TransformData int m_CurrentDeformVerticesLength = 0; SpriteRenderer m_SpriteRenderer; int m_CurrentDeformSprite = 0; - int m_SpriteId = -1; + int m_SpriteId = 0; bool m_IsValid = false; SpriteSkinState m_State; int m_TransformsHash = 0; @@ -198,6 +198,11 @@ internal struct TransformData /// internal int dataIndex => m_DataIndex; + internal void SetDataIndex(int index) + { + m_DataIndex = index; + } + /// /// 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. @@ -309,7 +314,7 @@ public bool forceCpuDeformation if (isActiveAndEnabled) { UpdateSpriteDeformationData(); - DeformationManager.instance.CopyToSpriteSkinData(this); + deformationSystem?.CopyToSpriteSkinData(this); } } } @@ -381,6 +386,8 @@ void OnEnable() void OnDisable() { + m_SpriteRenderer.UnregisterSpriteChangeCallback(OnSpriteChanged); + DeactivateSkinning(); BufferManager.instance.ReturnBuffer(GetInstanceID()); deformationSystem?.RemoveSpriteSkin(this); @@ -397,8 +404,6 @@ void RefreshBoneTransforms() DeformationManager.instance.AddSpriteSkinBoneTransform(this); CacheValidFlag(); - - DeformationManager.instance.CopyToSpriteSkinData(this); } void OnSpriteChanged(SpriteRenderer updatedSpriteRenderer) @@ -438,6 +443,7 @@ void CacheBoneTransformIds() void OnBoneTransformChanged() { RefreshBoneTransforms(); + deformationSystem?.CopyToSpriteSkinData(this); SpriteSkinContainer.instance.BoneTransformsChanged(this); } @@ -484,9 +490,7 @@ SpriteSkinState CacheValidFlag() internal bool BatchValidate() { if (!m_BoneCacheUpdateToDate) - { RefreshBoneTransforms(); - } CacheCurrentSprite(m_AutoRebind); var hasSprite = m_CurrentDeformSprite != 0; @@ -501,11 +505,9 @@ void Reset() CacheValidFlag(); if (!m_BoneCacheUpdateToDate) - { RefreshBoneTransforms(); - } - DeformationManager.instance.CopyToSpriteSkinData(this); + deformationSystem?.CopyToSpriteSkinData(this); } } @@ -689,12 +691,15 @@ public void OnPreviewUpdate() void Deform() { + if (m_SpriteRenderer.sprite != m_Sprite) + OnSpriteChanged(m_SpriteRenderer); + 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) + if (spriteVertexCount > 0 && (m_TransformsHash != transformHash || vertexDeformationHash != GetNewVertexDeformationHash())) { var inputVertices = GetDeformedVertices(spriteVertexCount); SpriteSkinUtility.Deform(sprite, gameObject.transform.worldToLocalMatrix, boneTransforms, inputVertices.array); @@ -719,7 +724,7 @@ internal void PostDeform(bool didDeform) #if ENABLE_URP UpdateDeformedOutlineCache(); #endif - m_VertexDeformationHash = Time.frameCount; + m_VertexDeformationHash = GetNewVertexDeformationHash(); } } @@ -732,7 +737,7 @@ void CacheCurrentSprite(bool rebind) { DeactivateSkinning(); m_CurrentDeformSprite = m_SpriteId; - if (rebind && m_CurrentDeformSprite > 0 && rootBone != null) + 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}."); @@ -740,7 +745,7 @@ void CacheCurrentSprite(bool rebind) } UpdateSpriteDeformationData(); - DeformationManager.instance.CopyToSpriteSkinData(this); + deformationSystem?.CopyToSpriteSkinData(this); CacheValidFlag(); m_TransformsHash = 0; @@ -864,12 +869,10 @@ void CacheOutlineVertices(int cacheSize) m_StaticOutlineVertexCache = vertexCache; } #endif - internal void CopyToSpriteSkinData(ref SpriteSkinData data, int spriteSkinIndex) + internal void CopyToSpriteSkinData(ref SpriteSkinData data) { if (!m_BoneCacheUpdateToDate) - { RefreshBoneTransforms(); - } CacheCurrentSprite(m_AutoRebind); @@ -883,7 +886,6 @@ internal void CopyToSpriteSkinData(ref SpriteSkinData data, int spriteSkinIndex) data.tangentVertexOffset = m_SpriteTangentVertexOffset; data.transformId = m_TransformId; data.boneTransformId = m_BoneTransformIdNativeSlice; - m_DataIndex = spriteSkinIndex; } internal bool NeedToUpdateDeformationCache() @@ -895,8 +897,7 @@ internal bool NeedToUpdateDeformationCache() if (rs) { UpdateSpriteDeformationData(); - deformationSystem.CopyToSpriteSkinData(this); - DeformationManager.instance.CopyToSpriteSkinData(this); + deformationSystem?.CopyToSpriteSkinData(this); } return rs; @@ -965,5 +966,7 @@ static int CountChildren(Transform transform) return count; } + + static int GetNewVertexDeformationHash() => Time.frameCount; } } diff --git a/Runtime/SpriteSkinUtility.cs b/Runtime/SpriteSkinUtility.cs index e3b1bfb..912e08e 100644 --- a/Runtime/SpriteSkinUtility.cs +++ b/Runtime/SpriteSkinUtility.cs @@ -50,7 +50,8 @@ internal static bool IsUsingGpuDeformation() internal static bool CanSpriteSkinUseGpuDeformation(SpriteSkin spriteSkin) { return IsUsingGpuDeformation() && - GpuDeformationSystem.DoesShaderSupportGpuDeformation(spriteSkin.spriteRenderer.sharedMaterial); + GpuDeformationSystem.DoesShaderSupportGpuDeformation(spriteSkin.spriteRenderer.sharedMaterial) && + spriteSkin.spriteRenderer.maskInteraction == SpriteMaskInteraction.None; } internal static SpriteSkinState Validate(this SpriteSkin spriteSkin) diff --git a/package.json b/package.json index 56395f0..22639c7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "com.unity.2d.animation", - "version": "10.1.3", + "version": "10.1.4", "unity": "2023.1", "displayName": "2D Animation", "description": "2D Animation provides all the necessary tooling and runtime components for skeletal animation using Sprites.", @@ -10,15 +10,15 @@ ], "category": "2D", "dependencies": { - "com.unity.2d.common": "9.0.6", + "com.unity.2d.common": "9.0.7", "com.unity.2d.sprite": "1.0.0", "com.unity.collections": "1.2.4", "com.unity.modules.animation": "1.0.0", "com.unity.modules.uielements": "1.0.0" }, "relatedPackages": { - "com.unity.2d.animation.tests": "10.1.3", - "com.unity.2d.common.tests": "9.0.6", + "com.unity.2d.animation.tests": "10.1.4", + "com.unity.2d.common.tests": "9.0.7", "com.unity.2d.psdimporter": "9.0.3" }, "samples": [ @@ -29,15 +29,15 @@ } ], "_upm": { - "changelog": "### Fixed\n- Sprite Swap overlay Label selection not reacting to mouse clicks. (case DANB-627)\n- Sprite Swap overlay selection lock behavior. (case DANB-629)\n- Sprite Bone Influence tab bone reordering. (case DANB-634)\n- Documentation, comments, and other requirements to conform to Package Validation. (DANB-653)\n- Wrong Label is deleted when a newly created Label is deleted in the Sprite Library Editor. (case DANB-665)\n- Cannot select multiple Labels in the Sprite Library Editor when using Grid View. (case DANB-670)\n- Documentation, comments, and other requirements to conform to Package Validation. (DANB-653)\n- Support for renaming Sprite Library Editor entries with 'F2' on Windows. (DANB-674)\n- Renaming functionality for Labels is available to users when multiple Labels are selected. (case DANB-668)\n- Fixed SpriteSkin's playmode test failures. (case DANB-678)\n- Modifying the Sprite Skin component through public API.\n- Skinning Editor bone and mesh Visibility sliders too short. (case DANB-681)" + "changelog": "### Fixed\n- Animation Preview window sometimes does not display deformed Sprites. (DANB-705)\n- Sprite Resolver missing sprite previews when dealing with large number of entries. (DANB-714)\n- Misaligned label previews in Sprite Resolver's inspector. (DANB-722)\n- Sprite Resolver component not updated after Sprite Library Asset has been modified. (DANB-727)\n- Sprite Skin breaks in the animation preview window after sprite swap. (DANB-743)\n- IK gizmos are displayed in the SceneView when IKManager2D is active in Animation Preview window. (DANB-738)\n- IK solvers are misaligned when bones have different depths. (DANB-753)\n- Rendering issues with SRP Batching and Sprite mask. (DANB-760)\n- Unable to drag sprites into empty rows of the Sprite Library Editor. (DANB-749)\n- Sprite Skin deformation systems have outdated data after sprite swap. (DANB-766)\n- Setting incorrect computer buffer size. (DANB-768)\n- Reenable editor tests.\n- Bone buffer binding issues.\n- Sprite changed callback listeners." }, "upmCi": { - "footprint": "1ea284a7dd16d90a32f3ec73d4737b32b7622919" + "footprint": "6d111bdb7567b996250ec628b7c316b4b6ae8a89" }, "documentationUrl": "https://docs.unity3d.com/Packages/com.unity.2d.animation@10.1/manual/index.html", "repository": { "url": "https://github.cds.internal.unity3d.com/unity/2d.git", "type": "git", - "revision": "8e3a56a8fe7951b15f737aee13ba8a90be9d2dc5" + "revision": "c393ad93bdba3e78ebd30a5ccd2e6da5d8b92aba" } }