반응형

AssetDatabase란?


Unity Editor상에서 모든 에셋 관련 파일 처리를 할때 사용하는 클래스로 기본 파일 입출력부터 Material, Prefab, Animationclip, CustomAsset등 파일을 만들고 제어 할 수 있습니다.


응용으로 프로젝트 내의 모든 씬파일을 찾아서 수정을 하거나, 현재 씬에 존재하는 오브젝트들을 자동으로 프리펩으로 만들어주는 기능을 만들 수 있습니다.


주의할 점은 AssetDatabase클래스는 Editor상에서만 동작하며 해당 코드를 사용하는 부분은 #if UNITY_EDITOR 조건 컴파일을 걸어야 빌드할때 에러나지 않습니다.

 

 

1. 파일탐색


string[] sAssetGuids = AssetDatabase.FindAssets("t:TextAsset", new[] { "Assets/JsonTest/Datas" });
string[] sAssetPathList = Array.ConvertAll<string, string>(sAssetGuids, AssetDatabase.GUIDToAssetPath);

foreach(string sAssetPath in sAssetPathList)
{
  TextAsset pAssetObject = AssetDatabase.LoadAssetAtPath(sAssetPath, typeof(TextAsset)) as TextAsset;
  Debug.Log("에셋 로드 : " + AssetDatabase_Function.GetAssetName(sAssetPath));
}

 

FindAsset

public static string[] FindAssets(string filter, string[] searchInFolders);
public static string[] FindAssets(string filter);

프로젝트의 Assets폴더안에 있는 에셋파일을 찾아서 가져오는 함수입니다.

찾은 에셋의 GUID를 string배열로 반환합니다.

 

- GUID란?

GUID는 Globally Unique IDentifier의 약자로 에셋의 고유 ID정보입니다.
프로젝트 내부에서 중복될일은 없으나 2개 이상 프로젝트에서 에셋이 와리가리 하면 중복될 가능성이 있습니다.

 

- string filter

co:이름 검색  (아마 contains?)

l:라벨 검색

t:Object의 type  (Scene, Material. Model, 등)

에셋가져오는 목록의 필터입니다.

 

예시

AssetDatabase.FindAssets ("co:Sword t:prefab t:material", new string[]{ "Assets/Weapons" });

 

라벨은 에셋의 Inspector 정보의 하단에 위치한 이것입니다.

 

- string[] searchInFolders

검색할 폴더입니다. "Assets/..."부터 입력하면 되고 여러 경로를 포함할 수 있습니다.

 

 

 

경로 가져오기

 string[] sAssetPathList = Array.ConvertAll<string, string>(sAssetGuids, AssetDatabase.GUIDToAssetPath);
 foreach(string sAssetPath in sAssetPathList)
 {
   TextAsset pAssetObject = AssetDatabase.LoadAssetAtPath(sAssetPath, typeof(TextAsset)) as TextAsset;
   Debug.Log("에셋 로드 : " + AssetDatabase_Function.GetAssetName(sAssetPath));
 }

이전에 GUID로 가져온 리스트를 AssetDatabase.GUIDToAssetPath을 통해서 실제 경로로 변환하고

LoadAssetAtPath함수를 통해 에셋으로 가져오면 됩니다.

 

 

 

추가 응용

public static class AssetDatabase_Function
{
    //! AssetPath를 넣으면 해당 에셋 파일 이름을 반환
    public static string GetAssetName(string sAssetPath)
    {
        string sAssetName = sAssetPath.Substring(sAssetPath.LastIndexOf("/") + 1);
        return sAssetName;
    }

    //! AssetPath를 넣으면 해당 에셋 파일 경로를 반환(파일 이름 제외)
    public static string GetAssetPath(string sAssetPath)
    {
        string sAssetName = sAssetPath.Substring(0, sAssetPath.LastIndexOf("/"));
        return sAssetName;
    }
}

AssetDatabase를 사용하다보면 에셋 이름만 가져오기, 경로가져오는 일이 많은데 편리하게 사용하기 위해 Static함수 만들 었습니다.

 

 

결과

 

 

 

2. 선택한 에셋 경로 가져오기


[MenuItem("Assets/GetAssetPath")]
static void GetAssetPath()
{
  UnityEngine.Object pSelectObj = Selection.activeObject;
  string sAssetPath = AssetDatabase.GetAssetPath(pSelectObj.GetInstanceID());
  Debug.Log(sAssetPath);
}

Selection.activeObject로 Project 탭에서 선택한 파일 포인터정보를 가져옵니다.

AssetDatabase.GetAssetPath(pSelectObj.GetInstanceID()); 그리고 이 코드를 통해 해당 에셋의 경로를 가져 올 수 있습니다.

 

 

 

 

3. 에셋 생성하기


 public static bool IsFolder(UnityEngine.Object obj)
    {
        if (obj == null) return false;

        string path = "";
        path = AssetDatabase.GetAssetPath(obj.GetInstanceID());
        if (path.Length > 0)
        {
            if (Directory.Exists(path)) return true;
        }
        return false;
    }

    public static bool IsExist(string sAssetPath)
    {
        if (string.IsNullOrEmpty(AssetDatabase.AssetPathToGUID(sAssetPath))) return false;
        return true;
    }



[MenuItem("Assets/CreaetMaterialFile")]
    static void CreaetMaterialFile()
    {
        UnityEngine.Object pSelectObj = Selection.activeObject;
        bool bIsFolder = AssetDatabase_Function.IsFolder(pSelectObj);
        if (bIsFolder == false)
        {
            Debug.LogError("폴더를 선택하세요.");
            return;
        }

        string sFolderPath = AssetDatabase.GetAssetPath(pSelectObj.GetInstanceID());
        string sAssetPath = string.Format(sFolderPath + "/{0}.mat", "TestMaterial");

        bool bIsExist = AssetDatabase_Function.IsExist(sAssetPath);
        if (bIsExist == true)
        {
            Debug.LogError("파일이 이미 존재함");
            return;
        }

        Material pMat = new Material(Shader.Find("Diffuse"));
        AssetDatabase.CreateAsset(pMat, sAssetPath);
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }

    [MenuItem("Assets/CreaetTextFile")]
    static void CreaetTextFile()
    {
        UnityEngine.Object pSelectObj = Selection.activeObject;
        bool bIsFolder = AssetDatabase_Function.IsFolder(pSelectObj);
        if (bIsFolder == false)
        {
            Debug.LogError("폴더를 선택하세요.");
            return;
        }

        string sFolderPath = AssetDatabase.GetAssetPath(pSelectObj.GetInstanceID());
        string sAssetPath = string.Format(sFolderPath + "/{0}.txt", "TestText");

        bool bIsExist = AssetDatabase_Function.IsExist(sAssetPath);
        if (bIsExist == true)
        {
            Debug.LogError("파일이 이미 존재함");
            return;
        }

        System.IO.FileInfo file = new System.IO.FileInfo(sAssetPath);
        file.Directory.Create();
        File.WriteAllText(file.FullName, "ABCDEFG");
        AssetDatabase.Refresh();
    }


    [MenuItem("Assets/CreaetPrefabFile")]
    static void CreaetPrefabFile()
    {
        UnityEngine.Object pSelectObj = Selection.activeObject;
        bool bIsFolder = AssetDatabase_Function.IsFolder(pSelectObj);
        if (bIsFolder == false)
        {
            Debug.LogError("폴더를 선택하세요.");
            return;
        }

        string sFolderPath = AssetDatabase.GetAssetPath(pSelectObj.GetInstanceID());
        string sAssetPath = string.Format(sFolderPath + "/{0}.prefab", "TestPrefab");

        bool bIsExist = AssetDatabase_Function.IsExist(sAssetPath);
        if (bIsExist == true)
        {
            Debug.LogError("파일이 이미 존재함");
            return;
        }

        GameObject pObj = GameObject.Find("TestPrefab");
        if (pObj == null) return;
        bool bSuccess = false;
        GameObject pPrefab = PrefabUtility.SaveAsPrefabAsset(pObj, sAssetPath, out bSuccess);
        if (bSuccess == true)
        {
            Debug.Log("레벨 프리펩 생성완료");
        }
        else
        {
            Debug.LogError("레벨 프리펩 생성 실패");
        }
        AssetDatabase.Refresh();
    }

위 예제 코드에서 핵심은 에셋은 다양한 수단으로 만들수 있으며 에셋을 생성후에

  AssetDatabase.Refresh(); 해야합니다.

(안하면 갱신이 안되는 문제가 발생합니다.)

 

위 코드를 통해 간단하게 3가지 형태의 에셋을 만드는 것을 해봤습니다.

 

 

 

4. 에셋 수정하기


 [MenuItem("Assets/EditModelFile")]
    static void EditModelFile()
    {
        UnityEngine.Object pSelectObj = Selection.activeObject;
        string sAssetPath = AssetDatabase.GetAssetPath(pSelectObj.GetInstanceID());
        string sAssetName = AssetDatabase_Function.GetAssetName(sAssetPath);
        if (sAssetName.Contains(".fbx") || sAssetName.Contains(".FBX"))
        {
            ModelImporter importer = AssetImporter.GetAtPath(sAssetPath) as ModelImporter;
            importer.materialImportMode = ModelImporterMaterialImportMode.None;
            importer.SaveAndReimport();
            EditorUtility.SetDirty(pSelectObj);
            AssetDatabase.Refresh();
        }
        else
        {
            Debug.LogError("FBX파일이 아닙니다.");
        }
    }

 이번엔 FBX에셋의 정보를 수정하는 코드를 작성했습니다.

간단하게 FBX의 마테리얼 Import 옵션을 끄는 코드입니다.

FBX는 다른 에셋과 달리 Refresh가 잘되지 않은 경험때문에

importer.SaveAndReimport();

EditorUtility.SetDirty(pSelectObj);
AssetDatabase.Refresh();

위 초기화 코드를 다 사용했습니다.

 

 

 

 

 

풀 소스 코드

#if UNITY_EDITOR
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;

public static class AssetDatabase_Function
{
    //! AssetPath를 넣으면 해당 에셋 파일 이름을 반환
    public static string GetAssetName(string sAssetPath)
    {
        string sAssetName = sAssetPath.Substring(sAssetPath.LastIndexOf("/") + 1);
        return sAssetName;
    }

    //! AssetPath를 넣으면 해당 에셋 파일 경로를 반환(파일 이름 제외)
    public static string GetAssetPath(string sAssetPath)
    {
        string sAssetName = sAssetPath.Substring(0, sAssetPath.LastIndexOf("/"));
        return sAssetName;
    }

    //! 해당 오브젝트가 폴더오브젝트인지 판단
    public static bool IsFolder(UnityEngine.Object obj)
    {
        if (obj == null) return false;

        string path = "";
        path = AssetDatabase.GetAssetPath(obj.GetInstanceID());
        if (path.Length > 0)
        {
            if (Directory.Exists(path)) return true;
        }
        return false;
    }

    public static bool IsExist(string sAssetPath)
    {
        if (string.IsNullOrEmpty(AssetDatabase.AssetPathToGUID(sAssetPath))) return false;
        return true;
    }
}


public class ADBTest
{
    [MenuItem("AssetDataBaseTest/GetAllFiles")]
    static void EditorWindow()
    {
        string[] sAssetGuids = AssetDatabase.FindAssets("t:TextAsset", new[] { "Assets/JsonTest/Datas" });
        string[] sAssetPathList = Array.ConvertAll<string, string>(sAssetGuids, AssetDatabase.GUIDToAssetPath);

        foreach(string sAssetPath in sAssetPathList)
        {
            TextAsset pAssetObject = AssetDatabase.LoadAssetAtPath(sAssetPath, typeof(TextAsset)) as TextAsset;
            Debug.Log("에셋 로드 : " + AssetDatabase_Function.GetAssetName(sAssetPath));
        }
    }

    [MenuItem("Assets/GetAssetPath")]
    static void GetAssetPath()
    {
        UnityEngine.Object pSelectObj = Selection.activeObject;
        string sAssetPath = AssetDatabase.GetAssetPath(pSelectObj.GetInstanceID());
        Debug.Log(sAssetPath);
    }

    [MenuItem("Assets/CreaetMaterialFile")]
    static void CreaetMaterialFile()
    {
        UnityEngine.Object pSelectObj = Selection.activeObject;
        bool bIsFolder = AssetDatabase_Function.IsFolder(pSelectObj);
        if (bIsFolder == false)
        {
            Debug.LogError("폴더를 선택하세요.");
            return;
        }

        string sFolderPath = AssetDatabase.GetAssetPath(pSelectObj.GetInstanceID());
        string sAssetPath = string.Format(sFolderPath + "/{0}.mat", "TestMaterial");

        bool bIsExist = AssetDatabase_Function.IsExist(sAssetPath);
        if (bIsExist == true)
        {
            Debug.LogError("파일이 이미 존재함");
            return;
        }

        Material pMat = new Material(Shader.Find("Diffuse"));
        AssetDatabase.CreateAsset(pMat, sAssetPath);
        AssetDatabase.SaveAssets();
        AssetDatabase.Refresh();
    }

    [MenuItem("Assets/CreaetTextFile")]
    static void CreaetTextFile()
    {
        UnityEngine.Object pSelectObj = Selection.activeObject;
        bool bIsFolder = AssetDatabase_Function.IsFolder(pSelectObj);
        if (bIsFolder == false)
        {
            Debug.LogError("폴더를 선택하세요.");
            return;
        }

        string sFolderPath = AssetDatabase.GetAssetPath(pSelectObj.GetInstanceID());
        string sAssetPath = string.Format(sFolderPath + "/{0}.txt", "TestText");

        bool bIsExist = AssetDatabase_Function.IsExist(sAssetPath);
        if (bIsExist == true)
        {
            Debug.LogError("파일이 이미 존재함");
            return;
        }

        System.IO.FileInfo file = new System.IO.FileInfo(sAssetPath);
        file.Directory.Create();
        File.WriteAllText(file.FullName, "ABCDEFG");
        AssetDatabase.Refresh();
    }


    [MenuItem("Assets/CreaetPrefabFile")]
    static void CreaetPrefabFile()
    {
        UnityEngine.Object pSelectObj = Selection.activeObject;
        bool bIsFolder = AssetDatabase_Function.IsFolder(pSelectObj);
        if (bIsFolder == false)
        {
            Debug.LogError("폴더를 선택하세요.");
            return;
        }

        string sFolderPath = AssetDatabase.GetAssetPath(pSelectObj.GetInstanceID());
        string sAssetPath = string.Format(sFolderPath + "/{0}.prefab", "TestPrefab");

        bool bIsExist = AssetDatabase_Function.IsExist(sAssetPath);
        if (bIsExist == true)
        {
            Debug.LogError("파일이 이미 존재함");
            return;
        }

        GameObject pObj = GameObject.Find("TestPrefab");
        if (pObj == null) return;
        bool bSuccess = false;
        GameObject pPrefab = PrefabUtility.SaveAsPrefabAsset(pObj, sAssetPath, out bSuccess);
        if (bSuccess == true)
        {
            Debug.Log("레벨 프리펩 생성완료");
        }
        else
        {
            Debug.LogError("레벨 프리펩 생성 실패");
        }
        AssetDatabase.Refresh();
    }


    [MenuItem("Assets/EditModelFile")]
    static void EditModelFile()
    {
        UnityEngine.Object pSelectObj = Selection.activeObject;
        string sAssetPath = AssetDatabase.GetAssetPath(pSelectObj.GetInstanceID());
        string sAssetName = AssetDatabase_Function.GetAssetName(sAssetPath);
        if (sAssetName.Contains(".fbx") || sAssetName.Contains(".FBX"))
        {
            ModelImporter importer = AssetImporter.GetAtPath(sAssetPath) as ModelImporter;
            importer.materialImportMode = ModelImporterMaterialImportMode.None;
            importer.SaveAndReimport();
            EditorUtility.SetDirty(pSelectObj);
            AssetDatabase.Refresh();
        }
        else
        {
            Debug.LogError("FBX파일이 아닙니다.");
        }
    }
}

#endif


 

반응형

WRITTEN BY
CatDarkGame
Technical Artist dhwlgn12@gmail.com

,