유니티의 Frustum Testing 에 대해 알아본다.


Frustum Testing 은 원하는 시점에 특정 게임 오브젝트가 화면에 보이는지를 알아보는 방법이다.



1. 먼저 아래처럼 카메라 객체로부터 절두체를 구성하는 각 평면들을 얻는다.

Plane[] planes = GeometryUtility.CalculateFrustumPlanes(Camera.main);



2. 다음은 게임 오브젝트의 영역 정보인 Bounds 를 얻는다. 보통은 렌더러에서 얻는데, 특수한 경우로 컬라이더에서 얻기도 한다.

Bounds bounds = targetGameObject.renderer.bounds;    // 렌더러에서 얻음

Bounds bounds = targetGameObject.collider.bounds;    // 컬라이더에서 얻음



3. 이제 아래의 코드를 통해 화면에 보이는지를 체크할 수 있다.

bool isVisible = GeometryUtility.TestPlanesAABB(planes, bounds);

Posted by 카코데몬
,



위 그림에서 바닥, 그리고 두 개의 큐브가 있고 이들을 Bake 한 네비게이션 메시들을 볼 수 있다.Off Mesh Link 는 위처럼 떨어져 있는 네비게이션 메시들끼리 연결해주는 개념으로, 두 가지 빙식이 있다.


먼저 첫 번째 방식을 알아보자. 첫 번째 방식은 Bake 시점에 네비게이션 메시들끼리의 높낮이 차이, 떨어진 거리의 차이로부터 연결을 생성하는 방식이다. 높낮이의 경우, 두 네비게이션 메시끼리의 높낮이 차이가 특정 값 이하인 경우 높은 네비게이션 메시에서 낮은 네비게이션 메시로 연결이 생성된다. 이를 직접 눈으로 확인해보자. 왼쪽 큐브를 선택한 후 Navigation Window 에서 다음처럼 설정해준다.





Drop Height 의 경우 상황에 맞게 적당한 값을 넣어준다. 이 상태로 Bake 를 하면 다음과 같은 연결이 생성됨을 확인할 수 있다.





이러한 연결이 생기면 해당 큐브 위의 물체가 바닥의 특정 목표점으로 이동할 수 있는 경로가 만들어진 것이다.


거리의 차이로부터 연결을 생성하는 것은 높낮이 차이의 그것과 크게 다르지 않다. 단지 Drop Height 대신 Jump Distance 가 사용된다는 차이가 있다. 위 상태에서 Jump Distance 에도 적당한 값을 넣어서 Bake 해보면 다음과 같은 결과를 얻을 수 있다.





이번엔 옆 큐브 쪽의 네비게이션 메시로 연결이 생성됐다.


이제 두 번째 방식을 알아보자. 두 번째 방식은 연결되길 원하는 두 지점을 직접 지정하는 방식으로, 컴포넌트를 이용하기 때문에 Bake 할 필요가 없다. 먼저 두 개의 게임 오브젝트를 만들고 연결되길 원하는 각 지점에 배치한다. 이제 또 다른 게임 오브젝트에 Off Mesh Link 컴포넌트를 추가하고 Start, End 에 방금의 오브젝트들을 연결해준다.





두 지점이 네비게이션 메시와 어느 정도 근접해 있어야 연결이 생성된다. 에디터 상에서 두 지점을 이리저리 움직여가며 연결을 만들어보자.




위와 같이 연결을 생성할 수 있다. 두 지점을 변경할 때마다 연결은 새로 갱신된다.

Posted by 카코데몬
,

오브젝트를 렌더링할 때 기본적으로 Renderer 컴포넌트의 sharedMaterial 이 사용된다. 이는 에디터에서 오브젝트에 설정해둔 재질과 정확히 일치한다. 즉 sharedMaterial 은 매트리얼 에셋과 대응한다. 이를 확인하는 방법은 실행 중에 sharedMaterial 의 속성을 변경해보는 것이다. 그럼 에셋이 바뀌어 있는 것을 확인할 수 있다. 심지어 종료해도 변경 상태가 남아있게 되므로 주의..

기본적으로, 매트리얼에 수정을 가하지 않으면 sharedMaterial 을 참조하여 렌더링된다. 그리고 이는 배치 렌더링의 핵심이다. 동일한 재질을 지녀야 한번에 렌더링할 수 있기 때문.

그러나 상당히 많은 경우에서 특정 오브젝트의 재질 속성을 변경할 필요가 생긴다( 일시적으로라도 ). 컬러값, 빛의 세기, 텍스처 등.. 이러한 이유 때문에 sharedMaterial 과 함께 material 이 존재한다. 유니티는 sharedMaterial 이 아닌 material 에 접근하는 순간 sharedMaterial 의 사본을 생성하여 material 에 할당해준다. material 은 Renderer 에 존재하며 다시 Renderer 는 오브젝트가 소유하므로 즉 오브젝트에 할당된 재질이다. 따라서 다른 오브젝에 영향을 주지 않으면서 재질 속성을 달리할 수가 있게 된다. 이렇게 사본이 생성되면 에디터상에서 오브젝트의 재질을 확인했을 때 (Instance) 라는게 붙는다는 것을 알 수 있다.

사본이 생성되는 순간 이 오브젝트는 배치 렌더링을 포기하게 되는 것이다. 한번 material 을 사용하게 되면 해당 오브젝트는 다시는 배치 렌더링을 할 수 없게 된다. 그리고 material 의 값을 변경하지 않더라도 참조하는 순간 사본이 생성된다( material, material.color, 이하 material 을 참조하는 순간.. ).

다행히, 일시적으로 재질 속성을 변경하기 위한 좋은 대안이 있는데 바로 재질 속성 블럭( Material Property Block ) 이다. 방법부터 정리하면 아래와 같다.

 

// 재질 속성 블럭을 생성한다. 생성은 한 번만 하면 되므로 Awake 같은 곳에서 호출하자
MaterialPropertyBlock mpb = new MaterialPropertyBlock();

// 방금 생성한  객체에 변경하길 원하는 재질 속성들을 설정한다
mpb.SetColor(Shader.PropertyToID("_Color"), Color.black);

// 렌더러에 객체를 설정해준다( 만약 이후에 재질 속성 블럭을 수정했다면 다시 아래 코드를 호출해줄 것 )
renderer.SetPropertyBlock(materialProp);

// 재질 속성을 원래대로 돌리는건 아래처럼 해주면 된다
renderer.SetPropertyBlock(null);

 

위처럼 재질 속성 블럭을 이용하면 사본이 생성되지 않으며 객체가 set 되어 있는 동안에만 배칭되지 않는다.

'유니티 - 최적화' 카테고리의 다른 글

NGUI 최적화의 핵심  (1) 2016.01.14
텍스처 최적화  (0) 2016.01.13
최적화의 기본  (0) 2016.01.08
Update 와 FixedUpdate  (0) 2016.01.08
Application.Integrate Assets in Background 에서 렉이 발생하는 경우  (0) 2016.01.08
Posted by 카코데몬
,