상세 컨텐츠

본문 제목

[Unity] 유니티 리소스 읽기, 경로 관련

게임엔진관련/유니티 엔진

by AlrepondTech 2019. 3. 22. 12:28

본문

반응형

 

 

 

=================================

=================================

=================================

 

 

 

 

 

 

 

 

출처: https://docs.unity3d.com/kr/2018.1/Manual/LoadingResourcesatRuntime.html

 

런타임 시 리소스 로드

 

어떤 상황에서는 씬의 일부로 로드하지 않고 프로젝트에서 사용할 수 있게 하는 것이 유용합니다. 예를 들어, 게임의 모든 씬에 등장할 수 있지만 드물게 사용되는 캐릭터 또는 기타 오브젝트가 있을 수 있습니다(가령 이것은 “비밀” 기능, 오류 메시지 또는 하이스코어 알림일 수 있습니다). 또한, 초기 다운로드 시간을 단축하거나 게임 콘텐츠를 교체하기 위해 별도의 파일 또는 URL에서 에셋을 로드할 수 있습니다.

Unity는 프로젝트에서 리소스 폴더 를 지원하여 콘텐츠가 메인 게임 파일에 공급될 수 있게 하지만, 요청이 있을 때까지 로드하지 않습니다. 또한, 에셋 번들 을 만들 수도 있습니다. 에셋 번들은 메인 게임 파일에서 완전히 분리된 파일로 게임이 요청했을 때 파일 또는 URL에서 엑세스할 수 있는 에셋을 포함합니다.

에셋 번들

에셋 번들(Asset Bundles)은 에셋의 외부 컬렉션입니다. 여러 개의 에셋 번들을 가질 수 있기 때문에 다른 에셋의 외부 컬렉션도 다수 가질 수 있습니다. 이러한 파일은 빌드된 Unity 플레이어의 외부에 존재하기 때문에 일반적으로 웹 서버에 있으며, 최종 사용자가 동적으로 액세스할 수 있습니다.

에셋 번들을 빌드하려면, 에디터 스크립트에서 BuildPipeline.BuildAssetBundles()를 호출해야 합니다. 인수에서 빌드된 파일에 포함될 오브젝트 배열을 다른 옵션과 함께 지정합니다. 이렇게 하면 추후 런타임에서 AssetBundle.LoadAsset()을 사용하여 동적으로 로드할 수 있는 파일을 빌드할 수 있습니다.

리소스 폴더

리소스 폴더(Resource Folders)는 빌드된 Unity 플레이어의 에셋 컬렉션이지만, 인스펙터에서 어떤 게임 오브젝트와 반드시 연결되어야 하는 것은 아닙니다.

리소스 폴더에 무언가를 넣으려면 프로젝트 뷰(Project View) 에 새 폴더를 만들고 폴더 이름을 “Resources”로 지정해야 합니다. 프로젝트에 여러 리소스 폴더를 다른 형태로 배치할 수 있습니다. 폴더 중 하나에서 에셋을 로드하고 싶다면 Resources.Load()를 호출해야 합니다.

참고

Resources 폴더의 모든 에셋 및 종속성은 resources.assets_이라는 파일에 저장됩니다. 에셋이 이미 다른 레벨에서 사용되는 경우 해당 레벨의 .sharedAssets_에 저장됩니다. Edit -> PlayerSettings First Streamed Level 설정에 따라 _resources.assets_가 모아져 빌드에 포함될 레벨을 결정합니다.

“First streamed Level” 보다 이전 레벨이 Resource 폴더의 ​​에셋을 포함하는 경우, 에셋은 해당 레벨의 에셋으로 저장됩니다. 이후에 포함될 경우 해당 레벨은 “resources.assets”의 에셋을 레퍼런스합니다.

Resources 폴더 에 있는 에셋만이 Resources.Load()를 통해 액세스될 수 있습니다. 그러나 종속성을 지니고 있으면 더 많은 에셋이 “resources.assets” 파일에 포함될 수 있습니다(예를 들어, Resources 폴더의 ​​머티리얼은 Resources 폴더 외부의 텍스처를 레퍼런스할 수 있습니다).

리소스 언로드

AssetBundle.Unload()를 호출해서 에셋 번들의 리소스를 언로드할 수 있습니다. unloadAllLoadedObjects 파라미터에 true 을 전달하면 에셋 번들에서 내부적으로 보유한 오브젝트와 AssetBundle.LoadAsset()을 사용하여 에셋 번들에서 로드된 오브젝트가 모두 삭제되고 번들에 의해 사용된 메모리가 릴리스됩니다.

에셋 번들을 로드한 후 원하는 오브젝트를 인스턴스화하고 오브젝트를 유지하면서 번들이 사용하던 메모리를 해제하고 싶은 경우가 있습니다. 다른 에셋 번들을 위한 인스턴스 로드 등, 다른 작업을 위해 메모리를 비울 수 있다는 게 장점입니다. 이 경우 파라미터에 false 를 전달해야 합니다. 번들이 삭제된 후에는 해당 번들에서 오브젝트를 로드할 수 없게 됩니다.

다른 레벨을 로드하기 전에 Resources.Load()를 사용하여 로드한 씬의 오브젝트를 삭제하려면 Object.Destroy()를 호출해야 합니다. 에셋을 해제하려면 Resources.UnloadUnusedAssets()를 사용해야 합니다.

 

 

=================================

=================================

=================================

 

 

 

출처: https://dlgnlfus.tistory.com/81

 

Resources.Load기능

http://docs.unity3d.com/ScriptReference/Resources.Load.html

 

 

GameObject a = Instantiate(Resources.Load("A", typeof(GameObject)))as GameObject;

GameObject a = Instantiate(Resources.Load<GameObject>("A");

 

리소스 파일에 있는 리소스들은 메모리에 올려놓은 상태라 많이 사용하면 좋치않음.

애셋번들을 사용해야함.



출처: https://dlgnlfus.tistory.com/81 [게임 개발 일기장]

 

 

=================================

=================================

=================================

 

 

 

출처: http://blog.kpaper.com/2017/02/unity3d.html

 

 

Unity3D 외부 리소스 가져오기

 
유니티로 빌드하면 에셋이 묶여서 엑세스가 불가하게 된다.
대량의 에셋을 추가하려면 에셋 번들을 이용하면 되는데,
이런 경우 말고 직접 리소스를 추가하고 싶은 경우가 있다.

최근 프로젝트에서 필요해서 하는김에 간단히 정리해봤다.
처음 하는 사람들에게 도움이 되길 -_-*

# Resource.Load 사용하기
 private void ResourceLoadSample(){    Texture2D texture = new Texture2D(0, 0);    string PATH = "Texture/image.jpg";    // 이미지 파일 패스를 써준다.    //중요한 것은 유니티 프로젝트 Assets/Resource/ 폴더 이후의 경로를 써주는 것이다. 이 폴더는 맘대로 바꿀 수가 없다.   texture = Resources.Load(PATH,typeof(Texture2D)) as Texture2D;  // 이미지 로드   targetObject.mainTexture = texture;  // 타겟 오브젝트에 메인 텍스쳐를 넣어준다.  }  
# System.File.IO로 직접 가져오기
Resource 폴더가 아니라 다른 폴더 특히 StreamingAssets에서 가져오려면

Resource.Load 함수를 쓰지 말고 직접 System.File.IO 로 가져와야 한다.
byte[] 로 가져온 다음에 Texture2D.LoadImage()를 사용하여 텍스쳐2D로 읽어오면 된다.

  private void SystemIOFileLoad(){  byte[] byteTexture = System.IO.File.ReadAllBytes(Path);      if (byteTexture.Length > 0)      {          texture = new Texture2D(0, 0);          texture.LoadImage(byteTexture);      }  } 

# 원하는 경로/파일에 엑세스 하기 
 # StreamingAssets 폴더의 하위 폴더/파일에 접근해본다. Path = System.IO.Path.Combine(Application.streamingAssetsPath, path); // path = 하위폴더 "하위폴더1/하위폴더2/file.png";  

 

 

 

=================================

=================================

=================================

 

 

 

반응형

 

 

728x90

 

 

출처: https://www.bsidesoft.com/?p=215

 

 

유니티IDE의 Assets 안 에는 수 많은 객체를 정의해 둘 수 있습니다. 이미지나 사운드를 비롯하여 스크립트와 프리펩까지 모두 들어갑니다.

이러한 에셋은 컴파일타임에 특정 게임오브젝트와 바인딩되지만 런타임에 스크립트를 통해 사용하려면 리소스를 로딩하는 과정을 거쳐야 합니다.


 

 

특별한 이름의 폴더top

유니티의 Assets 폴더 밑에는 서브폴더를 자유롭게 만들 수 있지만 미리 지정된 이름으로 폴더를 만들면 특별한 작동을 합니다.

http://wiki.unity3d.com/index.php/Special_Folder_Names_in_your_Assets_Folder

위 목록에서 다양한 특수 폴더명을 볼 수 있습니다. 대소문자는 구별하지 않습니다. 이 중 이번 포스팅에서 눈여겨 볼 폴더명은 Resources 입니다.

Assets/resources

에셋폴더 밑에 일단 resoureces 라는 이름으로 폴더를 만들면 이 폴더를 기준으로 여러 에셋을 런타임에 로딩하여 사용할 수 있게 됩니다.

예를들어 프리펩을 만들어 로딩하고 싶다면 다음과 같은 구조로 서브폴더를 만들어봅시다.

Screenshot_1

resources/block 폴더 안에 들어있는 R1~R5까지의 프리펩을 런타임에 불러오려면 어찌 해야할까요?

 

 

Resources.Load와 Resources.LoadAlltop

각각의 자원을 부르는 방법은 Resources.Load를 사용하는 것입니다.

GameObject temp1 = Resources.Load( "block/R1" as GameObject;
GameObject temp2 = Resources.Load( "block/R2" as GameObject;
GameObject temp3 = Resources.Load( "block/R3" as GameObject;
GameObject temp4 = Resources.Load( "block/R4" as GameObject;
GameObject temp5 = Resources.Load( "block/R5" as GameObject;

귀찮기 때문에 그저 서브폴더만 넘겨주면 전부 처리해주는 LoadAll을 제공합니다.

object[] temp = Resources.LoadAll( "block" );

LoadAll의 경우는 as GameObject[] 로 형 변환할 수 없습니다. 하지만 개별 요소에 대해서는 형변환할 수 있으므로 큰 문제는 없습니다.

object[] temp = Resources.LoadAll( "block" );
 
forint i = 0 ; i < temp.Length ; i++ ){
  GameObject go = temp[i] as GameObject;
  //go...
}

 

 

제네릭컬렉션으로 캐쉬하기top

일단 로딩한 후에는 해당 객체를 반복해서 사용하는 경우가 많습니다. 예를 들어 R1(녹색큐브)를 10개 복제한다고 하면 GameObject.Instantiate를 사용하기 위해 개별 객체를 인식해두지 않으면 안됩니다.

로딩된 배열을 해시테이블(HashTable)로 잡아두면 편리하게 사용할 수 있지만 제네릭 타입으로 정리하면 형변환도 필요없게 되므로 더욱 안정적이고 간단히 사용할 수 있을 것 입니다.

일단 제네릭컬렉션을 사용하려면 네임스페이스를 불러와야겠죠.

using System.Collections.Generic;

다음은 RSC클래스에 간단히 정적 필드로 캐쉬 공간을 만들어 둡시다.

class RSC {
  static private Dictionary<string,GameObject> _cache =
      new Dictionary<string,GameObject>();

 

 

로딩하기와 캐쉬에서 꺼내기top

그럼 이제 서브폴더를 로딩하는 함수를 일반화하여 캐쉬에 곧장 넣어버리죠.

static public void Load( string subfolder ){
  object[] t0 = Resources.LoadAll( subfolder );
  forint i = 0 ; i < t0.Length ; i++ ){
    GameObject t1 = (GameObject)(t0[i]);
    _cache[t1.name] = t1;
  }
 }
 
//서브폴더 로딩하기
RSC.Load( "block" );

그럼 그 뒤로는 캐쉬에서 직접 꺼내가던가 아니면 인스턴스를 반환하는 함수를 생각해 볼 수 있습니다. 우선 간단히 가져가는 함수는 다음과 같습니다.

static public GameObject Get( string key ){
  return _cache[key];
}
 
// R1을 가져오자
GameObject temp = RSC.Get( "R1" );

인스턴스를 직접 반환받고 싶다면 다음과 같은 함수로 편리하게 사용합시다.

static public GameObject Instance( string key, string name,
    float x, float y, float z ){
  GameObject t0 = (GameObject)(GameObject.Instantiate(
      _cache[key], new Vector3( x, y, z ), Quaternion.identity
    ));
  t0.name = name;
  return t0;
}
 
//R1으로부터 R1Clone을 가져오자.
GameObject temp = RSC.Instance( "R1""R1Clone", 0, 0, 0 );

 

 

캐쉬를 메모리에서 삭제top

메모리 절약을 위해 다양한 리소스를 로딩하려면 필요없는 리소스는 다시 삭제해줘야합니다. params인자를 통해 간단히 삭제하는 함수를 구현합시다.

static public void Remove( params string[] arg ){
  forint i = 0 ; i < arg.Length ; i++ ){
    string key = arg[i];
    _cache.Remove( key );
  }
}
 
//R1~R3까지 삭제
 
RSC.Remove( "R1""R2""R3" );

이를 통해 간단히 메모리에서 몇 개라도 한꺼번에 삭제할 수 있게 되었습니다[1. 참고로 GameObject의 경우 Resources.UnloadAsset 으로 삭제되지 않고 더 이상 사용되지 않으면 GC가 될 뿐입니다.]

 

 

간단한 샘플top

이상의 내용을 바탕으로 간단히 큐브를 화면에 채워봅시다.

Load ("block");
forint i = 0 ; i < 10 ; i++ ){
  forint j = 0 ; j < 10 ; j++ ){
    Instance( "R" + Random.Range(1,6), i+":"+j, i-5, j-5, 0 );
  }
}
Remove( "R1""R2" );

다음과 같은 화면이 된다면 정상입니다.

Screenshot_2

 

 

결론top

이번 포스팅에서는 간단히 런타임 에셋로딩을 알아봤습니다. 실제 소스는 거의 GameObject 로딩 중심으로 가볍게 설명했으나 이를 바탕으로 다양한 에셋로더를 구현하는 것은 또 다른 기회에 해보겠습니다(과연..)

종합 소스는 아래에 있습니다만, resources/block 폴더를 만들고 R1~R5까지의 색깔별 큐브를 프리펩으로 만들지 않으면 실행되지 않습니다.

http://blog.bsidesoft.com/unity/bside002.txt

 

 

=================================

=================================

=================================

 

 

 

출처: https://flystone.tistory.com/143

 

"Standard Assets"

"Pro Standard Assets"

다른스크립트들 보다 먼저 컴파일 되는 폴더 이다.

따라서 서로 다른 스크립트 간의 연동하는 일도 가능하다, C# 에서 JS 를 호출한다던지 하는 방법.

기본 Standard Assets 와 Pro 와의 차이점은 간단하다, 

Pro License 에서만 사용 가능한 기능들을 사용할때에는 Pro 디렉토리를 사용해야 한다.

EX ) RenderTexture 등등

 

( 최상위 폴더에만 위치해야 한다. )

 

 

"Editor"

유니티 에디터에서만 사용가능한 코드를 넣는 곳이다. ( UnityEditor namespace )
런타임 빌드시에는 해당 폴더에 있는 내용은 전혀 들어가지 않게된다.
마찬가지로, 다른 런타임 코드에서 이 폴더에 있는 클래스나, 자원은 접근조차 되지 않는다.
 
추가사항) 일반적으로 이 폴더는 전체 프로젝트의 어느 하위폴더에서도 사용 가능하다.
다만 이미 지정되어있는 스페셜 폴더 하위에 사용될 경우에는, 스페셜 폴더 바로 하위에서만 사용 가능하다.
 
ex) Scripts/View/Editor  -> ok
ex) Standard Assets/Editor  -> ok
ex) Standard Assets/My/Editor  ->  bad
ex) Plugins/Editor  -> ok
 
 

"Plugins"

외부 연동을 위한 라이브러리, 혹은 IOS, Android 빌드에 필요한 해당 언어 소스들을 넣는 폴더이다.
빌드시에 자동으로 해당 플렛폼으로 복사되어진다.
플렛폼 별로 
Plugins/iOS   ( .a, .m, .mm, .c, or .cpp )
Plugins/Android   ( Java .jar .so file (when having Android NDK-based plugins) )
등으로 서브 폴더가 나뉘어진다.
 
추가사항) 이 폴더 역시 Standard Assets 폴더와 마찬가지로 다른 소스들보다 먼저 빌드되어진다.
 
( 최상위 폴더에만 위치해야 한다. )

 

 

"Resources"

해당폴더에 있는 리소스 파일들은 빌드시에 언제나 포함된다.

사용하지 않는 리소스들 이더라도 모두 포함되어 용량을 차지할 수 있으니, 사용하지 않는 리소스는 정리하는것이 좋다.

 

이 폴더는 최상위 폴더가 아닌, 프로젝트 어디에서나 생성하여 사용 할 수 있다.

그러나 빌드시에 결국 하나의 asset 으로 합쳐지기 때문에, 파일 이름, 경로 등을 잘 설정해야 한다.

다른 폴더의 리소스 폴더에 들어있는 파일이라도, 이름이 같을 경우 이를 구분할 방법이 없다.

 

 

 

"Editor Default Resources"

리소스 폴더와 마찬가지의 일을 한다, 한가지 다른점은 이름에서와 같이 에디터 전용이다.
빌드시에는 포함하지 않고 에디터용 플러그인을 위한 리소스를 관리할때 사용한다.
EditorGUIUtility.Load() 함수를 이용하여 불러올 수 있다.

 

 

 

 

"Gizmos"

에디터 전용 폴더로, Gizmos.DrawIcon() 에 사용 될 리소스를 담는 폴더이다.
 
 
 

"StreamingAssets"

이 폴더에 넣는 파일들은 변형되지 않고 그대로 빌드에 포함시킨다
( 다만 web, mobile 빌드 시에는 변형된다. )
빌드 후 Application.streamingAssetsPath 를 통해 접근 할 수 있다.
 
추가사항) 
일반적으로 System.IO.File.ReadAllText 와 같이 직접 주소를 불러도 되지만
안드로이드의 경우 하나의 파일로 압축되어져 보관된다.
따라서 WWW 의 도움을 받아 접근 해야 한다.
WWW 가 알아서 압축해제 후 해당 파일을 가져와주는 일을 대신 수행한다.
직접 해당 부분을 구현해서 사용해도 된다.
 
 1  2  3  4  5  6  7  8  9 10 11 12 13 14 15
using UnityEngine; using System.Collections;  public class ExampleClass : MonoBehaviour {     public string filePath = System.IO.Path.Combine(Application.streamingAssetsPath, "MyFile");     public string result = "";     IEnumerator Example() {         if (filePath.Contains("://")) {             WWW www = new WWW(filePath);             yield return www;             result = www.text;         } else             result = System.IO.File.ReadAllText(filePath);     } } 

 



출처: https://flystone.tistory.com/143 [MomO]

 

 

=================================

=================================

=================================

 

 

반응형


관련글 더보기

댓글 영역