2023. 7. 13. 23:44ㆍUnity, C# 프로그래밍
회사에서 작업하면서 ScriptedImporter 를 적용해 보면서 자료를 많이 찾아봤었는데 쉽게 나오지 않았어서
다른 사람들도 보고 쉽게 따라할 수 있게 여기에 따로 정리한다.
총 2부로 구성해 볼 예정
1부는 ScriptedImporter 사용법.
2부는 내가 좀 찾는데 시간이 걸렸던 built-in 임포터에서 사용 중인 확장자의 임포터 오버라이드 방법.
ScriptedImporter란?
ScriptedImporter는 유니티에서 에셋을 임포트하는 AssetImporter를 사용자 정의할 수 있게 만든 클래스다.
이걸 설명하려면 먼저 에셋 임포터에 대해서 설명해야 하는데 알고 있는 사람들은 뒷부분으로 넘어가면 된다.
AssetImporter란?
먼저 AssetImporter에 대해서 설명하자면
유니티를 써본 사람이라면 다들 한번씩은 써봤을 Resources.Load<T>(string path) 함수.
이 함수를 쓰면 해당 경로에 있는 에셋을 불러오게 된다.
예시로 프로젝트 폴더 내에 "Assets/Resources/Player.png" 라는 파일이 존재할 때
런타임에서는 아래와 같이 텍스쳐 형식으로 불러올 수 있다.
var playerTexture = Resources.Load<Texture2D>("Player");
이때 png 파일은 로드할 경우 Texture2D 형식으로 불러오게 되는데,
이처럼 유니티는 각종 확장자들에 대해 어떤 형식으로 불러올지 정해져 있다.
txt 파일은 TextAsset 형식으로, prefab 파일은 GameObject 형식으로..
보통 여기까지는 다들 알고 있는 부분일텐데, 어떤 과정을 통해서 저렇게 가져올 수 있는지에 대해서는
딱히 신경쓰지 않았을 것이다.
유니티에서 이렇게 별다른 작업 없이 불러와지는 파일들은
내부적으로 유니티의 빌트인 임포터(Built-in Importer)에 의해 불러와지게 된다.
빌트인 임포터에 대해서는 유니티 공식 문서를 참고하면 되고, 보통은 C++ 레이어에서 처리하는 부분이라 디컴파일러로도 어차피 볼 수 없다. (어떤 확장자가 어떤 타입으로 로드되는지만 알면 된다)
유니티 빌트인 에셋 임포터 목록 : https://docs.unity3d.com/Manual/BuiltInImporters.html
에셋 임포터는 간단하게 알아봤고, 이제 ScriptedImporter에 대해 알아볼 차례다.
먼저 유니티에서는 내가 직접 만든 확장자(빌트인에 정의되지 않은 확장자)를 가진 파일의 에셋 로드가 일반적으로는 불가능하다.
예시로 프로젝트 폴더 내에 "Assets/Resources/MyAsset.myAsset" 이렇게 파일이 존재한다면?
아래와 같이 시도했을 때 로드에 실패해서 myAsset이 null인 것을 확인할 수 있다.
var myAsset = Resources.Load("MyAsset");
유니티에서는 이렇게 지원되지 않는 확장자에 대해서 로드할 수 있게 ScriptedImporter라는 기능을 추가했다.
위 코드 예제처럼 내가 만든 확장자를 가진 파일을 유니티에서 사용하고 싶다면 이 확장자에 대한 ScriptedImporter를 정의해줘야 한다.
ScriptedImporter 사용해보기
ScriptedImporter를 사용해 보려면 먼저 내가 만들 에셋 타입인 MyAsset의 정의를 해준다. (ScriptableObject로 만들었다)
(아래 클래스는 3가지 데이터를 담을 수 있게 준비했다)
using System;
using UnityEngine;
[Serializable]
[PreferBinarySerialization]
public sealed class MyAsset : ScriptableObject
{
public string stringData;
public float floatData;
public int intData;
}
이렇게 클래스를 정의했다면, 이 MyAsset으로 불러올 수 있게 .myAsset의 확장자를 가진 파일도 만들어 준다.
해당 파일은 간단하게 파싱하기 위해 위 클래스에 담을 3가지 데이터를 넣어뒀다.
stringData=Hello World
floatData=3.14
intData=1004
파일 이름은 확장자를 포함해서 MyAsset.myAsset 이다.
이때 파일 내용은 위와 같이 따라할 필요가 없고 내용을 json, xml 형식으로 만들 수도 있고 또는 바이너리 데이터를 넣어서 관리할 수도 있다.
여기에 어떤 내용을 넣게 되더라도 내가 만든 ScriptedImporter 에서 이 파일을 읽고 내 에셋 타입으로 바꿔줄 수만 있으면 된다.
마지막으로 .myAsset이라는 확장자를 가진 파일은 MyAsset 형식으로 로드할 수 있게 ScriptedImporter를 추가해 준다.
using System.IO;
using UnityEditor.AssetImporters;
using UnityEngine;
[ScriptedImporter(version: 1, ext: "myAsset")]
public sealed class MyAssetImporter : ScriptedImporter
{
public override void OnImportAsset(AssetImportContext ctx)
{
// ctx의 assetPath 경로에 있는 파일을 읽되,
// Unity의 임포트 관련 API말고 다른 API들을 사용해야 한다. (이 과정이 Importing!)
var lines = File.ReadAllLines(ctx.assetPath);
var myAsset = ScriptableObject.CreateInstance<MyAsset>();
// 그 후 내가 생각한 대로 파일을 파싱해 MyAsset을 설정해준다.
for (int i = 0; i < lines.Length; ++i)
{
var array = lines[i].Split('=');
if (array.Length < 2)
{
continue;
}
var key = array[0];
var value = array[1];
switch (key)
{
case "stringData": myAsset.stringData = value; break;
case "floatData": myAsset.floatData = float.Parse(value); break;
case "intData": myAsset.intData = int.Parse(value); break;
}
}
// Import Context에 내가 로드한 에셋을 등록해준다.
ctx.AddObjectToAsset("data", myAsset);
ctx.SetMainObject(myAsset);
}
}
위와 같이 임포터를 만들었다면 앞으로 .myAsset 이라는 확장자를 가진 파일은 유니티의 빌트인 임포터 대신 내가 정의한 임포터의 OnImportAsset() 을 통해 에셋을 임포트하게 된다.
여기서 조심할 점은
MyAsset 타입은 런타임에 로드해서 게임에 사용할 것이기 때문에 Assembly-CSharp 에 타입을 정의해주어야 하고,
MyAssetImporter 타입은 에디터에서 임포팅 타임에 호출될 것이기 때문에 Assembly-CSharp-Editor 에 정의해 주어야 한다.
(임포터를 통해 생성된 에셋은 런타임에는 임포터를 통해 생성되는것이 아니라 유니티 내부의 시리얼라이저를 통해 생성된다!)
이렇게 모두 추가했다면 .myAsset의 확장자를 가진 파일인 MyAsset.myAsset 에셋을 로드할 준비가 완료됐다!
유니티를 한번 Refresh해서 스크립트를 컴파일해주고 확인해 보면 아래와 같은 결과물을 확인할 수 있다.
만약 위와 같이 뜨지 않는다면 에셋을 우클릭 해서
다시 임포트(Reimport) 를 시도해보면 잘 된다.
Reimport 해도 뜨지 않는다면 위의 과정 중 무언가가 잘못됐을 가능성이 있다..
이제 내가 만든 에셋을 런타임에 Resources.Load<MyAsset>("MyAsset") 와 같이 사용해 로드하거나 인스펙터에 연결해서도 사용할 수 있게 됐다.
1부는 여기까지~
'Unity, C# 프로그래밍' 카테고리의 다른 글
유니티 에셋 번들 빌드 시간 단축 사례 (0) | 2024.02.01 |
---|---|
유니티 C# 개발 시 사용하기 좋은 툴 및 사이트 (2) | 2024.01.03 |
C#의 람다 (익명 함수) 사용 시 주의할 점 (2) | 2024.01.03 |
XML 데이터 로딩 최적화 사례 (1) | 2023.12.28 |
유니티 ScriptedImporter 써보기 2부 (0) | 2023.07.14 |