원문 : Assets, Objects and Serialization.

주의 : 번역이 개판이므로 원문을 참조하세요.

주의 : 허락받고 번역한 것이 아니므로 언제든 내려갈 수 있습니다.



Assets, Objects and Serialization


확인 완료한 버전 : 5.4 - 난이도 : 고급


이 기사는 유니티 5 의 애셋, 리소스, 그리고 리소스 관리를 다루는 기사 시리즈의 두 번째 챕터입니다.


이 챕터는 유니티의 직렬화 시스템의 내부 구현과 유니티 에디터와 런타임에서 서로 다른 오브젝트 간의 빠른 참조를 유지하는 방법에 대해서 다룹니다. 오브젝트와 애셋의 기술적인 차이에 대해서도 논의합니다. 여기에서 다루는 주제들은 유니티에서 애셋들을 효율적으로 로드하고 언로드하는 방법을 이해하기 위해서 필수적입니다. 적절한 애셋 관리는 로딩 시간을 짧게 유지하고 메모리 사용을 적게 하기 위해서 중요합니다.


1.1. Inside Assets and Objects


유니티에서 데이터를 적절하게 관리하기 위한 방법을 이해하기 위해서는, 유니티가 데이터를 식별하고 직렬화하는 방법을 이해하는 것이 중요합니다. 첫 번째 중요 지점은 애셋과 UnityEngine.Object 의 차이점입니다.


애셋은 디스크 상의 파일이며, 유니티 프로젝트의 Assets 폴더에 저장됩니다. 예를 들어, 텍스쳐 파일들, 머티리얼 파일들, FBX 파일들은 모두 애셋입니다. 어떤 애셋들은 머티리얼들처럼 유니티 포맷( formats native to Unity )들로 된 데이터를 포함합니다. FBX 파일과 같은 다른 애셋들은 자체 포맷( native formats )들로 처리될 필요가 있습니다.


대문자 'O' 로 시작하는 UnityEngine.Object( 혹은 Object ) 들은 리소스의 특정 인스턴스를 집합적으로 기술하는 직렬화된( serialized ) 데이터의 집합입니다. 이는 유니티 엔진이 사용하는 어떤 리소스 타입이든 될 수 있습니다. 그 예로는 메쉬( mesh ), 스프라이트( sprite ), 오디오 클립( AudioClip ), 애니메이션 클립( AnimationClip ) 등이 있습니다. 모든 오브젝트들은 UnityEngine.Object 기저 클래스의 서브클래스입니다.


대부분의 오브젝트 타입들은 내장 타입( built-in type )인데, 두 개의 특별한 타입들이 있습니다.


    1. ScriptableObject 는 개발자가 자신만의 데이터 타입을 정의할 수 있도록 해 주는 편리한 시스템을 제공합니다. 이 타입들은 유니티에 의해 자연스럽게 직렬화되고 역직렬화( deserialized )되며, 유니티 에디터의 인스펙터 윈도우에서 다뤄집니다.
    2. MonoBehaviourMonoScript 를 링크하는 래퍼( wrapper )를 제공합니다. MonoScript 는 유니티가 특정 어셈블리( assembly )나 네임 스페이스( namespace ) 내의 특정 스크립팅 클래스에 대한 참조를 유지하기 위해서 사용하는 내부 데이터 타입입니다. MonoScript 는 어떠한 실제 실행 코드도 포함하지 않습니다.


애셋과 오브젝트 사이에는 one-to-many 관계가 성립합니다; 즉 주어진 애셋 파일은 하나 이상의 오브젝트를 포함합니다.


1.2. Inter-Object References


모든 UnityEngine.Object 는 다른 UnityEngine.Object 들에 대한 참조를 가질 수 있습니다. 이 다른 오브젝트들은 같은 애셋 파일에 있을 수도 있고 다른 애셋 파일에 있을 수도 있습니다. 예를 들어 머티리얼 오브젝트는 항상 하나 이상의 텍스쳐 오브젝트에 대한 참조를 가집니다. 이 텍스쳐 오브젝트들은 일반적으로 ( PNG 나 JPG 같은 ) 하나 이상의 텍스쳐 애셋 파일들로부터 임포트( import )됩니다.


직렬화 시에, 이 참조들은 두 개의 개별 데이터 조각으로 구성됩니다: File GUIDLocal ID.  파일 GUID 는 대상 리소스가 저장되어 있는 애셋 파일을 식별합니다. 지역적으로 유일한 로컬 ID 는 애셋 파일 내의 각 오브젝트들을 식별합니다. 왜냐하면 애셋 파일은 여러 개의 오브젝트들을 포함할 수 있기 때문입니다.


파일 GUID 는 .meta 파일에 저장됩니다. 이 .meta 파일들은 애셋이 처음 임포트될 때 생성되며 애셋과 같은 디렉토리에 저장됩니다.


위의 식별자와 참조 시스템은 텍스트 에디터에서 확인할 수 있습니다: 새 유니티 프로젝트를 생성하고 그것의 에디터 셋팅을 Visible Meta Files 를 노출하고 애셋을 텍스트로 직렬화하도록 합니다. 그 프로젝트에서 머티리얼을 생성하고 텍스쳐를 임포트합니다. 그리고 씬에 있는 큐브에 머티리얼을 할당하고 씬을 저장합니다.


텍스트 에디터를 사용해, 위의 머티리얼과 연관된 .meta 파일을 엽니다. "guid" 라 표시된 라인은 파일의 거의 최상단에 보일 것입니다. 이 라인은 머티리얼 애셋의 파일 GUID 를 정의합니다. 로컬 ID 를 찾으려면, 텍스트 에디터에서 머티리얼 파일을 엽니다. 머티리얼 오브젝트의 정의는 다음과 같이 보일 것입니다:


--- !u!21 &2100000

Material:

 serializedVersion: 3

 ... more data ...


위의 예제에서, & 뒤에 나오는 숫자가 머티리얼의 로컬 ID 입니다. 만약 머티리얼 오브젝트가 파일 GUID "abcdefg" 에 의해서 식별되는 애셋 내부에 존재하면, 그 머티리얼 오브젝트는 파일 GUID "abcedfg" 와 로컬 ID "2100000" 의 조합에 의해 유일하게 식별될 것입니다.


1.3. Why file GUIDs and local IDs?



왜 유니티에서는 파일 GUID 시스템과 로컬 ID 시스템이 필요할까요? 그 대답은 신뢰성( robustness ) 및 유연하고 플랫폼 독립적인 워크플로우를 제공하기 위함입니다.


파일 GUID 는 파일의 특정 위치에 대한 추상화를 제공합니다. 특정 파일 GUID 가 특정 파일과 연관되어 있는 한, 그 파일의 디스크 상의 위치는 중요하지 않습니다. 그 파일은 파일을 참조하는 모든 오브젝트들을 갱신하지 않고도 자유롭게 이동될 수 있습니다.


애셋 파일은 다수 개의 UnityEngine.Object 리소스들을 포함할 수 있기 때문에( 혹은 임포트를 통해 생성할 수 있기 때문에 ), 로컬 ID 는 다른 오브젝트들과 명확하게 구분될 수 있을 것을 요구받습니다.


만약 애셋 파일과 연관된 파일 GUID 가 사라진다면, 그 애셋 파일 내부의 모든 오브젝트에 대한 참조도 사라질 것입니다. 이것이 .meta 파일이 그것이 연관된 애셋 파일과 같은 파일 이름을 가지고 같은 폴더에 저장되어야만 하는 이유입니다. 유니티는 제거되거나 위치가 잘못된 .meta 파일들을 자동으로 재생성한다는 점에 주의하십시오.


유니티 에디터는 알려진 파일 GUID 와 파일 경로에 대한 맵을 가지고 있습니다. 맵 엔트리는 애셋이 로드되거나 임포트될 때마다 기록됩니다. 맵 엔트리는 애셋의 특정 경로를 애셋의 파일 GUID 에 링크합니다. 만약 유니티 에디터가 .meta 파일이 사라졌지만 애셋의 경로가 변경되지 않았을 때 열리면, 에디터는 애셋이 같은 파일 GUID 를 유지하도록 해 줍니다.


만약 .meta 파일이 유니티 에디터가 닫히고 있을 때 사라지거나 .meta 파일은 그대로 두고 애셋 파일만 옮기면, 그 애셋 안의 모든 오브젝트에 대한 참조가 깨집니다.


1.4. Composite Assets and Importers


[ Inside Assets and Objects ] 에서 언급했듯이, non-native 애셋 타입들은 유니티에 임포트되어야만 합니다. 이는 애셋 임포터를 통해서 수행됩니다. 이 임포터들은 보통 자동으로 실행되지만, 그것들은 AssetImporter API 와 그것의 서브클래스를 통해 스크립트에 노출될 수도 있습니다. 예를 들어 TextureImporter API 는 PNG 나 JPG 와 같은 개별 텍스쳐 애셋을 임포트할 때 사용할 설정들에 대한 접근을 제공합니다.


임포트 절차의 결과는 하나 이상의 UnityEngine.Object 입니다. 이것들은 유니티 에디터에서 부모 애셋 내부의 다중 서브 애셋 형태로 가시화됩니다. 예를 들어 스프라이트 아틀라스로서 임포트된 텍스쳐 애셋 내부에 포함된 다중 스프라이트들이 있습니다. 각 오브젝트들은 같은 애셋 파일 내에 저장된 소스 데이터와 같은 파일 GUID 를 공유할 것입니다. 그것들은 임포트된 텍스쳐 애셋 내에서 로컬 ID 를 통해 구분될 것입니다.


임포트 절차는 소스 애셋을 유니티 에디터에서 선택한 대상 플랫폼에 맞는 포맷들로 변환합니다. 임포트 절차는 텍스쳐 압축과 같은 무거운 연산을 포함할 수 있습니다. 유니티 에디터가 열릴 때마다 임포트 절차가 수행되는 것은 매우 비효율적입니다.


대신에, 애셋 임포팅의 결과들은 Library 폴더로 캐싱됩니다. 특히, 임포트 절차의 결과는 폴더에 저장되는데, 폴더의 이름은 애셋 파일 GUID 의 처음 두 숫자입니다. 이 폴더는 LIbrary/metadata/ 폴더 내부에 저장됩니다. 개별 오브젝트들은 하나의 바이너리 파일로 직렬화되는데, 그것은 애셋 파일 GUID 와 동일한 이름을 가지게 됩니다.


이는 실제적으로 non-native 애셋들뿐만 아니라 모든 애셋에 대해 사실입니다. 그러나 native 애셋들은 장황한 변환 절차나 재직렬화를 요구하지 않습니다.


1.5. Serialization and Instances


파일 GUID 와 로컬 ID 가 신뢰성있기는 하지만, GUID 비교는 느리며 실시간에 좀 더 성능이 좋은 시스템이 필요합니다. 유니티는 내부적으로 파일 GUID 와 로컬 ID 를 단순한 정수로 변환하는 캐시를 유지합니다. 이 캐시는 싱글 세션에서만 유일합니다. 이들은 인스턴스 ID 라 불립니다. 그리고 새로운 오브젝트가 캐쉬에 등록될 때 단순한 점진적으로 증가하는 순서로 할당됩니다.


그 캐쉬는 주어진 인스턴스 ID( 오브젝트의 소스 데이터의 위치를 정의하는 파일 GUID 와 로컬 ID ) 와 메모리 상의 오브젝트 인스턴스 사이의 매핑을 유지합니다. 이는 UnityEngine.Object 들이 서로에 대한 참조를 신뢰성있게 유지할 수 있도록 해 줍니다. 인스턴스 ID 참조에 대한 resolving 은 인스턴스 ID 에 의해 표현되는 로드된 오브젝트를 빠르게 반환할 수 있습니다. 만약 대상 오브젝트가 아직 로드되지 않았다면, 파일 GUID 와 로컬 ID 는 오브젝트의 소스 데이터에 대해 resolve 될 수 있으며, 그 후에 유니티는 오브젝트를 제때( just-in-time ) 로드할 수 있습니다.


시작시에, 프로젝트에 내장된 모든 오브젝트( 예를 들어 씬에서 참조되는 )와 Resources 폴더에 포함된 모든 오브젝트를 위한 데이터를 사용해 인스턴스 ID 캐시가 초기화됩니다. 런타임에 새로운 애셋이 임포트되거나 애셋 번들로부터 오브젝트가 로드될 때 새로운 엔트리가 캐쉬에 추가됩니다. 인스턴스 ID 엔트리는 오브젝트가 무효화될( stale ) 때만 캐쉬에서 제거될 것입니다. 이는 특정 파일 GUID 와 로컬 ID 에 대한 애셋번들이 언로드될 때 발생합니다.


애셋 번들을 언로딩이 인스턴스 ID 를 무효화할 때, 메모리 보존을 위해 인스턴스 ID 와 그것의 파일 GUID 및 로컬 ID 사이의 매핑이 제거됩니다. 만약 애셋 번들이 다시 로드되면, 새로운 인스턴스 ID 가 다시 로드된 애셋 번들로부터 로드된 오브젝트를 위해서 생성될 것입니다.


애셋 번들을 언로드하는 것의 영향에 대한 더 깊은 논의를 원한다면, AssetBundle Usage Patterns 기사의 Managing Loaded Assets 섹션을 참조하십시오.


특정 플랫폼에서의 특정 이벤트는 오브젝트를 out of memory 상태로 이끌 수 있습니다. 예를 들어 앱이 중단되면( suspended ), iOS 상의 그래픽스 메모리로부터 그래피컬 애셋들이 언로드될 수 있습니다. 만약 이 오브젝트들이 언로드된 애셋 번들로부터 만들어진 것이라면, 유니티는 그 오브젝트를 위해 소스 데이터를 다시 로드하는 것이 불가능할 것입니다. 이러한 오브젝트들에 대한 현존하는 참조들도 무효화될 것입니다. 앞의 예에서, 안 보이는( 없어진 ) 메쉬나 마젠타( 없어진 ) 텍스쳐 & 머티리얼을 가진 것처럼 오브젝트가 렌더링 될 것입니다.


구현 노트 : 런타임에 위의 컨트롤 플로우는 문자 그대로 정확한 것은 아닙니다. 파일 GUID 와 Local ID 를 런타임에 비교하는 것은 무거운 로딩 연산 동안에는 충분히 효율적이지 못할 것입니다. 유니티 프로젝트에서 빌드를 할 때, 파일 GUID 와 Local ID 는 결정론적으로( deterministically ) 더 단순한 포맷으로 매핑됩니다. 그러나 그 개념은 동일하게 남아 있으며, 파일 GUID 와 로컬 ID 항에 대한 생각은 런타임 동안에 유용한 비유( analogy )로 남아 있게 됩니다.


이것은 애셋 파일 GUID 가 런타임에 질의될( queried ) 수 없는 이유이기도 합니다.


1.6. MonoScript


MonoBehaviour 가 MonoScript 에 대한 참조를 가지고 있고, MonoScript 는 단순히 특정 스크립트 클래스를 배치하기 위해서 필요한 정보만을 유지한다는 것을 이해하는 것은 중요합니다. 어떠한 유형의 오브젝트라도 스크립트 클래스의 실행 코드를 포함하지는 않습니다.


MonoScript 는 세 가지 문자열을 포함합니다: 어셈블리 이름, 클래스 이름, 네임스페이스.


프로젝트를 빌드할 때, 유니티는 모든 loose script file 을 Assets 폴더에서 수집해서 그것들을 모노 어셈블리로 컴파일합니다. 특히, 유니티는 Assets 폴더 내에서 사용된 각각의 다른 언어들을 위한 어셈블리를 빌드합니다. 또한 Assets/Plugins 폴더에 포함된 스크립트를 위한 독립된 어셈블리를 빌드합니다. Plugins 서브 폴더 외부의 C# 스크립트들은 Assembly-CSharp.dll 에 배치됩니다. Plugins 서브 폴더 내부의 스크립트들은 Assembly-CSharp-firstPass.dll 에 배치되는 식입니다.


( 미리 빌드된 어셈블리 DLL 들과 함께 ) 이 어셈블리들은 유니티 애플리케이션의 최종 빌드에 포함됩니다. 그것들은 MonoScript 가 참조하는 어셈블리이기도 합니다. 다른 리소스들과는 다르게, 유니티 애플리케이션에 포함된 모든 어셈블리들은 애플리케이션이 처음 시작될 때 로드됩니다.


이 MonoScript 오브젝트는 애셋번들( 혹은 씬 혹은 프리팹 )이 내부에 있는 MonoBehaviour 컴포넌트들 내의 어떠한 실행 코드도 포함하고 있지 않은 이유입니다. 이는 서로 다른 MonoBehaviour 들이 특정 공유 클래스나 심지어는 다른 애셋 번들에 존재하는 MonoBehaviour 들을 참조할 수 있도록 해 줍니다.


1.7. Resource LifeCycle


UnityEngine.Object 들은 특정 시점에 메모리에 로드되거나 메모리로부터 언로드됩니다. 로딩 시간을 줄이고 애플리케이션의 메모리 사용량을 줄이기 위해서는, UnityEngine.Object 들의 리소스 생명 주기에 대해서 이해하는 것이 중요합니다.


UnityEngine.Object 를 로드하는 두 가지 방법이 있습니다: 오브젝트는 자동으로 혹은 명시적으로. 역참조되고( dereferenced ) 있으며 현재 메모리에 로드되지 않았으며 오브젝트 소스 데이터가 정확한 위치에 있는 오브젝트에 인스턴스 ID 가 매핑되었을 때 자동으로 로드됩니다. 오브젝트는 그것들을 생성하거나 리소스 로딩 API( 예를 들어 AssetBundle.LoadAsset ) 를 호출함을써 스크립트를 통해 명시적으로 로드될 수 있습니다.


오브젝트가 로드될 때, 유니티는 각 참조의 파일 GUID 와 로컬 ID 를 인스턴스 ID 로 변환함으로써 모든 참조를 resolve 하려 시도합니다.


두 가지 조건만 만족한다면, 오브젝트는 자신의 인스턴스 ID 가 처음으로 역참조될 때 요구에 의해( on-demand ) 로드될 것입니다:


    1. 인스턴스 ID 가 현재 로드되지 않은 오브젝트를 참조할 때.
    2. 인스턴스 ID 가 캐시에 등록된 올바른 파일 GUID 와 로컬 ID 를 가질 때.


이는 일반적으로 참조가 스스로 로드되고 resolve 된 후에 매우 짧은 시간에 발생합니다.


만약 파일 GUID 와 로컬 ID 가 인스턴스 ID 를 가지고 있지 않거나, 언로드된 오브젝트를 가진 인스턴스 ID 가 유효하지 않은 파일 GUID 와 로컬ID 를 참조한다면, 그 참조는 보존되고 실제 오브젝트는 로드되지 않을 것입니다. 이는 유니티에서 "(Missing)" 참조라고 나옵니다. 실행중인 애플리케이션이나 씬뷰에서는 "(Missing)" 참조가 그것들의 유형에 따라 다른 방식으로 가시화될 것입니다: 메쉬들은 비가시화 상태가 되고, 텍스쳐들은 마젠타로 나타나는 식입니다.


오브젝트들은 세 가지 특정 시나리오에서 언로드됩니다:


    1. 오브젝트들은 사용되지 않는 애셋들을 클린업할 때 자동으로 언로드됩니다. 이 절차는 씬들이 파괴될 때( Application.LoadLevel API 를 non-additive 방식으로 호출할 때 )나 스크립트에서 Resources.UnloadUnusedAssets API 를 호출할 때 자동으로 발동합니다. 이 절차는 참조가 없는( unreferenced ) 오브젝트들만을 언로드합니다: Mono 변수가 그 오브젝트에 대한 참조를 가지고 있지 않거나 그 오브젝트에 대한 참조를 가진 살아 있는 오브젝트가 하나도 없을 때만 오브젝트가 언로드될 것입니다.
    2. Resources 폴더로부터 생성된 오브젝트들은 Resources.UnloadAsset API 를 호출함으로써 명시적으로 언로드될 수 있습니다. 이러한 오브젝트들의 인스턴스 ID 는 유효한 상태로 유지되며, 여전히 유효한 파일 GUID 와 로컬 ID 엔트리를 포함할 것입니다. 어떤 Mono 변수나 다른 오브젝트가 Resources.UnloadAsset 을 사용해 언로드된 오브젝트에 대한 참조를 가지고 있다면, 그 오브젝트는 살아 있는 참조가 역참조되자 마자 다시 로드될 것입니다.
    3. 애셋번들로부터 생성된 오브젝트들은 AssetBundle.Unload(true) API 를 호출할 때 자동으로 즉시 언로드됩니다. 이는 오븢게트의 InstanceID 의 파일 GUID 와 로컬 ID 참조를 무효화하며, 언로드된 오브젝트에 대한 살아 있는 모든 참조들은 "(Missing)" 참조가 될 것입니다. C# 스크립트에서, 언로드된 오브젝트에 대한 메서드나 프라퍼티에 접근하는 것은 NullReferenceException 을 생성하게 될 것입니다.


AssetBundle.Unload(false) 가 호출되면, 언로드된 애셋번들로부터 생성된 살아 있는 오브젝트들은 파괴되지 않을 것입니다. 하지만 유니티는 그것들의 인스턴스 ID 의 파일 GUID 와 로컬 ID 참조를 무효화시킬 것입니다. 만약 나중에 오브젝트가 메모리에서 언로드되고 언로드된 오브젝트에 대한 살아 있는 참조들이 유지되고 있다면, 이 오브젝트들을 유니티가 다시 로드하는 것은 불가능할 것입니다.


1.8. Loading Large Hierarchies


유니티 GameObject 의 계층을 직렬화할 때( 예를 들어 프리팹을 직렬화할 때 ), 전체 계층이 완전히 직렬화된다는 것을 기억하는 것이 중요합니다. 즉, 계층 내부의 모든 GameObject 와 Component 들이 개별적으로 직렬화된 데이터 내에 표현된다는 것입니다. 이는 GameObject 의 계층을 로드하고 인스턴스화하는데 필요한 시간에 흥미로운 영향을 미칩니다.


GameObject 계층을 생성할 때, CPU 시간이 몇 가지 방식으로 소비됩니다:


    1. 소스 데이터를 읽는 시간( 저장소로부터, 다른 GameObject 로부터 등 ).
    2. 새로운 Transform 사이에서 부모 자식 관계를 설정하는 시간.
    3. GameObject 와 Component 를 인스턴스화하는 시간.
    4. GameObject 와 Component 를 깨우는( awaken ) 시간.


나머지 세 비용은 일반적으로 계층이 현존하는 계층으로부터 복사되느냐 저장소( 예를 들어 애셋번들 )에서 로드되느냐와 관계없이 일정합니다. 그러나 소스 데이터를 읽는 비용은 계층에 직렬화된 Component 및 GameObject 의 개수에 따라 선형적으로 증가하며, 이는 데이터 소스의 속도와 곱해집니다.


현재 모든 플랫폼에서, 저장소 디바이스에서 로드하는 것보다는 메모리 어딘가에서 데이터를 읽어 들이는 것이 훨씬 빠릅니다. 더우기, 이용가능한 저장소 매체의 성능 특성은 각 플랫폼에서 매우 다양합니다 -- 데스크탑 PC 는 모바일 디바이스보다 훨씬 빠르게 디스크에서 로드합니다.


그러므로 느린 저장소를 가진 플랫폼에서 프리팹을 로드할 때, 저장소로부터 프리팹의 직렬화된 데이터를 읽는 비용은 프리팹을 인스턴스화하는 비용을 급격하게 넘어 갈 수 있습니다. 즉, 로딩 연산의 비용은 스토리지 I/O 시간에 의해 결정됩니다.


이전에 언급했듯이, monolithic prefab 을 직렬화할 때, 각 GameObject 와 Component 의 데이터는 개별적으로 직렬화됩니다 - 심지어 데이터가 중복되어 있더라도 그렇습니다. 30 개의 동일한 요소를 가진 UI 스크린은 동일한 요소를 30 번 직렬화할 것입니다. 이는 많은 바이너리 데이터 덩어리를 생성합니다. At load time, the data for all of the GameObjects and Components on each one of those thirty duplicate elements must be read from disk before being transferred to the newly-instantiated Object. 이는 파일 읽기 시간이며, 큰 프리팹을 인스턴싱하는 비용의 대부분을 차지합니다.


유니티가 내포된 프리팹( nested prefabs )을 지원하기 전까지는, 극단적으로 큰 GameObject 계층을 인스턴스화하는 프로젝트들은유니티의 직렬화 및 프리팹 시스템에 완전히 의존하기보다는,  재사용되는 요소들을 개별 프리팹으로 쪼개고 런타임에 그것을 인스턴스화함으로써 그들의 큰 프리팹의 로딩 비용을 많이 감소시킬 수 있었습니다.


더우기, 프리팹이나 GameObject 계층이 일단 생성되면, 새로운 복사본을 저장소에서 로드하는 것보다 현존하는 계층을 복사하는 것이 더 빠릅니다.


유니티 5.4 노트: 유니티 5.4 는 메모리에서 transform 에 대한 표현을 수정했습니다. 각 root transform 의 전체 자식 계층은 작고 연속적인 메모리 영역에 저장됩니다. 다른 계층으로 reparent 되는 새로운 GameObject 를 인스턴스화할 때는, parent 인자를 허용하는 GameObject.Instantiate 오우버로드( overloads ) 메서드를 사용하는 것을 골려하십시오.


이 오우버로드 메서드를 사용하면 새로운 GameObject 를 위한 root transform 계층을 할당하는 것을 피할 수 있습니다. 테스트를 해 봤을 때, 이것은 인스턴스화 연산을 위해 요구되는 시간을 5 ~ 10 % 정도 빠르게 만들어 줬습니다.


-- 각주 생략

+ Recent posts