에셋 데이터베이스로 더 효과적으로 작업하기 위한 팁

에셋 임포트 파이프라인 v2는 Unity의 새로운 기본 에셋 파이프라인으로, 에셋 임포트 파이프라인 v1을 재작성된 에셋 데이터베이스로 대체하여 빠른 플랫폼 전환을 가능하게 합니다. 강력한 종속성 추적을 통해 확장 가능한 자산 가져오기를 위한 토대를 마련합니다. 에셋 데이터베이스의 작동 방식을 살펴보고 시간을 절약할 수 있는 몇 가지 팁을 알아보세요.
Unity 2019.3 출시 이후 새로운 에셋 임포트 파이프라인은 신규 프로젝트의 기본 파이프라인으로 사용되고 있습니다. 다른 많은 개선 사항과 결합하여 더욱 안정적이고 성능이 뛰어나며 확장 가능한 에셋 가져오기 파이프라인의 기반을 마련했습니다. 이 재작성으로 인해 새로운 워크플로우를 지원하기 위해 라이브러리 폴더의 작동 방식이 변경되었습니다.
발생할 수 있는 여러 가지 상황과 이를 효율적으로 관리하는 방법을 자세히 살펴보세요. 시간과 프로젝트 성과를 저해하는 몇 가지 병목 현상을 발견하고 해결하는 방법을 배웁니다.
여기에서 확인할 수 있는 팁은 Unity 2019.3 이상 버전에 적용됩니다. 프로젝트가 프로토타이핑을 넘어 프로덕션 단계에 있는 경우 안정성을 극대화하려면 최신 장기 지원(LTS) 버전인 Unity 2019 LTS를 사용할 것을 권장합니다.
먼저 새 프로젝트를 만들거나 에셋 라이브러리가 없는 프로젝트를 열 때 발생하는 몇 가지 상황에 대해 이야기해 보겠습니다.
Editor.log 파일을 보면 다음과 같은 줄이 많이 보입니다:
- 가져오기 시작 ...
- 가져오기 완료 ...
이는 에셋 임포트 파이프라인이 나중에 검사할 수 있도록 작업 흔적을 남기는 방식입니다.
이 정보를 사용하여 특정 유형의 병목 현상, 즉 에셋 가져오기 시간을 파악할 수 있습니다.
각 줄의 출력을 살펴보면 다음과 같은 데이터를 추출할 수 있습니다:
- 자산 경로
- 가져오기 기간
- 파일 확장자
그런 다음 해당 데이터를 구문 분석하여 확장자별로 분류할 수 있습니다. 어떤 임포터가 어떤 자산을 가져왔는지 파악한 후에는 해당 데이터를 집계하여 어떤 유형의 자산을 가져오는 데 가장 오래 걸리는지 보여주는 원형 차트에 표시할 수 있습니다. 예를 들면 다음과 같습니다.

이 데이터를 통해 프로젝트의 병목 지점을 보다 명확하게 파악할 수 있습니다.
이 특정 예제에서는 텍스처, 모델 및 프리팹이 가장 큰 시간 낭비 요인으로, 어떤 에셋을 최적화할 수 있는지 조사하기 위한 시작점을 제공합니다.
이 SimpleEditorLogParser 샘플 프로젝트를 다운로드하여 자체 구문 분석기의 기반으로 사용하세요.
어떤 에셋 카테고리를 가져오는 데 가장 오래 걸리는지 알 수 있으면 최적화 작업을 어디에 집중할지 계획하는 데 도움이 됩니다. 텍스처 임포트가 가장 오래 걸리는 카테고리인 경우 임포트하는 데 가장 오래 걸리는 텍스처를 살펴보고 최종 빌드에 포함되지 않는 텍스처를 제거하는 것이 좋습니다.
이렇게 하면 가져오기 시간이 빨라질 뿐만 아니라 야간 클린 빌드 등을 수행하는 경우 지속적 통합 파이프라인의 성능도 향상됩니다.
프로젝트를 빠르게 여는 것이 중요합니다. 에디터를 재시작하거나 하루 종일 여러 프로젝트를 여는 데 걸리는 시간은 소중한 시간을 낭비하는 시간이 될 수 있습니다.
프로젝트가 복잡해지고 더 많은 기능을 사용할수록 오픈하는 데 시간이 더 오래 걸립니다. 이는 여러 가지 요인 때문일 수 있으며, Unity 2019.3 이전에는 에디터가 실행되는 동안 프로파일러를 실행할 수 있는 방법이 없었습니다.
Unity를 열 때 제공할 수 있는 여러 명령줄 인수 중 -profiler-enable 명령줄 인수를 사용하면 실행 중에 에디터를 프로파일링할 수 있습니다.
이 명령은 에디터가 애플리케이션의 첫 번째 프레임에 대한 프로파일링 데이터(에디터가 표시될 때까지 실행되는 모든 코드)를 기록하기 시작하도록 지시합니다. 이 인수를 사용하면 시작 중에 어떤 일이 발생하고 시간이 걸리는지 확인할 수 있습니다. Unity의 시스템인지, 에셋 스토어 패키지인지, 프로젝트에 특정한 코드인지 확인할 수 있습니다. 이를 통해 다음에 수행할 작업을 파악하는 데 도움이 될 수 있습니다.

이 캡처에서 이 특정 프로젝트를 여는 데 약 50초가 걸리는 것을 볼 수 있습니다.
언뜻 보기에 에셋 데이터베이스를 로드하는 데 43초가 걸리는 것처럼 보입니다. 자세히 살펴보면 OnPostProcessAllAssets 호출에 14초가 소요되는 것을 확인할 수 있습니다. 더 아래로 내려가면 RegisterScriptsAndTryLoadingExistingUserAssemblies 중에 실행되는 코드가 최대 10초를 추가하고, 그 중 5.7초는 도메인을 로드하는 데 사용되며, [InitializeOnLoad] 속성이 있는 스크립트 호출로 인해 속도가 더 느려집니다.
이 시작 데이터는 성능 병목 현상을 추적하고 코드가 프로젝트에 있는지 아니면 Unity 자체에 있는지 확인하는 데 도움이 됩니다.
이제 라이브러리 폴더에는 동일한 에셋에 대한 여러 임포트 결과가 포함될 수 있으므로 새로운 에셋 임포트 파이프라인을 사용하는 프로젝트에는 더 이상 라이브러리 폴더에 "단순한" GUID(글로벌 고유 식별자)와 폴더 매핑이 없습니다.
라이브러리 폴더의 파일은 콘텐츠의 해시와 여러 정적 및 동적 종속성을 기반으로 합니다. 이를 통해 Unity는 빠른 플랫폼 전환, 에셋 중복 제거, 에셋 해시가 이미 라이브러리 폴더에 있는 경우 임포트 건너뛰기 등의 기능을 사용할 수 있습니다.
따라서 라이브러리 폴더에서 가져오기 결과를 찾는 것이 더 이상 사소하지 않습니다. 다음은 "Assets/Prefabs/MyPrefab.prefab"의 가져오기 결과를 어디에서 찾을 수 있는지 보여주는 예시입니다:
public class LibraryPathsForAsset
{
[MenuItem("AssetDatabase/OutputLibraryPathsForAsset")]
public static void OutputLibraryPathsForAsset()
{
var assetPath = "Assets/Prefabs/MyPrefab.prefab";
StringBuilder assetPathInfo = new StringBuilder();
var guidString = AssetDatabase.AssetPathToGUID(assetPath);
//The ArtifactKey is needed here as there are plans to
//allow importing for different platforms without switching
//platform, thus ArtifactKeys will be parametrized in the future
var artifactKey = new ArtifactKey(new GUID(guidString));
var artifactID = AssetDatabaseExperimental.LookupArtifact(artifactKey);
//Its possible for an Asset to have multiple import results,
//if, for example, Sub-assets are present, so we need to iterate
//over all the artifacts paths
AssetDatabaseExperimental.GetArtifactPaths(artifactID, out var paths);
assetPathInfo.Append($"Files associated with {assetPath}");
assetPathInfo.AppendLine();
foreach (var curVirtualPath in paths)
{
//The virtual path redirects somewhere, so we get the
//actual path on disk (or on the in memory database, accordingly)
var curPath = Path.GetFullPath(curVirtualPath);
assetPathInfo.Append("\t" + curPath);
assetPathInfo.AppendLine();
}
Debug.Log("Path info for asset:\n"+assetPathInfo.ToString());
}
}
다음은 다양한 버전의 Unity에 대한 두 가지 요점입니다:
샘플이 다른 이유는 에셋 임포트 파이프라인의 구현이 성숙해지면서 많은 API가 실험용 네임스페이스에서 에셋 데이터베이스의 자체 네임스페이스로 옮겨졌기 때문입니다.
종종 프로젝트에서 특정 에셋을 찾아 그 결과물로 무언가를 하고 싶을 때가 있습니다. 에디터 코드를 실행할 때 이 작업을 여러 번 수행할 수도 있습니다.
AssetDatabase.FindAssets를 호출하면 전체 프로젝트를 탐색하여 지정한 쿼리와 일치하는 항목을 찾습니다. 프로젝트 규모가 커질수록 다양한 크기의 프로젝트를 검색하는 데 걸리는 시간이 선형적으로 증가하기 때문에 성능 병목 현상이 발생할 수 있습니다.

예상대로 프로젝트에 자산이 많을수록 자산을 검색하는 데 걸리는 시간이 길어집니다. 다행히도 각 자산을 찾는 데 걸리는 시간은 시간이 지나도 어느 정도 안정적으로 유지됩니다.

보시다시피 프로젝트에 수십만 개의 에셋이 있는 경우 에셋을 검색하면 개발 속도가 눈에 띄게 느려질 수 있습니다. 자산이 200,000개일 경우 간단한 검색 쿼리에는 이미 200ms의 지연이 발생합니다.
무차별 대입 방식을 사용하면 이러한 일반적인 사용 패턴이 생성됩니다:
string[] assets = AssetDatabase.FindAssets ("t:texture2D");
if(assets.Length > 0)
{
string path = AssetDatabase.GUIDToAssetPath (guids[0]);
if (!string.IsNullOrEmpty (path))
{
Texture tex = AssetDatabase.LoadAssetAtPath<Texture>(path);
//Do something with this texture
}
}기본적으로 이 코드는 전체 프로젝트를 탐색하여 하나의 텍스처를 찾은 다음 이를 사용하여 무언가를 수행합니다.
에셋데이터베이스는 GUID로 에셋의 경로를 조회하는 방법을 제공합니다. 일치하는 항목이 있는지 배열을 반복하는 대신 키로 사전에서 무언가를 찾는다고 생각하면 됩니다.
무차별 대입 방식보다 이 접근 방식을 사용하면 에셋을 찾기 위해 전체 프로젝트를 살펴볼 필요가 없다는 이점이 있습니다. GUID를 데이터베이스 인덱스로 사용하고 해당 경로를 따라 에셋을 메모리에 로드할 수 있습니다.
예를 들어 에셋의 해당 .meta 파일에서 GUID를 찾을 수 있습니다:
fileFormatVersion: 2
guid: 9fc0d4010bbf28b4594072e72b8655ab
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
이 경우 이 에셋의 GUID는 9fc0d4010bbf28b4594072e72b8655ab입니다.
해당 정보가 주어지면 다음을 수행할 수 있습니다:
var path = AssetDatabase.GUIDToAssetPath("9fc0d4010bbf28b4594072e72b8655ab");
var asset = AssetDatabase.LoadAssetAtPath<Texture>(path);
이제 에셋을 사용할 준비가 되었습니다.
참고로 편집기 내에서 검색 속도를 높이고 싶다면 다음 도구도 알아두세요:
퀵서치 패키지를 사용하면 Unity의 여러 영역을 검색할 수 있습니다.
TypeCache를 사용하여 알고 있는 유형에서 파생된 스크립트를 검색할 수 있습니다.
일반적으로 에셋의 GUID는 일정합니다.
그러나 특정 상황에서는 에셋과 해당 .meta 파일이 중복되어 충돌이 발생하며, 이 충돌은 다음과 같은 방식으로 AssetDatabase가 해결합니다:
프로젝트 내의 폴더를 같은 프로젝트의 다른 위치에 복제하는 경우
에셋 스토어 패키지를 여러 번 임포트하거나 다른 프로젝트의 폴더를 내 프로젝트에 여러 번 복사하기
AssetDatabase.Refresh가 실행되면 프로젝트를 유효한 상태로 표시하기 위해 많은 시스템이 함께 작동해야 합니다. 유나이트 코펜하겐 강연에서 새로 고침이 호출될 때 일어나는 다양한 단계에 대해 자세히 설명합니다.
새로 고침 중에 실행되는 특정 콜백은 코드와 상호 작용합니다. 이는 새로 고침 작업이 완료되는 데 걸리는 시간에 영향을 줄 수 있습니다.
도메인 새로 고침 중에 실행되는 코드가 많을수록 편집기 환경이 느려집니다. 코드를 반복할 때 흐름을 유지하려면 코드를 언제 실행해야 하는지, 프로젝트 후반으로 연기할 수 있는지 신중하게 생각하세요.
도메인 새로 고침 중에 코드에 다음 메서드가 포함된 경우 코드가 실행됩니다:
1. Awake
2. OnEnable
3. OnValidate
이러한 메서드의 코드는 매우 빠르거나 다른 시간(예: 새로 고침 중이 아닌 다른 시간)에 실행되도록 지연되어야 하는 것이 이상적입니다. 이러한 콜백은 특정 상태를 복원하는 데 도움이 되지만 이러한 콜백 내에서 수행할 수 있는 작업에는 제한이 없기 때문에 확장되지 않는 코드(즉, 전체 프로젝트를 가로지르는 모든 코드)는 에디터가 열려 있는 동안 스크립트의 반복 속도를 느리게 합니다.
또 다른 접근 방식은 EditorApplication.delayCall을 사용하는 것인데, 이 경우 AssetDatabase가 디스크의 모든 변경 사항을 감지하고 임포트할 기회를 얻은 후 다음 에디터 틱에 코드가 실행됩니다.
Unity 포럼의 이 스레드를 팔로우하여 이 영역의 개선 사항에 대한 최신 소식을 받아보세요.
이 팁이 도움이 되었기를 바랍니다. 에셋 임포트 파이프라인에 대해 더 알고 싶은 사항이나 불편한 점이 있으면 알려주세요. 에셋 임포트 파이프라인을 개선하기 위해 적극적으로 노력하고 있으며, 에디터로 작업하고 에셋 및/또는 스크립트를 변경할 때 생산성을 높일 수 있도록 반복 작업을 최대한 즉각적으로 처리할 수 있도록 하고자 합니다.
