diff --git a/CHANGELOG.md b/CHANGELOG.md index 56dddcb..db1f906 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ # Changelog +## [5.0.0-pre.1] - 2020-11-02 +### Added +- Added bone sharing from other PSDImporter file + ## [4.0.2] - 2020-08-31 ### Fixed - Fixed importing files with vector layers generates textures incorrectly (case 1266986) diff --git a/Documentation~/PSDImporter.md b/Documentation~/PSDImporter.md index bd5d7df..60faa57 100644 --- a/Documentation~/PSDImporter.md +++ b/Documentation~/PSDImporter.md @@ -1,5 +1,7 @@ # Summary +**Note: Documentation for version 5.0.0 is currently being updated.** + The PSD Importer is an Asset importer that is specialized for importing Adobe Photoshop .psb files into Unity and generating a Prefab made of Sprites based on the source file. The .psb file format is functionally identical to the more common Adobe .psd format and can support much larger images than the .psd format (up to 300,000 by 300,000 pixels in size). You can save or convert your Photoshop artwork files into the .psb format and import them into Unity with the PSD Importer. When you import .psb files with the PSD Importer, you can use features such as [Mosaic](#Mosaic) to automatically generate a Sprite sheet from the imported layers; or [Character Rig](#Rig) where Unity reassembles the Sprites of a character as they are arranged in their source files. @@ -219,4 +221,4 @@ namespace UnityEditor.U2D.PSD } } -``` \ No newline at end of file +``` diff --git a/Editor/PSDImporter.cs b/Editor/PSDImporter.cs index 3f0fc3c..2edfb10 100644 --- a/Editor/PSDImporter.cs +++ b/Editor/PSDImporter.cs @@ -10,7 +10,6 @@ using UnityEditor.U2D.Common; using UnityEditor.U2D.Sprites; using UnityEngine.Assertions; -using UnityEngine.Experimental.U2D.Animation; using UnityEngine.U2D; using UnityEngine.U2D.Animation; using UnityEngine.Scripting.APIUpdating; @@ -20,7 +19,7 @@ namespace UnityEditor.U2D.PSD /// /// ScriptedImporter to import Photoshop files /// - [ScriptedImporter(4, "psb")] + [ScriptedImporter(5, "psb")] [HelpURL("https://docs.unity3d.com/Packages/com.unity.2d.psdimporter@latest")] [MovedFrom("UnityEditor.Experimental.AssetImporters")] public class PSDImporter : ScriptedImporter, ISpriteEditorDataProvider @@ -114,17 +113,31 @@ struct BoneGO }; [SerializeField] + // SpriteData for both single and multiple mode List m_SpriteImportData = new List(); // we use index 0 for single sprite and the rest for multiple sprites [SerializeField] + // SpriteData for Mosaic mode List m_MosaicSpriteImportData = new List(); [SerializeField] + // SpriteData for Rig mode List m_RigSpriteImportData = new List(); + [SerializeField] + // CharacterData for Rig mode + CharacterData m_CharacterData = new CharacterData(); + [SerializeField] + // SpriteData for shared rig mode + List m_SharedRigSpriteImportData = new List(); + [SerializeField] + // CharacterData for shared rig mode + CharacterData m_SharedRigCharacterData = new CharacterData(); [SerializeField] List m_PlatformSettings = new List(); [SerializeField] bool m_MosaicLayers = true; [SerializeField] + bool m_CharacterMode = true; + [SerializeField] Vector2 m_DocumentPivot = Vector2.zero; [SerializeField] SpriteAlignment m_DocumentAlignment = SpriteAlignment.BottomCenter; @@ -141,7 +154,10 @@ struct BoneGO bool m_PaperDollMode = false; [SerializeField] - bool m_KeepDupilcateSpriteName = false; + bool m_KeepDupilcateSpriteName = true; + + [SerializeField] + private string m_SkeletonAssetReferenceID = null; [SerializeField] SpriteCategoryList m_SpriteCategoryList = new SpriteCategoryList() {categories = new List()}; @@ -170,16 +186,13 @@ internal int textureActualHeight [SerializeField] bool m_ResliceFromLayer = false; - [SerializeField] - bool m_CharacterMode = true; [SerializeField] List m_MosaicPSDLayers = new List(); [SerializeField] List m_RigPSDLayers = new List(); - [SerializeField] - CharacterData m_CharacterData = new CharacterData(); + List m_SharedRigPSDLayers = new List(); [SerializeField] bool m_GenerateGOHierarchy = false; @@ -192,6 +205,9 @@ internal int textureActualHeight [SerializeField] string m_SpriteLibAssetName = null; + + [SerializeField] + string m_SkeletonAssetName = null; [SerializeField] SecondarySpriteTexture[] m_SecondarySpriteTextures; @@ -261,6 +277,15 @@ public override void OnImportAsset(AssetImportContext ctx) { ImportFromLayers(ctx, doc); } + + if (!string.IsNullOrEmpty(m_SkeletonAssetReferenceID)) + { + var primaryAssetPath = AssetDatabase.GUIDToAssetPath(m_SkeletonAssetReferenceID); + if(!string.IsNullOrEmpty(primaryAssetPath) && primaryAssetPath != assetPath) + { + ctx.DependsOnArtifact(primaryAssetPath); + } + } } finally { @@ -271,9 +296,6 @@ public override void OnImportAsset(AssetImportContext ctx) EditorUtility.SetDirty(this); } - - // Debug Profiler. - // UnityEngine.Profiling.Memory.Experimental.MemoryProfiler.TakeSnapshot("snapshot.snap", MemorySnapshotFinish, CaptureFlags.ManagedObjects | CaptureFlags.NativeObjects | CaptureFlags.NativeAllocations | CaptureFlags.NativeStackTraces); } static void ValidatePSDLayerId(List layers, UniqueNameGenerator uniqueNameGenerator) @@ -574,12 +596,6 @@ void ImportFromLayers(AssetImportContext ctx, Document doc) foreach (var l in oldPsdLayers) l.Dispose(); } - - } - - void MemorySnapshotFinish(string path, bool done) - { - } void EnsureSingleSpriteExist() @@ -631,6 +647,8 @@ void RegisterAssets(AssetImportContext ctx, TextureGenerationOutput output) m_PrefabAssetName = GetUniqueName(string.Format("{0} Prefab", assetName), assetNameHash, true); if (string.IsNullOrEmpty(m_SpriteLibAssetName)) m_SpriteLibAssetName = GetUniqueName(string.Format("{0} Sprite Lib", assetName), assetNameHash, true); + if (string.IsNullOrEmpty(m_SkeletonAssetName)) + m_SkeletonAssetName = GetUniqueName(string.Format("{0} Skeleton", assetName), assetNameHash, true); output.texture.name = assetName; ctx.AddObjectToAsset(m_TextureAssetName, output.texture, output.thumbNail); @@ -666,6 +684,15 @@ void RegisterAssets(AssetImportContext ctx, TextureGenerationOutput output) slAsset.name = assetName; ctx.AddObjectToAsset(m_SpriteLibAssetName, slAsset); } + + if (characterMode && skeletonAsset == null) + { + var characterRig = ScriptableObject.CreateInstance(); + characterRig.name = assetName + " Skeleton"; + var bones = GetDataProvider().GetCharacterData().bones; + characterRig.SetSpriteBones(bones); + ctx.AddObjectToAsset(m_SkeletonAssetName, characterRig); + } } ctx.SetMainObject(mainAsset); } @@ -727,7 +754,7 @@ bool shouldResliceFromLayer bool characterMode { - get { return mosaicMode && m_CharacterMode == true; } + get { return mosaicMode && m_CharacterMode; } } float definitionScale @@ -796,7 +823,7 @@ void CreateBoneGO(int index, SpriteBone[] bones, BoneGO[] bonesGO, Transform def { go = go, index = index - }; + }; } BoneGO[] CreateBonesGO(Transform root) @@ -848,12 +875,13 @@ GameObject OnProducePaperDollPrefab(string assetname, Sprite[] sprites, SpriteLi var boneGOs = CreateBonesGO(root.transform); if (spriteLib != null) root.AddComponent().spriteLibraryAsset = spriteLib; + var currentCharacterData = characterData; for (int i = 0; i < sprites.Length; ++i) { string categoryName; if (SpriteIsMainFromSpriteLib(sprites[i].GetSpriteID().ToString(), out categoryName)) { - var spriteBones = m_CharacterData.parts.FirstOrDefault(x => new GUID(x.spriteId) == sprites[i].GetSpriteID()).bones; + var spriteBones = currentCharacterData.parts.FirstOrDefault(x => new GUID(x.spriteId) == sprites[i].GetSpriteID()).bones; var rootBone = root; if (spriteBones != null && spriteBones.Any()) { @@ -910,6 +938,7 @@ GameObject OnProducePrefab(string assetname, Sprite[] sprites, SpriteLibraryAsse CharacterData? characterSkeleton = characterMode ? new CharacterData ? (GetDataProvider().GetCharacterData()) : null; if (sprites != null && sprites.Length > 0) { + var currentCharacterData = characterData; var spriteImportData = GetSpriteImportData(); root = new GameObject(); root.name = assetname + "_GO"; @@ -946,7 +975,7 @@ GameObject OnProducePrefab(string assetname, Sprite[] sprites, SpriteLibraryAsse var spriteSkin = l.gameObject.AddComponent(); if (spriteRenderer.sprite != null && spriteRenderer.sprite.GetBindPoses().Length > 0) { - var spriteBones = m_CharacterData.parts.FirstOrDefault(x => new GUID(x.spriteId) == spriteRenderer.sprite.GetSpriteID()).bones.Where(x => x >= 0 && x < boneGOs.Length).Select(x => boneGOs[x]); + var spriteBones = currentCharacterData.parts.FirstOrDefault(x => new GUID(x.spriteId) == spriteRenderer.sprite.GetSpriteID()).bones.Where(x => x >= 0 && x < boneGOs.Length).Select(x => boneGOs[x]); if (spriteBones.Any()) { spriteSkin.rootBone = spriteBones.OrderBy(x => x.index).First().go.transform; @@ -1158,10 +1187,6 @@ internal T GetDataProvider() where T : class { return characterMode ? new CharacterDataProvider { dataProvider = this } as T : null; } - if (typeof(T) == typeof(ISpriteLibDataProvider)) - { - return new SpriteLibraryDataProvider() { dataProvider = this } as T; - } if (typeof(T) == typeof(ISecondaryTextureDataProvider)) { return new SecondaryTextureDataProvider() { dataProvider = this } as T; @@ -1184,7 +1209,6 @@ internal bool HasDataProvider(Type type) type == typeof(ISpriteOutlineDataProvider) || type == typeof(ISpritePhysicsOutlineDataProvider) || type == typeof(ITextureDataProvider) || - type == typeof(ISpriteLibDataProvider) || type == typeof(ISecondaryTextureDataProvider)) { return true; @@ -1272,12 +1296,44 @@ SpriteRect[] ISpriteEditorDataProvider.GetSpriteRects() List GetSpriteImportData() { - return mosaicMode ? (characterMode ? m_RigSpriteImportData : m_MosaicSpriteImportData) : m_SpriteImportData; + if (mosaicMode) + { + if (characterMode) + { + if (skeletonAsset != null) + { + return m_SharedRigSpriteImportData; + } + return m_RigSpriteImportData; + } + return m_MosaicSpriteImportData; + } + return m_SpriteImportData; + } + + private SkeletonAsset skeletonAsset + { + get + { + return AssetDatabase.LoadAssetAtPath( + AssetDatabase.GUIDToAssetPath(m_SkeletonAssetReferenceID)); + } } internal List GetPSDLayers() { - return mosaicMode ? (characterMode ? m_RigPSDLayers : m_MosaicPSDLayers) : null; + if (mosaicMode) + { + if (characterMode) + { + if (skeletonAsset != null) + return m_SharedRigPSDLayers; + else + return m_RigPSDLayers; + } + return m_MosaicPSDLayers; + } + return null; } internal SpriteMetaData[] GetSpriteMetaData() @@ -1290,6 +1346,8 @@ internal SpriteMetaData[] GetSpriteMetaData() internal SpriteRect GetSpriteDataFromAllMode(GUID guid) { var spriteMetaData = m_RigSpriteImportData.FirstOrDefault(x => x.spriteID == guid); + if(spriteMetaData == null) + spriteMetaData = m_SharedRigSpriteImportData.FirstOrDefault(x => x.spriteID == guid); if(spriteMetaData == null) spriteMetaData = m_MosaicSpriteImportData.FirstOrDefault(x => x.spriteID == guid); if(spriteMetaData == null) @@ -1356,8 +1414,19 @@ bool mosaicMode internal CharacterData characterData { - get { return m_CharacterData; } - set { m_CharacterData = value; } + get + { + if (skeletonAsset != null) + return m_SharedRigCharacterData; + return m_CharacterData; + } + set + { + if (skeletonAsset != null) + m_SharedRigCharacterData = value; + else + m_CharacterData = value; + } } internal Vector2Int documentSize @@ -1378,7 +1447,7 @@ SpriteLibraryAsset ProduceSpriteLibAsset(Sprite[] sprites) categoryList = x.labels.Select(y => { var sprite = sprites.FirstOrDefault(z => z.GetSpriteID().ToString() == y.spriteId); - return new Categorylabel() + return new SpriteCategoryEntry() { name = y.name, sprite = sprite @@ -1404,5 +1473,20 @@ internal void ReadTextureSettings(TextureImporterSettings dest) { m_TextureImporterSettings.CopyTo(dest); } + + internal SpriteBone[] mainRigBones + { + get + { + var rig = skeletonAsset; + if (rig != null) + { + return rig.GetSpriteBones(); + } + + return null; + } + } + } } diff --git a/Editor/PSDImporterDataProvider.cs b/Editor/PSDImporterDataProvider.cs index 7792287..c916fe3 100644 --- a/Editor/PSDImporterDataProvider.cs +++ b/Editor/PSDImporterDataProvider.cs @@ -234,7 +234,17 @@ public CharacterData GetCharacterData() } } + var cd = dataProvider.characterData; + cd.boneReadOnly = false; + var spriteBones = dataProvider.mainRigBones; + if (spriteBones != null) + { + cd.boneReadOnly = true; + cd.bones = spriteBones; + } + + var parts = cd.parts == null ? new List() : cd.parts.ToList(); var spriteRects = dataProvider.GetSpriteMetaData(); parts.RemoveAll(x => Array.FindIndex(spriteRects, y => y.spriteID == new GUID(x.spriteId)) == -1); @@ -263,8 +273,7 @@ public CharacterData GetCharacterData() else parts[srIndex] = cp; } - - var layers = dataProvider.GetPSDLayers(); + parts.Sort((x, y) => { return x.order.CompareTo(y.order); @@ -283,17 +292,4 @@ public void SetCharacterData(CharacterData characterData) dataProvider.characterData = characterData; } } - - internal class SpriteLibraryDataProvider : PSDDataProvider, ISpriteLibDataProvider - { - public SpriteCategoryList GetSpriteCategoryList() - { - return dataProvider.spriteCategoryList; - } - - public void SetSpriteCategoryList(SpriteCategoryList spriteCategoryList) - { - dataProvider.spriteCategoryList = spriteCategoryList; - } - } } diff --git a/Editor/PSDImporterEditor.cs b/Editor/PSDImporterEditor.cs index 825692c..5c7b842 100644 --- a/Editor/PSDImporterEditor.cs +++ b/Editor/PSDImporterEditor.cs @@ -8,6 +8,7 @@ using UnityEditor.U2D.Sprites; using UnityEngine; using UnityEngine.Scripting.APIUpdating; +using UnityEngine.U2D.Animation; namespace UnityEditor.U2D.PSD { @@ -55,12 +56,13 @@ public class PSDImporterEditor : ScriptedImporterEditor, ITexturePlatformSetting SerializedProperty m_GenerateGOHierarchy; SerializedProperty m_PaperDollMode; SerializedProperty m_KeepDupilcateSpriteName; + SerializedProperty m_SkeletonAssetReferenceID; + private SkeletonAsset m_SkeletonAsset; readonly int[] m_FilterModeOptions = (int[])(Enum.GetValues(typeof(FilterMode))); - bool m_IsPOT = false; + bool m_IsPOT = false; bool m_ShowAdvanced = false; - bool m_ShowExperimental = false; Dictionary m_AdvanceInspectorGUI = new Dictionary(); int m_PlatformSettingsIndex; bool m_ShowPerAxisWrapModes = false; @@ -85,6 +87,7 @@ public override void OnEnable() m_GenerateGOHierarchy = serializedObject.FindProperty("m_GenerateGOHierarchy"); m_PaperDollMode = serializedObject.FindProperty("m_PaperDollMode"); m_KeepDupilcateSpriteName = serializedObject.FindProperty("m_KeepDupilcateSpriteName"); + m_SkeletonAssetReferenceID = serializedObject.FindProperty("m_SkeletonAssetReferenceID"); var textureImporterSettingsSP = serializedObject.FindProperty("m_TextureImporterSettings"); m_TextureType = textureImporterSettingsSP.FindPropertyRelative("m_TextureType"); @@ -119,6 +122,8 @@ public override void OnEnable() var textureHeight = serializedObject.FindProperty("m_TextureActualHeight"); m_IsPOT = Mathf.IsPowerOfTwo(textureWidth.intValue) && Mathf.IsPowerOfTwo(textureHeight.intValue); + var assetPath = AssetDatabase.GUIDToAssetPath(m_SkeletonAssetReferenceID.stringValue); + m_SkeletonAsset = AssetDatabase.LoadAssetAtPath(assetPath); var advanceGUIAction = new Action[] { @@ -175,6 +180,20 @@ public override void OnInspectorGUI() serializedObject.ApplyModifiedProperties(); ApplyRevertGUI(); } + + void MainRigPropertyField() + { + EditorGUI.BeginChangeCheck(); + m_SkeletonAsset = EditorGUILayout.ObjectField(s_Styles.mainSkeletonName, m_SkeletonAsset, typeof(SkeletonAsset), false) as SkeletonAsset; + if (EditorGUI.EndChangeCheck()) + { + var referencePath = AssetDatabase.GetAssetPath(m_SkeletonAsset); + if (referencePath == ((AssetImporter) target).assetPath) + m_SkeletonAssetReferenceID.stringValue = ""; + else + m_SkeletonAssetReferenceID.stringValue = AssetDatabase.GUIDFromAssetPath(referencePath).ToString(); + } + } /// /// Implementation of AssetImporterEditor.Apply @@ -599,6 +618,7 @@ void DoSpriteInspector() GUILayout.EndHorizontal(); } //EditorGUILayout.PropertyField(m_PaperDollMode, s_Styles.paperDollMode); + MainRigPropertyField(); } @@ -608,13 +628,8 @@ void DoSpriteInspector() EditorGUILayout.HelpBox(s_Styles.resliceFromLayerWarning.text, MessageType.Info, true); } } - m_ShowExperimental = EditorGUILayout.Foldout(m_ShowExperimental, s_Styles.experimental, true); - if (m_ShowExperimental) - { - EditorGUI.indentLevel++; - EditorGUILayout.PropertyField(m_KeepDupilcateSpriteName, s_Styles.keepDuplicateSpriteName); - EditorGUI.indentLevel--; - } + + EditorGUILayout.PropertyField(m_KeepDupilcateSpriteName, s_Styles.keepDuplicateSpriteName); } using (new EditorGUI.DisabledScope(targets.Length != 1)) @@ -1092,8 +1107,8 @@ internal class Styles public readonly GUIContent generateGOHierarchy = new GUIContent(L10n.Tr("Use Layer Grouping"), L10n.Tr("GameObjects are grouped according to source file layer grouping")); public readonly GUIContent resliceFromLayer = new GUIContent(L10n.Tr("Reslice"), L10n.Tr("Recreate Sprite rects from file")); public readonly GUIContent paperDollMode = new GUIContent(L10n.Tr("Paper Doll Mode"), L10n.Tr("Special mode to generate a Prefab for Paper Doll use case")); - public readonly GUIContent experimental = new GUIContent(L10n.Tr("Experimental")); public readonly GUIContent keepDuplicateSpriteName = new GUIContent(L10n.Tr("Keep Duplicate Name"), L10n.Tr("Keep Sprite name same as Layer Name even if there are duplicated Layer Name")); + public readonly GUIContent mainSkeletonName = new GUIContent(L10n.Tr("Main Skeleton"), L10n.Tr("Main Skeleton to use for Rigging")); public Styles() { diff --git a/package.json b/package.json index ad63bd4..88a7a19 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,9 @@ { "name": "com.unity.2d.psdimporter", - "version": "4.0.2", - "unity": "2020.2", - "unityRelease": "0a19", + "version": "5.0.0-pre.1", + "unity": "2021.1", "displayName": "2D PSD Importer", - "description": "A ScriptedImporter for importing Adobe Photoshop PSB (Photoshop Big) file format. The ScriptedImporter is currently targeted for users who wants to create multi Sprite character animation using Unity 2D Animation Package.", + "description": "A ScriptedImporter for importing Adobe Photoshop PSB (Photoshop Big) file format. The ScriptedImporter is currently targeted for users who wants to create multi Sprite character animation using Unity 2D Animation Package.\n\nDocumentation for v5.0 is currently being updated.", "keywords": [ "2d", "psdimporter", @@ -12,19 +11,19 @@ ], "category": "2D", "dependencies": { - "com.unity.2d.common": "4.0.2", - "com.unity.2d.animation": "5.0.2", + "com.unity.2d.common": "5.0.0-pre.1", + "com.unity.2d.animation": "6.0.0-pre.1", "com.unity.2d.sprite": "1.0.0" }, "relatedPackages": { - "com.unity.2d.psdimporter.tests": "4.0.2" + "com.unity.2d.psdimporter.tests": "5.0.0-pre.1" }, "upmCi": { - "footprint": "37d303850b7c31729b17df490e53843ba578aada" + "footprint": "3efb2c8d304bb82110cabdbc7ba6451ee30e137b" }, "repository": { "url": "https://github.cds.internal.unity3d.com/unity/2d.git", "type": "git", - "revision": "4e96f68a7587d87b4fee15d6f88a5d86c2afa9aa" + "revision": "1f226d3f1c5c51421216a52396fba954b8b239de" } }