블로그 이미지
자신의 단점을 메꾸는 것을 단(鍛)이라 하고 자신의 강점을 갈고 닦는 것을 련(鍊)이라 하여, 두가지를 합친 것을 단련이라고 부른다. 붕대마음

카테고리

전체목록 (665)
참고사이트 (8)
Goal (4)
Travel (10)
My Life (104)
Game (35)
Game Review (7)
Game Plan (0)
Books (5)
English (1)
Optimizing (12)
Study (217)
유용한 것들_etc (44)
유용한 것들_func (20)
Unity (48)
Unreal (87)
작업장 (54)
RenderMonkey (6)
정리요망 (1)
따라잡기 시리즈 (0)
링크용 (0)
Total341,593
Today114
Yesterday125

unity의 awake

Unity/Unity Study / 2017.09.24 13:15

script 함수 실행 순서는 awake, onenable, start다. 

이건 알고있던 건데 작업을 하다가 자꾸 awake에 에러가 나서 에러를 찾다보니

하이라키에서 활성화 되어 있는오브젝트에 비활성화로 달려있는 컴포넌트였다.


여기에 붙어있는 컴포넌트의 내용은 아래와 같다.

public class TestAwake : MonoBehaviour 

{

    void Awake()    {        Debug.Log("Awake");    }

    void OnEnable() { Debug.Log("OnEnable"); }

    void Start () {    Debug.Log("Start"); }

    void Update () {  Debug.Log("Update"); }

}


똑같은 상태에서 TestAwake 컴포넌트의 active만 꺼 두면 어떻게 될까?

나의 예상과는 다르게 Awake는 무조건 호출이 된다.


Awake는 컴포넌트의 active 상태와 상관없이 호출이 되고 Start함수는 active 된 상태에서만 호출이 된다.

Awake 함수는 컴포넌트의 스크립트의 활성화 여부에 상관없이 컴포넌트의 오브젝트가 초기화 될 때 호출되기 때문이다.


그래서 위와 같이 컴포넌트의 오브젝트가 비활성화 되어 있으면 초기화가 안되어 컴포넌트 자체의 awake도 호출되지 않는다.





Reference Link

- MonoBehaviour.Awake()

-



'Unity > Unity Study' 카테고리의 다른 글

unity의 awake  (0) 2017.09.24
ExecuteInEditMode  (0) 2017.09.13
Inspector에서 AnimationCurve 버그  (0) 2017.07.21
unity에서 shader를 짤때..  (0) 2017.07.10
ARB_precision_hint_fastest  (0) 2017.07.10
The Magic Of Material Property Blocks  (0) 2017.06.23
Posted by 붕대마음
TAG AWAKE, Unity

댓글을 달아 주세요

작업할때 디자이너분들이 작업하기 편하게 "ExecuteInEditMode"를 자주 쓰는 편인데

어느날 에디터 실행후 종료시에 이상한 에러가 뜬다.

봤더니 에디터 실행 후 종료시에 ExecuteInEditMode 코드가 있는 스크립트의 start 함수가 호출된다.

누가 호출하는걸까..콜백도 없고...

그래서 디버그를 다 찍어서 editor을 실행하니 ExecuteInEditMode 코드가 있는 스크립트에서는


1. 에디터 실행 - script의 OnDestroy 실행, Start 실행

2. 에디터 종료 - script의 OnDestroy 실행, Start 실행


위와 같은 루틴을 탄다.



[ExecuteInEditMode]

public class ExecuteTest : MonoBehaviour {


// Use this for initialization

void Start () {

Debug.Log("Start");

}

// Update is called once per frame

void Update () {

Debug.Log("Update");

}


void OnDestroy()

{

Debug.Log("OnDestroy");

}

}


위 코드를 하이라키에 오브젝트 하나 만들어 add 시킨 후 테스트 해 보면 

아래와 같이 로그가 찍힌다.


에디터 실행..............................................에디터 종료.......................................

OnDestroy -> Start -> Update -> OnDestroy -> Start -> Update



에디터에서만 이렇게 동작하겠지만...

'Unity > Unity Study' 카테고리의 다른 글

unity의 awake  (0) 2017.09.24
ExecuteInEditMode  (0) 2017.09.13
Inspector에서 AnimationCurve 버그  (0) 2017.07.21
unity에서 shader를 짤때..  (0) 2017.07.10
ARB_precision_hint_fastest  (0) 2017.07.10
The Magic Of Material Property Blocks  (0) 2017.06.23
Posted by 붕대마음

댓글을 달아 주세요

RenderQueue

Unity/Unity Study / 2017.06.21 12:29

유니티에서는 Queue를 설정해서 오브젝트를 그릴 순서를 조절할 수 있다.

셰이더는 오브젝트가 속하는 render queue를 결정하며, 이 방법에 의해 어떠한

반투명 셰이더들도 불투명 오브젝트들 이후에 그려지게 보장한다.


유니티 도큐에 보면 아래와 같이 되어있다.


Background : 가장 먼저 그려짐

Geometry : 불투명(Opaque) 물체

AlphaTest : 알파테스트 물체

GeometryLast : 불투명(Opaque)에서 가장 나중에 그려짐.

Transparent : Geometry와 AlphaTest 이후에 그려짐. 순서는 뒤에서부터 앞으로.

Overlay : 중첩되는 효과.


큐 사이에서 좀 더 특별하게 사용할 수도 있다. 내부적으로 각 큐들은 정수 인덱스로 표시된다.

Background는 1000, Geometry는 2000, AlphaTest는 2450, Transparent는 3000, 그리고 Overlay는 4000이다.

만약 셰이더에서 쓸려면 아래와 같이 하면 된다.

Tags { "Queue" = "Geometry+1"}

이렇게 하면 이 오브젝트는 모든 불투명(opaque) 오브젝트들이 그려지고 나서, 그리고 반투명 오브젝트들 이전에

그려지며, render queue 인덱스는 2001이 될 것이다.(geometry +1)

이 기능은 특정 오브젝트가 항상 다른 오브젝트들 사이에 그려져야 할 때 유용하다.

예를 들자면, 대부분의 경우 반투명 물은 불투명 오브젝트보다 나중에, 반투명 물체이전에 그려져야 한다.

2500번까지는(Geometry+500) "반투명(Opaque)"로 간주되며 최상의 퍼포먼스를 위해 객체의 그리기 순서를 최적화 한다.

더 높은 큐 값은 "불투명(Transparent) 오브젝트"로 간주되며 거리에 따라 정렬된다.

스카이박스는 모든 불투명(Opaque)와 모든 반투명(Transparent) 사이에 그려진다.


대충 내용은 위와 같고 이를 실제로 사용하는 방법을 좀 보자.

우선 머티리얼을 하나 만들면 머티리얼에 아래와 같은 값이 있다.

예전부터 있던건지는 잘 모르겠지만 큐브와 스피어를 몇개 만들어서 테스트를 해 봤다.

Shader는 그냥 유니티가 제공하는 Unlit Color을 사용했다.


다 같은 셰이더를 사용하고 있다.

처음 만들면 Render Queue는 "From Shader"로 되어있고 여기에 내가 수정하면(예를들어 2050) "Custom"으로 자동으로

바뀌며, 다시 원래값인 2000으로 바꾸면 "Geometry"가 된다.

값을 2050로 바꿔서 "Custom" 으로 바꾼 상태에서 "Geometry"나  "From Shader"로 바꾸면 다시 값이 2000이 된다.


못찾은 건지 인스펙터창에서 이 옵션에 대한 내용은 없어서... 적당히 정리해 보자면

From Shader : shader 파일에 설정한 값을 우선으로 한다. 

  예를들어 "RenderType"="Opaque" "Queue" = "Geometry+100"의 경우 인스펙터에서 From Shader라면 

  자동으로 2100이 된다.

Geometry : Shader에 설정된 값을 무시하고 그냥 Geometry 값인 2000 설정한다.

AlphaTest : Shader에 설정된 값을 무시하고 그냥 AlphaTest 값인 2450으로 설정한다.

Transparent : Shader에 설정된 값을 무시하고 그냥 Transparent값인 3000으로 설정한다. 

Custom : 0~5000까지의 값을 지원한다.


테스트를 해 보자.

위와같이 네가지를 설정해 주었으며 From Shader는 위에서 설정한 대로 "Geometry+100" 이다.

렌더링을 하면 순서는 아래와 같다.

위에 두개는 불투명으로 해서 순서대로 그려지고 뒤에 두개는 반투명으로 해서 두개가 그려진다.


결국은 셰이더에 작업을 잘 해도 디자이너분이 저 값을 인스펙터에서 건드는 순간 셰이더에서 설정한 값 보다

인스펙터값을 우선하게 된다.


Reference Link

- unity, RenderQueue

- unity, material.renderQueue

- unity, ShaderLab: SubShader Tag

-

'Unity > Unity Study' 카테고리의 다른 글

ARB_precision_hint_fastest  (0) 2017.07.10
The Magic Of Material Property Blocks  (0) 2017.06.23
RenderQueue  (0) 2017.06.21
There are inconsistent line endings  (2) 2017.06.20
assetbundle building, change file  (0) 2017.06.03
메모리 프로파일러  (0) 2017.05.19
Posted by 붕대마음

댓글을 달아 주세요

There are inconsistent line endings in the 'Assets/Scripts/SomeThing.cs' script. Some are Mac OS X (UNIX) and some are Windows.

This might lead to incorrect line numbers in stacktraces and compiler errors. Many text editors can fix this using Convert Line Endings menu commands.


유니티에서 가끔 위와같은 경고가 찍힌다.
대략적인 내용은 아래와 같다.

스크립트의 줄끝이 명확하지 않습니다. 
어떤건 Mac을 따르고 어떤건 Window를 따릅니다.
이렇게 되면 나중에 컴파일러 오류시 스택 추적할 때 잘못된 행번호가 찍힐 수 있다.
Convert Line Ending 메뉴명령을 사용해서 문제를 해결해라.

대략 디버깅때 문제될 수 있으니까 정리하는걸 권고한다는 내용인듯하다.

그런데 사실 여러명이 작업하다 보니 이런게 은근 많이 발생한다.

그래서 기능을 만들어 볼까 하다가 구글링 해 보니 역시 먼저 작업해서 올려주신 분이 있다.

그대는 멋쟁이!!


이곳을 참조하자

코드를 대략적으로 살펴보면 폴더경로에 해당 확장자 파일을 찾아서 라인의 끝을 바꿔준다.




'Unity > Unity Study' 카테고리의 다른 글

The Magic Of Material Property Blocks  (0) 2017.06.23
RenderQueue  (0) 2017.06.21
There are inconsistent line endings  (2) 2017.06.20
assetbundle building, change file  (0) 2017.06.03
메모리 프로파일러  (0) 2017.05.19
Asset Bundles vs. Resources : A Memory Showdown  (0) 2017.04.14
Posted by 붕대마음

댓글을 달아 주세요

  1. 2018.01.26 10:38 dre0112  댓글주소  수정/삭제  댓글쓰기

    감사합니다. 덕분에 도움이 되었습니다.

내용은 이러함.

1. 에셋번들 빌드

2. 빌드결과 파일들 복사.

3. 프로젝트 아무것도 안 건드리고 다시 빌드

4. 두번째 빌드결과 파일들과 첫번째 빌드 파일들 비교

이상하게 몇몇 파일들이 자꾸 결과물이 다르다.

실제로 파일용량도 다르다.

대략 내용을 보면 내용은 같은데 파일의 내용 부분에서 저장 데이터 위치가 

조금씩 바뀌면서 용량도 틀려지고 하는듯 하다.

근데 왜 저장 위치가 달라지는 거지?


현재 사용 버전 : 5.5.1p3

결론 : 빌드할 때마다 특정 scene들의 파일 용량이 다르며, 실제이 조금씩 달라진다.

         그럼으로 인해 파일의 CRC 또한 달라진다.


첫번째 해결 시도

혹시 editor 관련 코드들이 random 을 만들어 내거나 하지 않을까?

editor 코드들을 제거. 끝없이 제거..딱히 정확한 연관성을 찾지 못함.


두번째 해결 시도

scene이 제대로 저장되지 않은게 아닐까?

프리팹들을 여기저기에 쓰는데 scene에서도 정보를 자체적으로 저장하니까,

그리고 이미 유니티 버전업도 몇번 진행했으니까 마이그레이션에서 문제가 있을수도 있고..

그래서 모든 신을 오픈하고 다시 저장하는 스크립트를 만들어서 돌림.

그랬더니!!!

파일 해쉬는 여전히 바뀌지만 파일 용량은 바뀌지 않음!!!

이 부분에서 유추할 수 있는 내용은 뭘까?

어느 부분이 해결되서 파일 용량이 안바뀌게 된걸까?

버전에 따른 추가정보 저장이 있는걸까?

그런데 왜 특정 scene만 저장해서 하면 계속 용량이 바뀌는 걸까?

결국 뭔가의 연관성이라는 게 있는걸까?


세번째 해결 시도

복사 붙여넣기 프리팹이 문제일까?

실제로 하나의 프리팹을 만든 후 그걸 여러군데에서 떙겨쓰고 apply하고 수정하고 하는 

일들을 많이 한다.

이는 프리팹을 쓰는 정확한 가이드 라인과 잘못 사용하는 프리팹을 찾을 수 있는 기능을

처음부터 제시하지 못한 나의 잘못. 그래서 이 부분에 대해 조사.

우선 프리팹의 문제인지 검증하기 위해 의심가는 프리팹을 링크를 끊어서 테스트.

여러번 빌드해도 해시과 변경되지 않는다!!

결국은 프리팹이 문제인 건데 여기서 다시 프리팹에 붙어 있는 특정 script가 문제 인가 하여

script를 지우면서 테스트 해 봐도 그건 아닌 듯 하다.

프리팹 링크에 대한 문제인듯 하다.

scene에 올려져 있는 세개의 프리팹의 링크를 끊었다.

a.prefab : 해당 scene에서만 사용하는 프리팹으로 editor 관련 컴포넌트가 붙어있다.

b.prefab : 몇군데의 scene에서 사용하는 프리팹으로 프리팹 안에 다른프리팹들이 여러개 들어 있다.

c.prefab : 해당 scene에서만 사용하는 프리팹으로 컴포넌트에 다른 프리팹에 대한 링크를 들고 있다.

위 프리팹들을 하나씩 다시 재 구축하며 테스트를 진행하였다.


a.prefab를 위한 테스트.

다시 프리팹으로 만들어서 테스트 : 두번의 빌드 후 scene 비교 결과 결과값이 다르다.

새로 만든 프리팹이며 하나의 신에서만 사용하는데도 신 빌드 결과값이 다름.

이 프리팹에 붙어있는 두개의 컴포넌트는 아래와 같다.

- script1 : editor script

- script2 : mono script

테스트를 진행해 봤다.

script1을 제거하고 테스트, script2를 제거하고 테스트 등 몇가지 테스트를 해 봤지만

script가 하나라도 붙어 있으면 계속 빌드를 하면 결과값이 바뀐다.

왜 script가 하나라도 붙어있으면 결과값이 바뀌는 걸까? 

다른 프리팹은 안바뀌는데... 

결과값에 영향을 안주는 프리팹과 비교해 본 결과 차이점은 결과값에 차이를 안 주는 프리팹은 

유니티 자체 컴포넌트(ex : animation, mesh 등)을 사용하고 있었다.

그래서 다시 a.prefab에 유니티 자체 컴포넌트를 붙여서 테스트 해 보니 결과값이 바뀌지 않음.

결론은....커스텀 script를 컴포넌트로 가지는 프리팹이 scene의 하이라키에 있으면 scene을 빌드할 때 문제가 생긴다??

혹시 custom하게 추가 한 스크립트 실행순서 때문일까? 모두 지우고 테스트 해 보니 이건 원인이 아님.

(지웠던 순서를 되돌리기 위해선 해당 스크립트의 메타를 고쳐야 한다. 순서는 메타에 저장된다)


여기까지의 정리를 보자면

1. scene의 하이라키에 프리팹이 올려져 있고 그 프리팹이 unity 지원이 아닌 자체 script을 컴포넌트로 가지면 

   번들을 빌드할 때 마다 파일이 조금씩 달라진다.

2. 새로 프로젝트를 만들어서 똑같이 테스트 해 본 결과 달라지지 않는다. 즉 현재 작업중인 프로젝트에 무었인가가 

   빌드시 프리팹을 건드는게 있다고 추측할 수 있다.

3. 그리고 scene의 하이라키에 missing난 컴포넌트가 있으면 결과 번들파일이 달라진다.

   그러니 missing난 컴포넌트를 잘 살펴보자.


분석 시작 3주째....

어느순간 내가 분석한 데이터가 다 필요없다는걸 깨달았다.

분명 두번 빌드해서 결과값이 같은걸 보고 연관성을 찾으려 했는데

사실 두번 빌드 했을 경우 우연히 결과값이 맞을수도, 틀릴수도 있다는 걸 알았다.

그래서 연속으로 30번 빌드하는 기능으로 바꿔서 테스트 해 보니 내가 찾았던 문제로 의심되던 것들이 

다 의미가 없어졌다. 아무런 연관성이 없다. 이런 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX...

미친 XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

깊은 빡침이란 이런걸까...아..미친듯이욕하고싶다...이런...

AssetBundleExtractor의 도움으로 내부 덤프파일을 일일이 검사해보니 특정파일의

SInt64 m_PathID 값이 다른걸 발견했다.

이 m_PathID를 검색해 보니 이런 을 발견했다.


작업을 위해 필요했던 것들.

1. 모든 번들을 다 빌드하면 시간이 많이 걸리기 때문에 하나의 번들과 그에 연관된 번들만

   빌드하기 위해 파일별 개별 빌드 기능을 만듬.

2. scene 파일이 많기 때문에 모든 scene을 열어서 새로 저장하는 기능이 필요해서 만듬.

3. 특정 프리팹을 지울 때 이 프리팹을 쓰는 scene들을 찾기 위한 기능을 만듬.

   모든 scene을 열어서 하이라키에 특정 프리팹을 쓰는 곳이 있는지 찾음.

4. 특정 번들만 다른이름 으로 두번 연속 빌드해서 결과값 비교 기능 만듬.

5. 모든 스크립트 재컴파일 기능 추가.

6. 모든 scene의 모든 컴포넌트를 검사하여 missing 찾는 기능 추가.



딮빡침......그래서 유니티 패치를 찾아봄.....

아...이런..딮딮딮...빡침...미친...빡침...

나의3주가...나의시간이....허무하게소비되었어.....패치를꼼꼼히읽어야지.늘생각했거늘...이런...

업그레이드 후 테스트 하니 잘 됨.

이 버그를 발견해서 수정하려고 시작한 날짜가 5.12일 이고 위 패치노트가 나온날이 5.24일 이니까

이 때 미친듯이 구글링 했을때 못찾았던건 당연한건가.......

찜찜하지만 해결하는데 한달이 넘게걸렸군.....이런 거지같은...내 인생 최대의 고난이었음...


업그레이드 하지 않고 이 문제를 피해가기 위해서는 나름 테스트한 결과를 토대로 방법을 강구하자면

scene의 하이라키상에 프리팹이 있고 이 프리팹이 유니티가 지원해주는 스크립트가 아닌것을 컴포넌트로 가지면

문제가 발생한다. 그러니 프리팹을 끊던지 컴포넌트를 없애던지 프리팹을 동적로드로 바꾸던지 해야 한다.

이건 테스트 할 당시에는 발생을 안했는데 확실성을 가지진 않는다.

그러니 업그레이드를 추천한다.


Reference Link

- [SCENE]M_ROOTORDER ORDER BEING SAVED AS A PREFABMODIFICATION 

  WITHIN THE SCENE FILE HAS AN INCORRECT VALUE

UNITY TEXT FORMAT AND M_ROOTORDER TEXT

- SOME ASSET BUNDLE COMPONENTS HAVE DIFFERENT M_PATHID COMPARED TO 

  NEW ASSET BUNDLE WITH DELETED LIBRARY

-

'Unity > Unity Study' 카테고리의 다른 글

RenderQueue  (0) 2017.06.21
There are inconsistent line endings  (2) 2017.06.20
assetbundle building, change file  (0) 2017.06.03
메모리 프로파일러  (0) 2017.05.19
Asset Bundles vs. Resources : A Memory Showdown  (0) 2017.04.14
Asset Bundle Compression  (0) 2017.03.22
Posted by 붕대마음

댓글을 달아 주세요

개인 필요에 의해 번역한 글입니다.

원문을 참고하시길 강추드립니다.


유니티 5.3a4는 상당히 저레벨의 새로운 메모리 프로파일러 API가 있다.

이 프로파일러는 어느 오브젝트가 얼마나 많은 c++ 메모리 할당을 받았는지에

대해 찾아낼 수 있다.

IL2CPP 플랫폼에서 c#타입의 설명 뿐 아니라 전체 c# 힙의 덤프까지 제공한다.


이 API는 대부분의 사람들이 사용하기에는 너무 저레벨이다.

이 말은 이 API를 사용하기 위해 멋진 UI 윈도우가 더해지면

정말로 많은 사람에게 활용하기 유용할 것이며,

어느 오브젝트가 로드되었는지, 어느 오브젝트가 많은 메모리를 차지하는지,

그리고 가장 중요한 왜 그 오브젝트가 메모리에 있는지를 찾는데 도움을 줄 것이다.

이 레퍼지토리는 더 멋진 UI 윈도우로 작업이 진행중에 있다.


일반적인 "메모리 릭"의 패턴은 우리가 알고 있듯이, 

만약 정적 필드가 있는 c#클래스에 큰 크기의 Texture2D의 레퍼런스를 가지는

오브젝트의 리스트를 가지고 있는 경우이다.

이 Texture2D는 c#에서 여전히 접근할 수 있으므로 절대 언로드 되지 않는다.

이런 경우를 파악하기는 무척 힘들다.

이 새로운 메모리 프로파일러 윈도우는 직관적으로 만들어 질 것이며,

만약 큰 Texture2D를 선택하면, Texture2D가 로드되는 원인이 되는

정적 c# 필드(클래스 이름을 포함한)에 대한 대한 레퍼런스의 역추적 정보가 표시될 것이다.

이는 il2cpp 플렛폼에서만 작동하며, 이 역추적을 하기 위해 전체 il2cpp힙이 필요하다)


우리는 유니티 제품 자체에서 저수준 레벨 API를 올려 접근하는 방식을 채택하였고,

"적절하게 유니티에 포함될 충분한 준비"로 이미 오래전에 

이 메모리 프로파일러 윈도우를 오픈소스 형태로 해 두었다.

우리는 이 윈도우를 오픈소스 프로젝트로 개발할 것이다.

기부는 환영합니다.

어떤 시점에서 우리는 이 기능이 충분하다고 느낄 것이고,

그 시점에 유니티와 함께 상자 밖으로 나올 것이다.


오늘날, 이 기능의 UI 부분은 여전히 무척 힘들다.

우리는 어쨌든지 프로젝트를 오픈소스로 하기로 결정했으며,

너의 프로젝트에서 "메모리를 절약해야 하는데, 지금 우리가 무었을 할 수 있을까?" 라고 생각한다면,

너는 아마 메모리 릭을 찾는 것에 대해 더 많은 관심을 가질 것이며, 그리고

지금부터 6개월 뒤에는 이 기능의 훌륭한 버튼과 사용 경험으로 메모리 릭들을 찾을 것이다.


사용 :

- 유니티 5.3a4나 그 이상 버전 사용

- il2cpp 프로젝트로 빌드 & 실행 (어느 il2cpp 플렛폼이라도 괜찮다.)

- 이 레퍼지토리에서 프로젝트를 연다.

- 일반적인 프로파일러 윈도우를 연다.

- 일반적인 프로파일 하듯이 플레이어 연결

- 메모리 프로파일러 윈도우 열기(Window-MemoryProfilerWindow)

- "SnapShot" 클릭

- 또는 이 비디오 참조 : https://www.youtube.com/watch?v=7B6xRYMzst8


개인 생각

이 툴의 존재를 안지는 좀 되었는데 그다지 잘 활용하지 않았던 이유가 현재 프로파일러를 사용함에 있어

그다지 모자른 감이 없었고 이 툴 역시 기존 프로파일러와 같이 에디터상에서 종료시 깔끔하게

내부 캐시정보? 같은걸 정확하게 내려주지 않아서 아직 로드하지 않은 것들도 메모리에 로드되어 있어 보이기 때문이다.

물론 이 현상은 기존 프로파일러에도있어서 최적화 작업을 할 때는 보통 최대한 에셋을 클릭하지 않거나

클릭을 했다면 에디터 종료가 아니라 유니티 프로그램을 껏다 켜야 제대로 정보가 나왔다.

비주얼 적으로 훌륭하기 때문에 추천할만한 기능이다.


Reference Link

- unity technologies, MemoryProfiler

- c# 컴파일 그리고 il2cpp

- unity community, memory profiler

-

Posted by 붕대마음

댓글을 달아 주세요

필요에 의해 번역한 내용입니다. 원문을 보시기를 추천합니다.


리소스 : Resources

에셋번들 : Asset Bundles


최근에 우리는 기존 방식의 리소스 시스템 사용에 대한 것과 

왜 이전 에셋 로딩이 이후 에셋 로딩보다 메모리 오버헤드가 더 높은지에 대해 많은 문의를 받았다.


본문이 너무 길어 읽지 않은 사람들을 위해 : 

만약 리소스 시스템에서 할 수 없는걸 에셋번들이 할 수 있다면 

결국에는 에셋번들의 오버헤드가 훨씬 작을 것이다.

만약 에셋번들에 익숙하지 않고 에셋번들에 대해 더 알고자 한다면 Unity Manual

Asset Bundles & Resources Guide를 읽어보길 추천한다.


바로 살펴보면, 우리는 기본적으로는 같은 내용인 버그 리포트를 몇개 받았는데,

내용은 에셋번들을 통해 에셋을 로드할 때는 메모리가 몇 메가바이트 증가하지만

리소스를 사용하면 메모리가 증가하지 않는다는 내용이다.

버그를 단계별로 재현해 보면 위의 내용과 매우 비슷한 결과를 얻을 수 있다.

일반적인 메모리는 시작때 사용되고 에셋이 로드될 때 증가하며, 원래 값으로 돌아가지 않는것을 발견했다.


에셋번들의 메모리 사용량


리소스의 메모리 사용량


위의 실제 수치들을 살펴보기 전에 이러한 수치를 나타내는 시스템과 그들 사이의 관계에 대해 이야기 해 보자.

유니티의 네이티브 메모리 시스템은 메인스레드 대 백그라운드 스레드 같이 어디에 할당되어 동작하는 타입인지, 

또는 현재 실행중인 플랫폼이 무었인지에 따라 1MB ~ 32MB(평균 1MB 에서 4MB)의 

다양한 크기의 몇몇개의 고정 크기의 블럭 할당자(메모리풀)를 사용한다 

Reserved Total(총 예약)은 OS에 의해 할당된 모든 블럭들의 합인 반면,

Used Total(총 사용)은 Reserved Total에서 유니티가 실제로 사용하는 것을 나타낸다.

FMOD, Profiler 등의 각 레이블은 해당 할당자의 설정 값이거나 시스템에서 보고된

예상 외부 메모리를 나타낸다.

레벨 영역에 대해서는 Memory Profiler 메뉴얼을 참고하면 된다.

메뉴얼 페이지에 없는 것 중 알아야 할 게 좀 있는데, Used Total과 Reserved Total은 

이 글을 쓸 당시에(Unity 5.5.0f3) FMOD 값을 포함하지 않고 있는데

이 부분은 수정하고 있는 중이다.

(앱이 시작될 때 리소스 기준으로 계산 해 보자면, Used Total : 30.1메가 = 

Unity : 21.4메가, Mono : 356킬로바이트, GfxDriver : 4.6메가, Profiler : 3.7메가)

Total System Memory Usage(총 시스템 메모리 사용 양)는 플랫폼에 의해 시스템에서 보고받은 

가상메모리 크기로 이는 모든 플랫폼의 특징은 아니며, 지원하지 않는 경우에는 0으로 표시된다.

마지막으로 Used Total은 오브젝트의 헤더나 바이트 정렬을 고려하지 않지만, Reserved Total은 고려한다.

그래서 Asset Bundles vs Resources의 메모리 사용량을 살펴보기 위해, 

유니티의 Used Total과 Reserved Total 부분을 둘 다 집중해서 살펴볼 것이다.


프로파일러에서 진행되는 작업의 이해를 위해 필요한 또 다른 정보 하나는

에셋번들과 리소스의 데이터가 디스크에 배치되는 방법이다.

리소스와 에셋번들 두 방식의 핵심은 데이터 구조가 무척 비슷하다는 것이며,

직렬화된 오브젝트를 로드하기 위한 에셋 파일 경로의 매핑과 

추가 리소스 파일의 효율적인 비동기 로딩(텍스쳐, 오디오 등)을 위해

리소스와 에셋번들 둘 다 모든 오브젝트에 대한 직렬화된 데이터를 포함하는 하나의 파일을 가진다.

에셋번들은 이러한 파일들을 아카이브에 같이 저장하고 매핑은 에셋번들 오브젝트 안에 직렬화된 데이터에 저장된다.

리소스는 매핑을 ResourceManager라는 전역 싱글톤에 저장하고 파일 자체는 디스크에서 없어진다.

게다가, 리소스 시스템과는 달리, 에셋들은 모두 같은 에셋번들에 있어야 할 필요가 없으므로

데이터를 일부만 로드하여 메모리 사용량을 보다 많이 제어할 수 있다.

좀 더 자세한 정보는 에셋번들 내부 구조에 관한 메뉴얼에서 확인할 수 있다.

(이 글을 쓰고 있는 지금도 에셋번들 내부 구조에 관한 메뉴얼 글이 계속 갱신되고 있는 중인 듯 하다.)


Asset Bundles

Resource

유니티의 메모리와 파일 시스템에 대한 지식을 활용하여, 

이제 메모리 사용량 수치가 무었을 나타내는지에 대해 좀 더 깊이있게 이야기 해 보자.

첫번째로 두드러지는 내용은 에셋번들의 Reserved Unity 영역이 10메가 증가한 반면,

(60.1메가 -> 70.1메가) Resource는 전혀 증가하지 않았다(63.3메가 -> 63.3메가)는 것이다.

왜 그럴까?

이는 실제로 앞서 언급했던 블럭 할당자 때문이다.

이 특별한 메모리 사용량 테스트를 위해 비동기 로딩 API와 코루틴을 사용하는 AsyncBundleLoader.cs 를 사용하였다.

이 조합은 현재 시점까지 아직 사용되고있지 않는 다른 블럭 할당자를 실제로 사용하기에 무척 주의해야 한다.

그래서 이 10메가의 증가는 초기 메모리 블럭 할당과, 새 오브젝트에 필요로 하는 추가 메모리로

4메가 블럭을 할당, 이렇게 두 할당이다.

두개의 새로운 할당 중, 하나는 에셋번들 비동기 로딩을 위해 2메가 블럭을 할당하고,

다른 하나는 Type Trees를 위해 4메가를 할당한다.(Type Trees에 대해 자세한건 나중에 이야기 하자)

이러한 블럭 크기들은 여러개의 Asset들을 동시에 로딩하는 것에 최적화 되어있다.

예를들어, 에셋번들 비동기 로딩을 위한 할당이나 새 블럭을 필요로 하는 Type Trees가 없어도

동시에 4~5개의 에셋번들에서 오브젝트들을 로드할 수 있다.

이는 당연히 이 번들에 에셋번들 크기와 압축 사용여부, 그리고 얼마나 많은 스크립트를 

사용했는지에 따라 다르다.


이러한 블럭 할당의 경우, Type Tree를 위한 4메가 블럭은 에셋번들에서 오브젝를 실제로 로딩할 때만 필요하다.

이 블럭은 사용후에는 사라져야 하지만, 예제에서 코루틴을 어떻게 구조화 했는지에 따라 

AssetBundleRequest 오브젝트는 여전히 사용중으로 간주되어 가비지 컬렉터에 의해 정리되지 않는다.

에셋번들 비동기 로딩을 위한 2메가는 에셋번들 아카이브 내의 버퍼를 읽는 스레드용으로

사용되며 번들에 대한 내부 참조가 없을 때 사라진다.

마지막 4 메가 블럭은 모든 오브젝트 저장에 사용되는 메인 할당자에 있기 때문에 사라지지 않는다.

일반적인 프로젝트에서는 오브젝트의 생성 및 삭제가 빈번하게 발생하므로 오브젝트를

해제하여 할당자에게 되돌려주는 대신 재사용을 위해 메모리를 풀링한다.

마지막으로 언로드된 Reserved Unity 값을 보면, 에셋번들의 값이(64.1 MB)

단지 할당자가 새 블럭을 얻는 순서때문에 Resource의 값(63.1 MB)에 매우 가깝다는 것을 알수 있다.


여태껏 Reserved 메모리에 대해 이야기 했는데, 에셋번들과 리소스 사이에

실제 Reserved 메모리를 사용하는 효율성은어떨까?

이는 유니티의 Used 영역이 바로 표시해 주기 때문에 인지하기가 무척 쉽다.

에셋번들의 경우 Reserved 메모리에서 21.7 MB를 사용하고, 

리소스는 에셋번들보다 조금 더 많은 22.2 MB를 사용한다.

게다가, 언로드 시킬 때, 이 메모리는 각각 20.7 MB와 21.2 MB로 떨어진다.

그래서 Asset Bundle이 효율적인 메모리 활용면에서는 분명하게 승리자이다.

이미 알고 있듯이, 언로딩 후 에셋번들 사용량은 시작 했을 때 보다 훨씬 커졌다.

(16.3 MB -> 20.7 MB , 4.4 MB가 커져있다.)

이전에 언급했었듯이 메모리 재사용을 위해 풀링되어 있기 때문에 에셋번들과 에셋을 

다시 로드하면 21.7 MB로  돌아간다.

리소스의 경우에는, 시작과 언로드 간의 메모리 차이는 반올림 오류 때문이다.


에셋번들을 위한 블럭 할당은 성능과 하위 호환성과의 절충으로 줄일 수 있다.

위에서 언급했듯이, 오브젝트를 로드하기에 충분한 메모리가 없기 때문에

4 메가 블럭 할당은 불가피 하다.

나머지 6 MB중 2 MB는 비동기로딩 API를 사용하기 때문에 발생한다.

그래서 블럭 할당을 피하기 위해서는, FPS 버벅거림을 감수하고 synchronous API을 사용하면 된다.

마지막 4 MB 할당은 Tree system 타입 때문이며, 위에서 언급했듯이 더 자세히 설명할 것이다.

이 시스템은 여분의 데이터를 Asset BUndle에 저장하지만, 리소스에는 저장하지 않으며,

이는 Asset Bundle을 보다 넓은 범위의 유니티 버전과 호환 가능하게 만들고

FromerlySerializedAsAttribute 와 같은 직렬화 속성을 작동시킨다.

이는 만약 새 버전으로 유니티를 업그레이드하거나 중요하지 않은 코드를 바꾸거나 할 때, 

그것들을 재빌드 하는 대신에, 게임 변경시 유저가 전체 에셋번들을 다시 다운로드 하게 할 때

동일한 에셋번들을 계속 사용할 수 있다.

이 추가 데이터를 쓰지 못하게 하려면 BuildAssetBundleOptions.DisableWriteTypeTree 옵션을

BuildPipeline.BuildAssetBundles API에 전달하면 된다.


Asset Bundles Loaded Synchronous without Type Trees


Asset Bundle 1, Resource 0 개 있다.

만약 이 데이터를 직접 재현하고자 한다면 이 블로그에서 사용된 스크립트가 Github Gist에 업로드 되어 있다.

현재 Texture, Monobehaviro, 그리고 Prefab를 100개씩 생성하도록 설정되어 있으며,

고정 랜덤화 시드를 사용하기때문에 실행 할 때 마다 동일한 결과가 나올 것이다.

(하지만 아마도 나의 결과와는 다를 수 있다.)

Asset Bundle 프로젝트에 실수로 컨텐츠가 있는 Resource폴더를 만들지 않도록 만들어야 하는데

그렇지 않다면 메모리 값이 예상보다 두배가 된다.



Reference Link

- 원문

- unity doc, The Profiler WIndow

- unity doc, Practical guide to optimization for mobiles

- unity doc, FromerlySerializedAsAttribute

- 파일 직렬화

- 파일 아카이브

- unity doc, 자동 메모리 관리를 이해하기

-

Posted by 붕대마음

댓글을 달아 주세요

Mesh 최적화

Optimizing/Unity / 2017.04.11 07:40

5.5.1p3 기준


하나씩 테스트를 해 보자.

Mesh Compression : 이 값을 높이면 메쉬 파일 크기가 줄어든다.

실제로 어떻게 차이가 나는건지 테스트 해 보자.

Mesh Compression : Off



Mesh Compression : High


뭔가 모습이 좀 달라진거 같기도 하고 아닌거 같기도 하고...

겹쳐서 보면 좀 움찔움찔 바뀌는 것 같음.


버텍스 갯수라던지 파일의 용량은 1도 안 줄어들었음.. 뭘까 분명 줄어든다고 했는데...

그런데 모양은 바뀐단 말이지....

여기 링크를 읽어보면 이렇게 적혀 있다.


"게임 파일에서 적은 공간을 차지하도록 메쉬와 임포트된 애니메이션 클립을 압축할 수 있다.

메쉬압축을 하려면, 메쉬를 선택 후 인스펙터에 있는 Mesh Compression을 Low, Medium 또는 High로 설정해라

메쉬와 애니메이션 압축은 양자화를 사용는데 이 말인 즉슨, 압축을 사용하면 공간은 덜 차지하지만

부정확성이 생길 수 있다는 것이다.

압축을 사용하고자 하는 모델에 어느정도 압축이 적합한지 테스트 해 봐라.

메쉬 압축은 단지 좀 더 작은 데이터 파일만 만들어 낼 뿐 실행시간에 더 적은 메모리를 사용하지는 않는다는 것을 알아야 한다.

애니메이션 키프레임 감소는 실행시간에 좀 더 작은 데이터 파일과 더 적은 메모리를 사용한다.

일반적으로 항상 이 기능을 켜둬라."


으잉? 데이터파일은 작아졋는데 메모리는 줄어들지 않는다고? 흐음...좀 이상하네.

아래 유니티 포럼에서 댓글을 좀 모아서 정리하자면 아래와 같다.


"이 기능은 실제로는 렌더링이나 메모리를 위한 기능이 아니라 게임 빌드 용량을 위한 기능이라고 봐야할듯하다.

즉, mesh 압축은 더 작은 메시로 만드는게 아니라 꼭지점/ 겹침 선을 제거한다.

메쉬 데이터를 저장하는 정밀도를 줄여 공간을 절약한다.

하지만, 메쉬 렌더링이 끝나면 이전과 같은 복잡성을 가지며 정확도는 약간 떨어진다.

그래서 파일 용량은 줄어들지만 렌더링시 퍼포먼스적인 그다지 이슈는 없다.


실제로 메쉬압축을 끄고 빌드한 경우 2.74메가, High로 한 경우 2.70메가가 나왔다.

우선 유니티 도큐먼트에서 말했던 더 작은 데이터 파일을 만들어 낸다는 말은 맞는말!! 

근디 좀 더 확확 해주지 0.04메가 줄다니..ㅜㅜ.


혹시나 해서 프로파일러로 메모리에 올라가는 크기를 찍어봤다.

메쉬 압축 Off : 349.3, 메쉬 압축 High : 248.2 가 나왔다.

메모리는 안 준다더니 줄어들었네??

물론 이건 위에서 만든 번들로 실행한게 아닌 로컬파일로 실행한 거긴 하지만 머 같지 않을까...


찜찜한 기분에 번들로 체크를 해 봤다.

메쉬 압축 Off : 349.3 메쉬 압축 High : 248.2

그래도 줄어들었다.


혹시나 해서 프레임 디버그로 정점갯수도 찍어봤지만 메쉬 압축을 Off로 하든 High로 하든 결과는 같았다.

그래서 내가 테스트 한 결과는 아래와 같다.

메쉬 압축 Off : 파일 용량(2.74 MB), 메모리(349.3 KB)

메쉬 압축 High : 파일 용량(2.70 MB), 메모리(248.2 KB)

테스트 환경 : pc, assetbundle. 유니티 프로파일러, 유니티 프레임 디버거 사용.


유니티 도큐먼트랑은 결과가 조금 다르게 나왔다.

내가 해석을 잘못 한걸까? ㅜㅜ.

유닛히에게 문의 좀 해봐야겠다.

(실제 테스트는 위 사진처럼 유니티의 예제 모델이 아닌 프로젝트 모델로 하였지만

글을 공개로바꾸기 위해 유니티 모델 사진으로 수정했슴.)


Read/Write Enabled : 런타임에 mesh 쓰기가 가능하도록 메모리에 복사본이 생성한다.

이 옵션을 끄면 유니티가 게임의 mesh 데이터를 언로드 할수 있기 때문에 메모리가 절약된다.

하지만 런타임에 비균등 스케일로 메쉬를 스케일링 또는 인스턴스화 하면 이 기능을 켜야하는 경우가 많다.

비균등 스케일링은 mesh 데이터를 메모리에 유지해야 하기 때문이다.

런타임에 MeshColliders를 만들고자 할 경우에도 마찬가지이다.


Optimize Mesh : 메쉬의 삼각형 순서를 결정한다.

이 기능을 사용하면 메쉬가 더 빨리 디스플레이 되며 로드시간이 줄어든다.

내부적으로 정점 캐시 영역에 대한 삼각형을 최적화 한다.


Import BlendShapes : 모프타겟 또는 정점 애니메이션.

자세한 내용은 이곳을 참고하자.

안쓰면 꺼두자. 


Normal & Tangents : Normal의 계산여부

이 옵션을 None으로 하면 게임크기가 줄어들고 Tangents 기능이 자동으로 꺼진다.

Import가 기본옵션이며 파일에서 법선을 임포트 한다.

Calculate는 Smoothing angle에 따라 법선을 계산한다.

None은 법선을 해제하므로 메시가 매핑된 법선을 사용하거나 실시간 라이팅의 영향을

받고 있는 법선인 경우는 사용하면 안된다.

쓰지않으면 None으로 설정하자.


Tangents : 탄젠트와 종법선 계산여부.

이 옵션은 위의 Normal & Tangents의 하위옵션이다.

Import는 파일에서 탄젠트와 종법선을 가져온다.

Calculate는 탄젠트와 종법선을 해제한다.

None은 탄젠트와 종법선을 해제하는데 메쉬에는 탄젠트가 없기에 법선매핑 셰이더로 사용할 수 없다.

쓰지않으면 None으로 설정하자.


Reference Link

- Mesh compression - what does it actually do?

- Does mesh compression increase performance of Unity3D games?

- Reducing the file size of your build

- Mesh

- Model

- Animation BlendShapes

-

'Optimizing > Unity' 카테고리의 다른 글

MaterialPropertyBlock  (0) 2017.06.27
Mesh 최적화  (0) 2017.04.11
Dynamic Batching이 효율적일까?  (0) 2017.03.31
유니티 텍스처  (0) 2017.03.22
animation 최적화  (0) 2017.03.04
유니티에서의 메모리 관리.  (0) 2017.01.13
Posted by 붕대마음

댓글을 달아 주세요

항상 날 괴롭히던 버그가 하나 있었다.

NullReferenceException: WWW class has already been disposed.


c#코드에서 www를 쓸 때 나는 에러인데 왜 이게 나는지 항상 의문이었다.

이 에러가 나는 원인은 말 그대로 www값이 이미 제거되었는데 이 값으로 무언가를 하려 하기 때문이다.

나의 경우는 이런상황에서 나왔다.

www test = new(path)


// path가 잘못되서 test가 err남

if (test.error != null)

{

        // err 난건 폐기하려고 함

test.Dispose();

  return;

}


위 코드에서 err난 시점에 이미 dispose되었는데 코드에서 다시 dispose를 하려 해서

위와같은 에러가 났다.


Posted by 붕대마음
TAG Dispose, Unity, WWW

댓글을 달아 주세요

이전에는 안그랬는데 유니티 버전을 올렸더니 아래와 같은 경고가 자꾸 남.

이런 경고가 나는곳은 특정 텍스처에 현재 화면을 찍어주는 역활을 하는 곳이었는데

대충 아래와 같은 코드로 되어 있었다.


void OnRenderImage(RenderTexture source, RenderTexture destination)

{

         .....

       다른곳에서 받은 RenderTexture rt에 현재 스샷을 찍는다.

       Graphics.Blit(source, rt, mat, 0);

      그리고 이런저런 처리를 하고 이 rt를 다른곳에서 쓴다.

}


이전에는 문제가 없었는데 언제부턴가 위와같은 경고가 나왔다.

내용은, "너 임마,  걍 destination에 아무것도 안썻잖아" 이다.

그냥 이렇게 냅둬도 디바이스에서도 별로 문제가 없는것 같고

그냥 실수한거 아니냐는 느낌으로 경고를 띄워주는것 같은데 이런 경고가 보기 싫으면

그냥 머 한번 써 주면 된다.

가장 아래줄에 이렇게 넣어줬다.

Graphics.Blit(source, destination);

이러면 경고가 사라진다.


해도 그만 안해도 그만인듯.

Posted by 붕대마음

댓글을 달아 주세요

최근에 달린 댓글

최근에 받은 트랙백

글 보관함