오늘의 학습 키워드
Static Batching, Dynamic Batching, Gpu Instancing
공부한 내용
Static Batching
Static Batching은 드로우 콜을 줄이기 위한 배칭의 한 기법으로 움직이지 않는 여러 오브젝트가 같은 Material을 공유할 때 메시를 통째로 메모리에 같이 올려 한 번에 그려주는 기능이다.
특징
- 정적인 오브젝트 대상 (인스펙터에서 static 체크)
- 여러 메시를 통째로 미리 메모리에 올리기 때문에 추가적인 메모리 필요
- 런타임 전에 상태 변경 명령을 수행
- 드로우콜 감소 -> CPU 병목 완화
*드로우 콜 : CPU가 GPU에게 상태 변경 명령부터 렌더링까지 명령하는 것
Dynamic Batching
Static Batching은 드로우 콜을 줄이기 위한 배칭의 한 기법으로 움직일 수 있는 동일한 메쉬를 가진 여러 오브젝트가 같은 Material을 공유할 때 런타임 중에 버텍스를 모아 한 번에 그려주는 기능이다.
특징
- Skinned Mesh에는 적용 불가
- 버텍스 수가 일정 수치보다 높으면 적용 불가
- 런타임 중에 버텍스 정보를 읽어오므로 오버헤드 증가
- 드로우 콜 감소 -> CPU 병목 완화
GPU Instancing
GPU Instancing은 동일한 메시의 복사본들을 만들어 별도의 메시를 생성하지 않고 GPU에서 원본 메시를 가져다가 여러 오브젝트를 한 번에 처리해서 렌더링한다.
특징
- GPU에서 인스턴싱 처리 -> 오버헤드나 메모리 이슈에서 자유로움 (버텍스 수로부터 자유로움)
- 동일한 모양의 오브젝트들이 많이 렌더링 되어야 할 때 유용한 기법
Mesh.CombineMeshes
Mesh.CombineMeshes는 동일한 Material을 공유하는 메시끼리 스크립트를 통해서 합쳐주는 메서드이다.
- 런타임 동안 파츠가 조합되어 오브젝트가 만들어져야 하는 경우라면 고려할만 하다.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
// 모델링 과정에서 하나의 오브젝트로 만들어져 생성하는 것이 좋겠지만
// 같은 Material을 공유하고 파츠별로 바꿔서 조립하며 버텍스 수가 많아 다이나믹 배칭이 어려운 상황에서는
// CombineMesh도 고려할만 하다.(배치와 SetPass 감소)
public class CombineMesh : MonoBehaviour
{
void Start()
{
CombineMeshs();
}
private void CombineMeshs()
{
// 자식들의 메쉬 필터와 렌더러를 가져옴
MeshFilter[] meshFilters = GetComponentsInChildren<MeshFilter>();
MeshRenderer[] meshRenderers = GetComponentsInChildren<MeshRenderer>();
// 컴바인인스턴스 배열을 메쉬 필터의 길이만큼 생성
CombineInstance[] combineInstances = new CombineInstance[meshFilters.Length];
if (CanMeshCombine(meshRenderers))
{
// 메쉬 필터, 렌더러 정보를 컴바인인스턴스에 저장하고 게임 오브젝트 다 끄기(자식)
for (int i = 0; i < combineInstances.Length; i++)
{
combineInstances[i].mesh = meshFilters[i].sharedMesh;
combineInstances[i].transform = meshFilters[i].transform.localToWorldMatrix; // 트랜스폼 로컬 좌표를 월드 좌표로 변환
meshFilters[i].gameObject.SetActive(false);
}
// 새 메쉬 필터와 렌더러 컴포넌트 추가
MeshFilter meshFilter = gameObject.AddComponent<MeshFilter>();
MeshRenderer meshRenderer = gameObject.AddComponent<MeshRenderer>();
// 메쉬 렌더러 Material 초기화
meshRenderer.sharedMaterial = meshRenderers[0].sharedMaterial;
// 새 메쉬 생성 후 메쉬 필터에 넣어놓고 메쉬를 합침
Mesh newMesh = new Mesh();
meshFilter.mesh = newMesh;
//메쉬 합치기
newMesh.CombineMeshes(combineInstances);
// 이후 오브젝트 켜주기(부모)
transform.gameObject.SetActive(true);
}
}
// Material이 같다면
private bool CanMeshCombine(MeshRenderer[] renderers)
{
Material material = renderers[0].sharedMaterial;
for (int i = 1; i < renderers.Length; i++)
{
if (material != renderers[i].sharedMaterial)
{
return false;
}
}
return true;
}
}
오늘의 회고
오늘은 팀 프로젝트 제출과 발표가 있었다. 나는 오늘 오전에 버그를 잡고 시연 영상을 찍는 작업을 했는데 시연 영상을 찍을 때마다 새로운 버그가 나와서 바로바로 고쳐서 겨우 제출할 수 있었다. 오후에는 개인 공부 시간을 가졌는데 최적화 관련해서 배칭과 드로우콜 부분을 공부하게 되었다. CPU 병목일 때 드로우콜을 낮추기 위해 static batching, Dynamic Batching, GPU Instancing을 고려해봐야겠다는 생각이 들었다.
내일도 최적화 부분을 좀 더 공부하지 않을까 싶다. 내일도 파이팅!
'스파르타 Unity 1기' 카테고리의 다른 글
내일배움캠프 30일차 TIL - 낮과 밤 구현 해석, 1인칭 회전 (1) | 2023.09.18 |
---|---|
내일배움캠프 29일차 TIL - Quaternion과 벡터의 곱셈, LayerMask, 연산자 우선순위 (0) | 2023.09.15 |
내일배움캠프 27일차 TIL - CustomEditor (0) | 2023.09.13 |
내일배움캠프 26일차 TIL - EditorWindow와 CustomEditor (0) | 2023.09.12 |
내일배움캠프 25일차 TIL - 사운드 매니저 (0) | 2023.09.11 |