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

카테고리

전체목록 (618)
참고사이트 (9)
Goal (3)
Travel (10)
My Life (84)
Game (36)
Game Review (7)
Game Plan (0)
Books (5)
English (1)
Optimizing (11)
Study (207)
유용한 것들_etc (44)
유용한 것들_func (20)
Unity (41)
Unreal (87)
작업장 (45)
RenderMonkey (6)
정리요망 (2)
따라잡기 시리즈 (0)
링크용 (0)
Total275,959
Today35
Yesterday204

50x50 같은 물체가 있다고 가정하자.

이들 물체의 색은 상황에 따라 몇가지 색상으로 변경될 수 있다.

즉, 하나의 물체의 색상이 빨간색, 파란색, 노란색 등 바뀔 수 있다는 것이다.

2500개의 물체를 그리더라도 색상이 다 같다면 배치는 한번만 이루어 진다.

하지만 2500개의 물체가 다 다른 색상을 가진다면 배치는 물체의 수만큼 이루어 진다.


!테스트에 사용된 리소스와 소스파일은 가장 아래에 있습니다.!


테스트 1. 단순하게 2500개의 물체 뿌리기

Test Code

GameObject[] objects;

void Start()

{

if (sphere)

{

float colorOffset = square * square;

objects = new GameObject[square * square];

for (int xi = 0; xi < square; xi++)

{

for (int zi = 0; zi < square; zi++)

{

GameObject go = Game.CreateDynamicObject(sphere, this.gameObject.transform);

go.transform.position = new Vector3(xi, 0, zi % square);

go.name = "sphere" + xi.ToString() + "_" + zi.ToString();

objects[xi * square + zi] = go;

}

}

}

}

결과값

material : 40

setpass call : 2

draw calls : 2501

(static batching)batches : 0

참고로 테스트 화면이 기본 디폴트 화면이라서 스카이 박스나 플랜등 기본적으로 쓰는 값이 있다.


테스트 2. static batching

Test Code

..

StaticBatchingUtility.Combine(gos, this.gameObject);

..

}

결과값

첫번째 테스트에서 staticbatching만 추가했다.

머티리얼이 바뀌지 않는이상 머티리얼은 하나로 사용하기 때문에 배칭이 될 수 있다.

material : 40

setpass call : 2

draw calls : 102

(static batching)batches : 101

배칭에 관한 내용은 이곳에 정리를 한 적이 있어서 다시 자세히 언급하지는 않고 패스한다.


테스트 3. 색상 바꾸기.

Test Code

첫번째 테스트에서 material.color = ...만 추가되었다.

objects[xi * square + zi].material.color = new Color(rCol + (xi * square + zi) / colorOffset, gCol, bCol);


결과값

material : 2540

setpass call : 2501

draw calls : 2501

(static batching)batches : 0

위 결과값에서 보면 알 수 있듯이 머티리얼 갯수가 기존 40개에서 2540개로 늘어났다.


테스트 4. MaterialPropertyBlock 사용

Test Code

첫번째 테스트에서 Offset 관련 코드만 추가되었다.

go.GetComponent<SphereWithMaterialPropertyBlock>().Offset = (xi * square + zi) / colorOffset;

그리고 물체 프리팹에 아래와 같은 코드를 달아 주었다.

void Start()

{

    _propBlock = new MaterialPropertyBlock();

    _renderer = GetComponent<Renderer>();

    _renderer.GetPropertyBlock(_propBlock);

    _propBlock.SetColor("_Color", Color.Lerp(Color1, Color2, (Mathf.Sin(Time.time * Speed + Offset) + 1) / 2f));

    _renderer.SetPropertyBlock(_propBlock);

}


결과값

material : 40

setpass call : 2501

draw calls : 2501

(static batching)batches : 0

render opaque geometry : 3.26

위 결과값에서 보면 알 수 있듯이 머티리얼 갯수가 테스트 3에서 컬러바꿀 때와 다르게

2540개가 아니라 40개로 2500개가 줄었다.


테스트 5. material.color update(animation)

Test Code

업데이트 함수에서 컬러를 계속 변경해준다.

void Update()

{

float colorOffset = square;

if (objects[0] == null)

return;

for (int xi = 0; xi < square; xi++)

for (int zi = 0; zi < square; zi++)

objects[xi * square + zi].material.SetColor("_Color", Color.Lerp(Color.red, Color.yellow, (Mathf.Sin(Time.time * 1.0f + (xi * square + zi) / colorOffset) + 1) / 2f));

}


결과값

material : 2540

Render.OpaqueGeometry : 9.03

Material.SetPassUncached : 6.3

Color Change 관련 Update : 5.49


테스트 6. MaterialPropertyBlock update(animation)

Test Code

첫번째 테스트에서 Offset 관련 코드만 추가되었다.

go.GetComponent<SphereWithMaterialPropertyBlock>().Offset = (xi * square + zi) / colorOffset;

그리고 물체 프리팹에 아래와 같은 코드를 달아 주었다.

void Start()

{

    ..

   go.GetComponent<SphereWithMaterialPropertyBlock>().Offset = (xi * square + zi) / colorOffset;

    ..

}

각 프리팹의 스크립트에서 아래와 같이 업데이트 해 준다.

void Update()

 {

      _renderer.GetPropertyBlock(_propBlock);

      _propBlock.SetColor("_Color", Color.Lerp(Color.red, Color.yellow, (Mathf.Sin(Time.time * Speed + Offset) + 1) / 2f));

      _renderer.SetPropertyBlock(_propBlock);

}

그리고 셰이더 코드의 컬러값에 [PerRendererData]을 추가해 준다.


결과값

material : 40

Render.OpaqueGeometry : 2.90

Material.SetPassUncached : 없음

Color Change 관련 Update : 2.64


테스트 5와 테스트 6의 결과를 비교해 보면 Material 갯수가 2540에서 40으로 줄어들었고

렌더링 하기 위한 시간이 9.03에서 2.90으로 6.13정도 줄었다.

이는 아마 setpass 관련 시간인듯 하다.

업데이트 시간을 보면 5.49에서 2.64로 줄었다.

이제 정리를 해 보자.

Material을 접근 할 때는 Renderer.sharedMaterial과 Renderer.material 이렇게 두가지가 있다.

일반적으로 렌더링 시 sharedmaterial을 참조해서 랜더링 하는 이는 하나의 머티리얼을 공용으로 

사용하는 것이고 이를 통해 배칭이 가능하게 된다.

하지만 여기에 수정을 가해야 할 때(예를들어 머티리얼의 컬러값을 바꿔야 할 때) 생각해야 할 부분이 있다.

10개의 물체가 같은 머티리얼을 공유하는 중에 sharedmaterial.color값을 수정하면 모든 물체의 color값이 바뀐다.

이걸 원한다면 다행이지만 그렇지 않다면 material.color을 수정해야 하는데 이렇게 되면 하나의 물체의 컬러만 

바꿀 수 있긴 하지만 material을 참조하는 순간 내부적으로 sharedmaterial의 사본이 생성되어 material에 할당된다.

하지만 MaterialPropertyBlock을 사용하면 사본이 생성되지 않는다.

그리고 모든 물체들이 다시 같은 색상 파라미터값을 가지게 되면 배칭이 된다.

아래 참고 글중 "Setting MaterialPropertyBlocks breaks batching"을 인용하자면,


"배칭은 GPU로 GPU로 보내기 전에 여러 오브젝트의 지오메트리를 결합하여 하나의 객체로

렌더링하는 것을 의미한다. 당연히 모든 셰이더는 정점 데이터의 일부가 아니라 전반적으로 같아야 한다.

그래서 머티리얼 프로퍼티를 바꾸면, 어떤 짓을 하더라도, 프로퍼티가 같지 않는 한 오브젝트는 배칭이 되지 않는다.

MaterialPropertyBLock은 파라미터 값이 많이 바뀌는 많은  인스턴스가 있는 상황을 위한 것이다.

그래서 머티리얼을 복제할 필요는 없지만 동적으로 전역 셰이더를 동일한 MaterialPropertyBlock로 설정한다.

이는 드로우콜이 절약되지는 않지만 오버헤드는 절약된다. (뒤의 이야기는 질문자의 코드에서 사용번 관련 이야기)"


그리고 유니티 도큐먼트에 보면 "같은 머티리얼을 가진 여러개의 오브젝트를 그리고 싶은데 프로퍼티 값이

살짝씩 다른경우에 사용한다. 예를 들면 각 메시를 그릴 때 색사을 살짝 다르게 하는 정도며 렌더 스테이트의

변경은 지원되지 않는다. 유니티 지형 엔진은 나무를 그리기 위해 이 기능을 사용하고 있다.

모든 나무가 같은 머티리얼이지만 다른 색상, 크기, 그리고 바람 속성값을 가진다.

Graphics.DrawMesh나 Renderer.SetPropertyBlock에게 전달된 블럭은 복사되어지며, 

그래서 이 기능을 가장 효율적으로 사용하는 방법은 하나의 블럭을 만들어서 모든 DrawMesh 호출에 

재활용 하는 것이다."라고 적혀있다.


아래 링크중 "The Magic Of Material Property Blocks"을 참고하면

"셰이더 파일에 [PerRendererData] 속성으로 셰이더 프로퍼티를 명시해 줘야 한다.

이걸 추가 해 주면 이 셰이더를 사용하는 모든 렌더러에 공유되는 대신 해당 속성(예를 들면 _Color)

이 렌더러별로 설정되는 방식으로 유니티에 셰이더를 컴파일 하도록 요청한다.

그렇지 않으면 SetPropertyBlock이 작동은 하지만 내부적으로 머티리얼 인스턴스를 만들어서

renderer.material과 같은 결과가 된다." 라고 적혀 있어서 그렇게 하긴 했는데

실제로 저 [PerRendererData]를 넣는 것과 넣지 않는것에 대한 프로파일러의 변화값을 못찾겠다.


testProperty.unitypackage


Reference Link

- The Magic Of Material Property Blocks

- The Magic Of Material Property Blocks 번역

- Dynamic Batching이 효율적일까?

- unity, MaterialProperty

- Setting MaterialPropertyBlocks breaks batching

- unity, ShaderLab: Properties



저작자 표시 비영리 변경 금지
신고

'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 붕대마음

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' 카테고리의 다른 글

RenderQueue  (0) 2017.06.21
There are inconsistent line endings  (0) 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 붕대마음

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' 카테고리의 다른 글

RenderQueue  (0) 2017.06.21
There are inconsistent line endings  (0) 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 붕대마음

최근에 달린 댓글

최근에 받은 트랙백

글 보관함

티스토리 툴바