using UnityEditor; using UnityEngine; using System.Collections.Generic; using System.Linq; using System.IO; public class MaterialAndTextureMover : EditorWindow { public List targetObjects = new List(); public string targetFolder = "Assets/"; private List foundMaterials = new List(); private List materialSelectionStatus = new List(); private List foundTextures = new List(); private List textureSelectionStatus = new List(); private bool materialsSearched = false; private Vector2 scrollPos; [MenuItem("Tools/Material and Texture Mover")] public static void ShowWindow() { GetWindow("Material & Texture Mover"); } private void OnGUI() { GUILayout.Label("Step 1: Select Target Objects and Search Materials and Textures", EditorStyles.boldLabel); int removeIndex = -1; for (int i = 0; i < targetObjects.Count; i++) { GUILayout.BeginHorizontal(); targetObjects[i] = (GameObject)EditorGUILayout.ObjectField(targetObjects[i], typeof(GameObject), true); if (GUILayout.Button("Remove", GUILayout.Width(60))) { removeIndex = i; } GUILayout.EndHorizontal(); } if (removeIndex >= 0) { targetObjects.RemoveAt(removeIndex); } if (GUILayout.Button("Add Target Object")) { targetObjects.Add(null); } GUILayout.Space(10); if (GUILayout.Button("Search Materials and Textures")) { SearchMaterialsAndTextures(); materialsSearched = true; } GUILayout.Space(10); if (materialsSearched) { if (GUILayout.Button("Resolve Duplicated Names")) { ResolveDuplicatedNames(); } GUILayout.Space(10); } scrollPos = EditorGUILayout.BeginScrollView(scrollPos, GUILayout.Height(300)); if (materialsSearched && foundMaterials.Count > 0) { GUILayout.Label("Remapped Materials", EditorStyles.boldLabel); for (int i = 0; i < foundMaterials.Count; i++) { GUILayout.BeginHorizontal(); materialSelectionStatus[i] = EditorGUILayout.ToggleLeft(foundMaterials[i] ? foundMaterials[i].name : "None", materialSelectionStatus[i], GUILayout.Width(200)); if (foundMaterials[i] != null && GUILayout.Button("Ping", GUILayout.Width(50))) { EditorGUIUtility.PingObject(foundMaterials[i]); } GUILayout.EndHorizontal(); } } GUILayout.Space(10); if (materialsSearched && foundTextures.Count > 0) { GUILayout.Label("Remapped Textures", EditorStyles.boldLabel); for (int i = 0; i < foundTextures.Count; i++) { GUILayout.BeginHorizontal(); textureSelectionStatus[i] = EditorGUILayout.ToggleLeft(foundTextures[i] ? foundTextures[i].name : "None", textureSelectionStatus[i], GUILayout.Width(200)); if (foundTextures[i] != null && GUILayout.Button("Ping", GUILayout.Width(50))) { EditorGUIUtility.PingObject(foundTextures[i]); } GUILayout.EndHorizontal(); } } EditorGUILayout.EndScrollView(); GUILayout.Space(20); GUILayout.Label("Step 2: Select Target Folder and Move Materials and Textures", EditorStyles.boldLabel); GUILayout.BeginHorizontal(); EditorGUILayout.LabelField("Folder Path:", targetFolder); if (GUILayout.Button("Select Folder", GUILayout.Width(100))) { string selectedPath = EditorUtility.OpenFolderPanel("Select Target Folder", "Assets/", ""); if (!string.IsNullOrEmpty(selectedPath)) { if (selectedPath.StartsWith(Application.dataPath)) { targetFolder = "Assets" + selectedPath.Substring(Application.dataPath.Length); } else { Debug.LogError("Please select a folder within the Assets directory."); } } } GUILayout.EndHorizontal(); GUILayout.Space(10); if (GUILayout.Button("Move Materials and Textures")) { MoveMaterialsAndTextures(); } } private void SearchMaterialsAndTextures() { foundMaterials.Clear(); materialSelectionStatus.Clear(); foundTextures.Clear(); textureSelectionStatus.Clear(); foreach (var obj in targetObjects) { if (obj == null) continue; Renderer[] renderers = obj.GetComponentsInChildren(); foreach (var renderer in renderers) { foreach (var mat in renderer.sharedMaterials) { if (mat != null && !foundMaterials.Contains(mat)) { foundMaterials.Add(mat); materialSelectionStatus.Add(true); // 모든 텍스처 검색 Shader shader = mat.shader; for (int j = 0; j < ShaderUtil.GetPropertyCount(shader); j++) { if (ShaderUtil.GetPropertyType(shader, j) == ShaderUtil.ShaderPropertyType.TexEnv) { string propertyName = ShaderUtil.GetPropertyName(shader, j); Texture texture = mat.GetTexture(propertyName); if (texture != null && !foundTextures.Contains(texture)) { foundTextures.Add(texture); textureSelectionStatus.Add(true); } } } // 사용자 정의 속성 직접 검색 foreach (string propertyName in mat.GetTexturePropertyNames()) { Texture texture = mat.GetTexture(propertyName); if (texture != null && !foundTextures.Contains(texture)) { foundTextures.Add(texture); textureSelectionStatus.Add(true); } } } } } } Debug.Log("Materials and Textures found and listed."); } private void ResolveDuplicatedNames() { HashSet usedNames = new HashSet(); for (int i = 0; i < foundMaterials.Count; i++) { Material mat = foundMaterials[i]; string originalName = mat.name; int counter = 1; while (usedNames.Contains(mat.name)) { mat.name = $"{originalName}_{counter}"; counter++; } usedNames.Add(mat.name); } for (int i = 0; i < foundTextures.Count; i++) { Texture tex = foundTextures[i]; string originalName = tex.name; int counter = 1; while (usedNames.Contains(tex.name)) { tex.name = $"{originalName}_{counter}"; counter++; } usedNames.Add(tex.name); } Debug.Log("Duplicated names resolved."); } private void MoveMaterialsAndTextures() { if (!AssetDatabase.IsValidFolder(targetFolder)) { Debug.LogError("Target folder does not exist or is invalid."); return; } for (int i = 0; i < foundMaterials.Count; i++) { if (!materialSelectionStatus[i]) continue; Material mat = foundMaterials[i]; string path = AssetDatabase.GetAssetPath(mat); string targetPath = Path.Combine(targetFolder, Path.GetFileName(path)); if (AssetDatabase.LoadAssetAtPath(targetPath) != null) { Debug.LogWarning($"Material '{mat.name}' already exists in the target folder. Skipping."); continue; } if (!string.IsNullOrEmpty(path)) { string uniquePath = AssetDatabase.GenerateUniqueAssetPath(targetPath); AssetDatabase.MoveAsset(path, uniquePath); } } for (int i = 0; i < foundTextures.Count; i++) { if (!textureSelectionStatus[i]) continue; Texture tex = foundTextures[i]; string path = AssetDatabase.GetAssetPath(tex); string targetPath = Path.Combine(targetFolder, Path.GetFileName(path)); if (AssetDatabase.LoadAssetAtPath(targetPath) != null) { Debug.LogWarning($"Texture '{tex.name}' already exists in the target folder. Skipping."); continue; } if (!string.IsNullOrEmpty(path)) { string uniquePath = AssetDatabase.GenerateUniqueAssetPath(targetPath); AssetDatabase.MoveAsset(path, uniquePath); } } AssetDatabase.SaveAssets(); AssetDatabase.Refresh(); Debug.Log("Selected materials and textures moved successfully."); } }