Unity 에셋 워크플로우: 폴더별 기본 프리셋 적용
개요
Unity에서는 대규모 프로젝트에서 다양한 에셋 타입을 효율적으로 관리하기 위해 폴더별로 기본 프리셋을 적용하는 방법을 제공합니다. 특히 텍스처 에셋과 같은 특정 유형의 에셋에 대해 서로 다른 프리셋을 사용할 수 있습니다.
주요 기능
- 폴더별 프리셋 적용
- 상위 폴더에서 프리셋 검색
- 기본 프리셋 사용
사용 방법
1단계: Editor 폴더 생성
먼저, Project 창에서 이름이 'Editor'인 새 폴더를 생성합니다.
2단계: C# 스크립트 생성
이 'Editor' 폴더에 새 C# 스크립트를 생성하고 아래의 코드를 복사하여 붙여넣습니다.
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.Experimental;
using UnityEditor.Presets;
using UnityEngine;
namespace PresetsPerFolder
{
public class EnforcePresetPostProcessor : AssetPostprocessor
{
void OnPreprocessAsset()
{
if (assetPath.StartsWith("Assets/") && !assetPath.EndsWith(".cs") && !assetPath.EndsWith(".preset"))
{
var path = Path.GetDirectoryName(assetPath);
ApplyPresetsFromFolderRecursively(path);
}
}
void ApplyPresetsFromFolderRecursively(string folder)
{
var parentFolder = Path.GetDirectoryName(folder);
if (!string.IsNullOrEmpty(parentFolder))
ApplyPresetsFromFolderRecursively(parentFolder);
context.DependsOnCustomDependency($"PresetPostProcessor_{folder}");
var presetPaths = Directory.EnumerateFiles(folder, "*.preset", SearchOption.TopDirectoryOnly).OrderBy(a => a);
foreach (var presetPath in presetPaths)
{
var preset = AssetDatabase.LoadAssetAtPath<Preset>(presetPath);
||
|---|
{
context.DependsOnArtifact(presetPath);
}
}
}
private static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths, bool didDomainReload)
{
if (didDomainReload)
{
var allPaths = AssetDatabase.FindAssets("glob:\"**.preset\"")
.Select(AssetDatabase.GUIDToAssetPath)
.OrderBy(a => a)
.ToList();
bool atLeastOnUpdate = false;
string previousPath = string.Empty;
Hash128 hash = new Hash128();
for (var index = 0; index < allPaths.Count; index++)
{
var path = allPaths[index];
var folder = Path.GetDirectoryName(path);
if (folder != previousPath)
{
if (previousPath != string.Empty)
{
AssetDatabase.RegisterCustomDependency($"PresetPostProcessor_{previousPath}", hash);
atLeastOnUpdate = true;
}
hash = new Hash128();
previousPath = folder;
}
hash.Append(path);
hash.Append(AssetDatabase.LoadAssetAtPath<Preset>(path).GetTargetFullTypeName());
}
if (previousPath != string.Empty)
{
AssetDatabase.RegisterCustomDependency($"PresetPostProcessor_{previousPath}", hash);
atLeastOnUpdate = true;
}
if (atLeastOnUpdate)
AssetDatabase.Refresh();
}
}
}
public class UpdateFolderPresetDependency : AssetsModifiedProcessor
{
protected override void OnAssetsModified(string[] changedAssets, string[] addedAssets, string[] deletedAssets, AssetMoveInfo[] movedAssets)
{
HashSet<string> folders = new HashSet<string>();
foreach (var asset in changedAssets)
{
if (asset.EndsWith(".preset"))
{
folders.Add(Path.GetDirectoryName(asset));
}
}
foreach (var asset in addedAssets)
{
if (asset.EndsWith(".preset"))
{
folders.Add(Path.GetDirectoryName(asset));
}
}
foreach (var asset in deletedAssets)
{
if (asset.EndsWith(".preset"))
{
folders.Add(Path.GetDirectoryName(asset));
}
}
foreach (var movedAsset in movedAssets)
{
if (movedAsset.destinationAssetPath.EndsWith(".preset"))
{
folders.Add(Path.GetDirectoryName(movedAsset.destinationAssetPath));
}
if (movedAsset.sourceAssetPath.EndsWith(".preset"))
{
folders.Add(Path.GetDirectoryName(movedAsset.sourceAssetPath));
}
}
if (folders.Count != 0)
{
EditorApplication.delayCall += () =>
{
DelayedDependencyRegistration(folders);
};
}
}
static void DelayedDependencyRegistration(HashSet<string> folders)
{
foreach (var folder in folders)
{
var presetPaths = AssetDatabase.FindAssets("glob:\"**.preset\"", new[] { folder })
.Select(AssetDatabase.GUIDToAssetPath)
.Where(presetPath => Path.GetDirectoryName(presetPath) == folder)
.OrderBy(a => a);
Hash128 hash = new Hash128();
foreach (var presetPath in presetPaths)
{
hash.Append(presetPath);
hash.Append(AssetDatabase.LoadAssetAtPath<Preset>(presetPath).GetTargetFullTypeName());
}
AssetDatabase.RegisterCustomDependency($"PresetPostProcessor_{folder}", hash);
}
AssetDatabase.Refresh();
}
}
}
코드 설명
- OnPreprocessAsset: 에셋 임포트 시 각 에셋 폴더를 확인하고, 해당 폴더의 프리셋을 찾아서 적용합니다.
- ApplyPresetsFromFolderRecursively: 모든 상위 폴더를 재귀적으로 탐색하여 프리셋을 적용합니다.
- OnPostprocessAllAssets: 프로젝트 로드 시 모든 임포트된 에셋에 대해 프리셋 의존성을 업데이트합니다.
- UpdateFolderPresetDependency: 에셋이 수정되거나 추가 및 삭제될 때 프리셋 의존성을 관리합니다.
활용 예제
이 스크립트를 활용하여 프로젝트 내에서 다양한 에셋 유형에 대해 개별적으로 프리셋을 관리할 수 있습니다. 예를 들어:
- 텍스처 에셋: 텍스처 프리셋을 통해 기본 불투명도 및 색상을 설정하여 품질을 일정하게 유지할 수 있습니다.
- 모델 에셋: FBX 모델의 애니메이션 및 머티리얼 프리셋을 활용하여 다양한 모델에 일관성을 부여할 수 있습니다.
이러한 방법을 통해 팀원 간의 에셋 품질을 보장하고, 프로젝트 유지보수를 용이하게 할 수 있습니다.
결론
Unity의 폴더별 기본 프리셋 적용 기능은 큰 프로젝트에서 에셋을 효율적으로 관리하고자 할 때 매우 유용한 도구입니다. 이를 통해 애니메이션, 텍스처, 모델 등 다양한 에셋의 품질을 유지하고 팀 작업의 일관성을 높일 수 있습니다.