TECHARTNOMAD | TECHARTFLOWIO.COM

UNITY3D

TextureCopyPasteExtension

jplee 2025. 5. 9. 23:07

기능.

프로젝트 창에서 텍스처 선택 했다면 Ctrl+c 로 머티리얼에 적용 하려고 하는 텍스처를 리스트에 저장.

머티리얼 선택하고 Ctrl+p 하면 리스트에 저장했던 텍스처가 머티리얼 텍스처 프로퍼티에 등록됨.

드레그 엔 드랍 귀찮을 때 쓸만 함.

생성 : Claude AI

개선 가는성 : Yes

향후 개선 방향 : 프로퍼티 검증 룰베이스 추가 해서 고도화 가능해 보임.

TextureCopyPasteExtension.cs

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;

// Unity 6.1 호환 텍스처 복사/붙여넣기 확장 도구
public static class TextureCopyPasteExtension
{
    // 복사된 텍스처 저장 리스트
    private static List<Texture> textureClipboard = new List<Texture>();
    
    // 에디터 시작 시 한 번 호출되는 초기화 함수
    [InitializeOnLoadMethod]
    private static void Initialize()
    {
        // 이벤트 핸들러 등록
        EditorApplication.update += OnEditorUpdate;
        EditorApplication.projectWindowItemOnGUI += OnProjectItemGUI;
        SceneView.onSceneGUIDelegate += OnSceneGUI;
        
        Debug.Log("<color=#00FF88>텍스처 복사/붙여넣기 도구</color>: 초기화 완료. Ctrl+C/V 단축키를 사용할 수 있습니다.");
    }
    
    // 에디터 업데이트 이벤트
    private static void OnEditorUpdate()
    {
        // 인스펙터 창에서도 키 이벤트를 감지하기 위한 처리
        if (EditorWindow.focusedWindow != null && EditorWindow.focusedWindow.GetType().Name == "InspectorWindow")
        {
            Event e = Event.current;
            if (e != null)
            {
                // Ctrl+C 처리
                if (e.control && e.type == EventType.KeyDown && e.keyCode == KeyCode.C)
                {
                    TryHandleCopy();
                    e.Use();
                }
                
                // Ctrl+V 처리
                if (e.control && e.type == EventType.KeyDown && e.keyCode == KeyCode.V)
                {
                    TryHandlePaste();
                    e.Use();
                }
            }
        }
    }
    
    // 씬 뷰 GUI 이벤트 처리
    private static void OnSceneGUI(SceneView sceneView)
    {
        Event e = Event.current;
        
        // Ctrl+C 처리
        if (e.control && e.type == EventType.KeyDown && e.keyCode == KeyCode.C)
        {
            TryHandleCopy();
            e.Use();
        }
        
        // Ctrl+V 처리
        if (e.control && e.type == EventType.KeyDown && e.keyCode == KeyCode.V)
        {
            TryHandlePaste();
            e.Use();
        }
    }
    
    // 프로젝트 창 GUI 이벤트 처리
    private static void OnProjectItemGUI(string guid, Rect selectionRect)
    {
        Event e = Event.current;
        
        // Ctrl+C 처리
        if (e.control && e.type == EventType.KeyDown && e.keyCode == KeyCode.C)
        {
            TryHandleCopy();
            e.Use();
        }
        
        // Ctrl+V 처리
        if (e.control && e.type == EventType.KeyDown && e.keyCode == KeyCode.V)
        {
            TryHandlePaste();
            e.Use();
        }
    }
    
    // 복사 기능 처리
    private static bool TryHandleCopy()
    {
        // 프로젝트 창에서 현재 선택된 객체들 가져오기
        Object[] selectedObjects = Selection.GetFiltered<Object>(SelectionMode.Assets);
        
        // 리스트 초기화
        textureClipboard.Clear();
        
        bool hasTextureCopied = false;
        
        // 선택된 객체들 순회
        foreach (Object obj in selectedObjects)
        {
            // 텍스처 유형 확인 (Texture, Texture2D, Sprite 등)
            if (obj is Texture || AssetDatabase.GetMainAssetTypeAtPath(AssetDatabase.GetAssetPath(obj)) == typeof(Texture2D))
            {
                Texture texture = obj as Texture;
                if (texture != null)
                {
                    textureClipboard.Add(texture);
                    hasTextureCopied = true;
                    Debug.Log($"<color=#80FFFF>텍스처 복사</color>: {obj.name}");
                }
            }
            // 스프라이트도 처리
            else if (obj is Sprite)
            {
                Sprite sprite = obj as Sprite;
                if (sprite != null && sprite.texture != null)
                {
                    textureClipboard.Add(sprite.texture);
                    hasTextureCopied = true;
                    Debug.Log($"<color=#80FFFF>스프라이트 텍스처 복사</color>: {obj.name}");
                }
            }
        }
        
        if (hasTextureCopied)
        {
            // 팝업 대신 로그로 복사 완료 알림
            Debug.Log($"<color=#00FF00>복사 완료</color>: {textureClipboard.Count}개의 텍스처가 클립보드에 저장되었습니다.");
            return true;
        }
        
        return false;
    }
    
    // 붙여넣기 기능 처리
    private static bool TryHandlePaste()
    {
        // 클립보드에 텍스처가 없으면 아무 작업도 하지 않음
        if (textureClipboard.Count == 0)
        {
            return false;
        }
        
        // 현재 선택된 머티리얼 가져오기
        Object[] selectedObjects = Selection.objects;
        bool pasteSucceeded = false;
        
        foreach (Object obj in selectedObjects)
        {
            // 선택된 객체가 머티리얼인지 확인
            if (obj is Material)
            {
                Material material = obj as Material;
                
                // 현재 인스펙터에서 포커스된 컨트롤 이름 가져오기
                string focusedControlName = GUI.GetNameOfFocusedControl();
                
                // 포커스된 컨트롤이 없거나 머티리얼 인스펙터에서 처리해야할 경우
                // 가장 적합한 텍스처 슬롯 찾기
                ApplyTexturesToMaterial(material, focusedControlName);
                pasteSucceeded = true;
            }
        }
        
        if (pasteSucceeded)
        {
            // 에디터 리프레시 및 변경 내용 저장
            AssetDatabase.Refresh();
            return true;
        }
        
        return false;
    }
    
    // 머티리얼에 텍스처 적용
    private static void ApplyTexturesToMaterial(Material material, string focusedPropertyName)
    {
        if (material == null || textureClipboard.Count == 0)
            return;
            
        Texture textureToPaste = textureClipboard[0];
        bool applied = false;
        
        // 머티리얼 변경 기록 시작 (Undo 지원)
        Undo.RecordObject(material, "Paste Texture");
        
        // 포커스된 특정 프로퍼티가 있는 경우
        if (!string.IsNullOrEmpty(focusedPropertyName))
        {
            // 해당 프로퍼티에 텍스처 적용
            material.SetTexture(focusedPropertyName, textureToPaste);
            Debug.Log($"<color=#FFCC00>텍스처 붙여넣기 완료</color>: '{textureToPaste.name}'를 머티리얼 '{material.name}'의 '{focusedPropertyName}' 프로퍼티에 적용했습니다.");
            applied = true;
        }
        else
        {
            // 포커스된 프로퍼티가 없는 경우, 일반적인 텍스처 슬롯을 찾아 적용
            string[] commonTextureProperties = {
                "_MainTex", 
                "_BaseMap",
                "_BumpMap", 
                "_NormalMap",
                "_EmissionMap", 
                "_OcclusionMap", 
                "_MetallicGlossMap",
                "_SpecGlossMap",
                "_DetailAlbedoMap",
                "_DetailNormalMap"
            };
            
            // 이름을 기반으로 적절한 텍스처 슬롯 자동 선택
            string textureName = textureToPaste.name.ToLower();
            
            if (textureName.Contains("albedo") || textureName.Contains("diffuse") || textureName.Contains("color"))
            {
                TrySetTexture(material, new[] { "_MainTex", "_BaseMap" });
                applied = true;
            }
            else if (textureName.Contains("normal") || textureName.Contains("bump"))
            {
                TrySetTexture(material, new[] { "_BumpMap", "_NormalMap" });
                applied = true;
            }
            else if (textureName.Contains("emission") || textureName.Contains("emissive"))
            {
                TrySetTexture(material, new[] { "_EmissionMap" });
                applied = true;
            }
            else if (textureName.Contains("metallic") || textureName.Contains("smoothness"))
            {
                TrySetTexture(material, new[] { "_MetallicGlossMap" });
                applied = true;
            }
            else if (textureName.Contains("occlusion") || textureName.Contains("ao"))
            {
                TrySetTexture(material, new[] { "_OcclusionMap" });
                applied = true;
            }
            else if (textureName.Contains("specular") || textureName.Contains("glossiness"))
            {
                TrySetTexture(material, new[] { "_SpecGlossMap" });
                applied = true;
            }
            else
            {
                // 텍스처 이름으로 적절한 슬롯을 찾지 못한 경우 메인 텍스처에 적용
                TrySetTexture(material, new[] { "_MainTex", "_BaseMap" });
                applied = true;
            }
            
            // 텍스처가 적용된 경우 함수 종료
            if (applied)
                return;
                
            // 일반적인 텍스처 슬롯에 적용 시도
            foreach (string propName in commonTextureProperties)
            {
                if (material.HasProperty(propName))
                {
                    material.SetTexture(propName, textureToPaste);
                    Debug.Log($"<color=#FFCC00>텍스처 붙여넣기 완료</color>: '{textureToPaste.name}'를 머티리얼 '{material.name}'의 '{propName}' 프로퍼티에 적용했습니다.");
                    applied = true;
                    break;
                }
            }
        }
        
        // 아무 프로퍼티에도 적용하지 못한 경우
        if (!applied)
        {
            Debug.LogWarning($"<color=#FF6666>적용 실패</color>: 머티리얼 '{material.name}'에 적용할 수 있는 텍스처 프로퍼티를 찾지 못했습니다.");
        }
    }
    
    // 텍스처 적용 도우미 함수
    private static bool TrySetTexture(Material material, string[] propertyNames)
    {
        if (textureClipboard.Count == 0) return false;
        
        foreach (string propName in propertyNames)
        {
            if (material.HasProperty(propName))
            {
                material.SetTexture(propName, textureClipboard[0]);
                Debug.Log($"<color=#FFCC00>텍스처 붙여넣기 완료</color>: '{textureClipboard[0].name}'를 머티리얼 '{material.name}'의 '{propName}' 프로퍼티에 적용했습니다.");
                return true;
            }
        }
        
        return false;
    }
    
    // 메뉴에 항목 추가 (수동으로 텍스처 복사/붙여넣기 관리)
    [MenuItem("Assets/텍스처 복사", true)]
    private static bool ValidateTextureCopy()
    {
        return Selection.activeObject is Texture || Selection.activeObject is Sprite;
    }
    
    [MenuItem("Assets/텍스처 복사", false, 20)]
    private static void TexureCopyMenuItem()
    {
        TryHandleCopy();
    }
    
    [MenuItem("Assets/텍스처 붙여넣기", true)]
    private static bool ValidateTexturePaste()
    {
        return textureClipboard.Count > 0 && Selection.activeObject is Material;
    }
    
    [MenuItem("Assets/텍스처 붙여넣기", false, 21)]
    private static void TexurePasteMenuItem()
    {
        TryHandlePaste();
    }
}

// 텍스처 복사/붙여넣기 관리 윈도우
public class TextureCopyPasteWindow : EditorWindow
{
    // 복사된 텍스처 참조를 위한 변수
    private List<Texture> _clippedTextures = new List<Texture>();
    private Vector2 _scrollPosition;
    
    // 메뉴에 윈도우 항목 추가
    [MenuItem("Window/텍스처 복사 붙여넣기 관리")]
    public static void ShowWindow()
    {
        TextureCopyPasteWindow window = GetWindow<TextureCopyPasteWindow>("텍스처 복사/붙여넣기");
        window.minSize = new Vector2(300, 200);
    }
    
    private void OnGUI()
    {
        // 윈도우 제목 및 설명
        GUILayout.Label("텍스처 복사/붙여넣기 도구", EditorStyles.boldLabel);
        EditorGUILayout.Space();
        
        // 사용 방법 설명
        EditorGUILayout.HelpBox(
            "사용 방법:\n\n" +
            "1. 프로젝트 윈도우에서 텍스처를 선택하고 Ctrl+C를 누르세요.\n" +
            "2. 머티리얼을 선택한 후, 텍스처 프로퍼티 인터페이스의 빈칸을 클릭하고 Ctrl+V를 누르세요.\n\n" +
            "또는 컨텍스트 메뉴(우클릭)에서 '텍스처 복사'와 '텍스처 붙여넣기' 메뉴를 사용할 수 있습니다.",
            MessageType.Info);
        
        EditorGUILayout.Space(10);
        
        // 주의사항 설명
        EditorGUILayout.HelpBox(
            "주의사항:\n\n" +
            "1. 텍스처 프로퍼티에 포커스를 맞춘 상태에서 붙여넣기를 해야 정확한 슬롯에 적용됩니다.\n" +
            "2. 포커스가 없는 경우, 텍스처 이름을 기반으로 적절한 슬롯을 찾아 자동으로 적용합니다.",
            MessageType.Warning);
            
        // 스크립트의 private 필드에 직접 접근할 수 없으므로
        // UI만 표시하고 실제 데이터는 참조하지 못함
        EditorGUILayout.Space(10);
        EditorGUILayout.LabelField("이 도구는 Unity 6.1에 맞춰 최적화되었습니다.", EditorStyles.boldLabel);
    }
    
    // 업데이트 함수 (윈도우가 열려 있는 동안 주기적으로 호출)
    private void Update()
    {
        // 변화가 있으면 윈도우 갱신
        Repaint();
    }
}

'UNITY3D' 카테고리의 다른 글

Data Validation Toolset 개발. 버전 0.2  (0) 2025.05.23
적응형 CSM by FOV  (0) 2025.05.17
Unity Shading Rate  (0) 2025.04.03
내장 셰이더 벡터 파라메터  (1) 2025.03.03
Cursor AI IDE 와 UNITY3D 연동하여 개발하기.  (0) 2025.03.02