using UnityEngine; using UnityEditor; using System.IO; using System.Collections.Generic; using XRLib; using XRLib.Util; using System.Threading.Tasks; #if UNITY_EDITOR using UnityEditor.AddressableAssets.Settings; using UnityEditor.AddressableAssets; #endif namespace XED { public class TwinObjectPreprocessingHelper { #if UNITY_EDITOR static List twinContainerList = new(); //[MenuItem("Tools/TwinObjectsSetting")] //public static void TwinObjectsSetting() //{ // AutomateTwinObjectSetup(); //} //Á¸ÀçÇÏÁö ¾ÊÀº Æú´õÀÇ °æ¿ì ÇØ´ç Æú´õ¸¦ »ý¼ºÇØÁÖ´Â ¸Þ¼­µå static void CreateFolder(string folderPath) { if (Directory.Exists(folderPath)) return; Directory.CreateDirectory(folderPath); } //TODO : °æ·Î¸¦ ÇϵåÄÚµù ÇÏ´Â ¹æ½Ä ÀÌ¿ÜÀÇ ´Ù¸¥ ¹æ½Ä Ȱ¿ë, Prefab ÀÇ À̸§ ÆÄ½ÌÀ» ÀÌ¿ëÇÑ ¹æ½Ä Ȱ¿ë(PRF_Robot01_Robot) static void AutomateTwinObjectSetup() { var mainPath = "Assets/Models/"; var beforePath = string.Concat(mainPath, "TwinObject_BeforeProcessing"); var afterPath = string.Concat(mainPath, "TwinObject_AfterProcessing/"); string etcPath = string.Concat(mainPath, "$etc"); CreateFolder(etcPath); CreateAddressableAssets(beforePath, etcPath, afterPath); TwinContainerAddressableSetting(twinContainerList); } static void CreateAddressableAssets(string beforePath, string etcPath, string afterPath) { //beforPath Æú´õ ¾ÈÀÇ Å¸ÀÔÀÌ ÇÁ¸®ÆÕÀÎ AssetÀÇ guid¸¦ ¸ðµÎ ã½À´Ï´Ù. string[] guids = AssetDatabase.FindAssets("t:Prefab", new string[] { beforePath }); foreach (var guid in guids) { //guid ¿¡ ÇØ´çÇÏ´Â Asset ÀÇ °æ·Î¸¦ ã½À´Ï´Ù. string filePath = AssetDatabase.GUIDToAssetPath(guid); if (filePath.StartsWith(etcPath)) { continue; } //°æ·Î¿¡ ÇØ´çÇÏ´Â Asset À» ã½À´Ï´Ù. var loadAsset = AssetDatabase.LoadAssetAtPath(filePath); var twinObject = loadAsset.GetComponent(); string fileName = Path.GetFileName(filePath); string fileNameWithoutExtension = Path.GetFileNameWithoutExtension(filePath); string folderPath = string.Concat(afterPath, fileNameWithoutExtension); string fullPath = string.Concat(folderPath, "/", fileName); //Àüó¸® ¿Ï·á Æú´õ¸¦ »ý¼ºÇÕ´Ï´Ù. CreateFolder(folderPath); //TwinContainer ¸¦ »ý¼ºÇÕ´Ï´Ù. var twinContainer = CreateTwinContainer(folderPath, twinObject); //TwinObject ¹Ì¸®º¸±â À̹ÌÁö¸¦ »ý¼ºÇÕ´Ï´Ù. var texture = CreateTwinObjectPortrait(folderPath, twinObject); //TwinObject ÀÇ ¸ðµ¨¸µ À§Ä¡, ÄݶóÀÌ´õ¸¦ ÃʱâÈ­ ÈÄ ÆÄÀÏ À§Ä¡¸¦ º¯°æÇÕ´Ï´Ù. SetTwinObject(loadAsset); var moveFilePath = MoveFiles(fileName, filePath, fullPath, etcPath); AssetDatabase.Refresh(); //TwinContainer ¿¡ µ¥ÀÌÅ͸¦ ÇÒ´çÇÕ´Ï´Ù. TwinContainerSetData(twinContainer, texture, moveFilePath); twinContainerList.Add(twinContainer); } } static TwinContainer CreateTwinContainer(string folderPath, TwinObject twinObject) { var twinContainer = ScriptableObject.CreateInstance(); var path = string.Concat(folderPath, "/", twinObject.name, ".asset"); AssetDatabase.CreateAsset(twinContainer, path); return twinContainer; } static Texture2D CreateTwinObjectPortrait(string folderPath, TwinObject twinObject) { Texture2D thumbnailTexture = null; //¹Ì¸®º¸±â ÅØ½ºÃ³ »ý¼º while (thumbnailTexture == null) { thumbnailTexture = AssetPreview.GetAssetPreview(twinObject.gameObject); System.Threading.Thread.Sleep(5); } var transparentTexture = BackgroundTransparencyProcess(thumbnailTexture); //ÅØ½ºÃ³ ÀúÀå transparentTexture.name = string.Concat("Texture_", twinObject.name); byte[] bytes = transparentTexture.EncodeToPNG(); string filePath = string.Concat(folderPath, "/", transparentTexture.name, ".png"); File.WriteAllBytes(filePath, bytes); AssetDatabase.Refresh(); //ÅØ½ºÃ³ ºÒ·¯¿À±â var texture = AssetDatabase.LoadAssetAtPath(filePath); return texture; } static Texture2D BackgroundTransparencyProcess(Texture2D texture) { var transparentTexture = new Texture2D(texture.width, texture.height); transparentTexture.SetPixels(texture.GetPixels()); for (int h = 0; h < texture.height; h++) { for (int w = 0; w < texture.width; w++) { transparentTexture.SetPixel(w, h, Color.clear); if (texture.GetPixel(w, h) != texture.GetPixel(w + 1, h)) break; } for (int w = texture.width; w > 0; w--) { transparentTexture.SetPixel(w, h, Color.clear); if (texture.GetPixel(w, h) != texture.GetPixel(w - 1, h)) break; } } transparentTexture.Apply(); return transparentTexture; } //ÀÛ¾÷ÀÌ ¿Ï·áµÈ ¸ðµ¨¸µÀ» Àüó¸® ¿Ï·á Æú´õ·Î À̵¿½ÃŰ´Â ¸Þ¼­µå static string MoveFiles(string fileName, string filePath, string fullPath, string etcPath) { if (File.Exists(fullPath) && (filePath != fullPath)) { int filenum = 0; string EtcFileName = string.Concat(etcPath, "/", fileName); while (File.Exists(EtcFileName)) { filenum++; EtcFileName = string.Concat(etcPath, "/", filenum.ToString(), "_", fileName); } fullPath = EtcFileName; } File.Move(filePath, fullPath); return fullPath; } static void TwinContainerSetData(TwinContainer twinContainer, Texture2D texture, string filePath) { var moveAsset = AssetDatabase.LoadAssetAtPath(filePath); var moveTwinObject = moveAsset.GetComponent(); twinContainer.twinObject = moveTwinObject; twinContainer.twinObjectPortrait = texture; } #region TwinObject Modeling °ú Collider ¸¦ ¼³Á¤ÇÏ´Â ¸Þ¼­µå //TwinObject ÀÇ Modeling ÀÇ À§Ä¡¿Í Collider ¸¦ ¼³Á¤ÇÏ´Â ¸Þ¼­µå static void SetTwinObject(GameObject twinObject) { var bounds = CalculateBounds(twinObject.transform); SetModelPosition(twinObject.transform, bounds); SetBoxCollider(twinObject.transform, bounds); } //TwinObject ÀÇ Bounds ¸¦ °è»êÇÏ´Â ¸Þ¼­µå static Bounds CalculateBounds(Transform twinObject) { var childRenderers = twinObject.GetComponentsInChildren(); var combinedBounds = childRenderers[0].bounds; foreach (var childRenderer in childRenderers) { combinedBounds.Encapsulate(childRenderer.bounds); } return combinedBounds; } //TwinObject ÀÇ ÄݶóÀÌ´õ¸¦ Å©±â¿¡ ¸Â°Ô ¼³Á¤ÇÏ´Â ¸Þ¼­µå static void SetBoxCollider(Transform twinObject, Bounds bounds) { var boxCollider = twinObject.GetOrAddComponent(); boxCollider.size = bounds.size; boxCollider.center = Vector3.zero; } //TwinObject ÀÇ ¸ðµ¨¸µ °´Ã¼ÀÇ À§Ä¡¸¦ ¼³Á¤ÇÏ´Â ¸Þ¼­µå static void SetModelPosition(Transform twinObject, Bounds bounds) { var twinObjectChild = twinObject.GetChild(0); twinObjectChild.position -= bounds.center; } #endregion #region TwinContainer ¸¦ Addressable Asset À¸·Î ¼³Á¤ÇÏ´Â ¸Þ¼­µå private static void TwinContainerAddressableSetting(List twinContainers) { foreach (var twinContainer in twinContainers) { AddressableSetting(twinContainer); } } //TwinContainer ÀÇ Addressable(Group, Label)À» ¼³Á¤ÇÏ´Â ¸Þ¼­µå private static void AddressableSetting(TwinContainer twinContainer) { AddressableAssetSettings settings = AddressableAssetSettingsDefaultObject.Settings; var path = AssetDatabase.GetAssetPath(twinContainer); var guid = AssetDatabase.AssetPathToGUID(path); var entry = settings.FindAssetEntry(guid); var label = twinContainer.twinObject.assetLabel.ToString(); var group = CreateOrFindGroup(settings, label); if (entry == null) { entry = settings.CreateOrMoveEntry(guid, group); } else { entry.address = path; } settings.MoveEntry(entry, group); entry.SetLabel(label, true); } //Addressable Group À» ã°í, ãÁö ¸øÇßÀ¸¸é ÇØ´ç Group À» »ý¼ºÇÏ°í ¹ÝȯÇÏ´Â ¸Þ¼­µå static AddressableAssetGroup CreateOrFindGroup(AddressableAssetSettings settings, string groupName) { var group = settings.FindGroup(groupName); if (group == null) group = settings.CreateGroup(groupName, false, false, true, null); return group; } #endregion #endif } }