Unity

유니티 드로우콜

우대비 2025. 5. 14. 20:34
반응형
Unity Draw Call

Unity Draw Call 최적화 가이드

1. Draw Call이란?

Draw Call은 GPU에게 "이 물체를 이렇게 그려라"라고 명령하는 작업입니다. 각 Draw Call은 CPU와 GPU 사이의 통신을 필요로 하며, 이는 성능에 직접적인 영향을 미칩니다.

2. Draw Call의 작동 방식

2.1 기본 개념

// 예시: 각각의 머티리얼은 별도의 Draw Call을 발생시킴
public class DrawCallExample : MonoBehaviour
{
    [SerializeField] private Material material1;
    [SerializeField] private Material material2;
    
    private void Start()
    {
        // 각각 다른 머티리얼을 사용하는 오브젝트는
        // 별도의 Draw Call이 발생
        GameObject obj1 = new GameObject("Object1");
        obj1.GetComponent().material = material1;
        
        GameObject obj2 = new GameObject("Object2");
        obj2.GetComponent().material = material2;
    }
}

2.2 Draw Call 발생 조건

  • 다른 머티리얼 사용
  • 다른 셰이더 사용
  • 다른 렌더 큐 사용
  • 다른 렌더 타겟 사용

3. Draw Call 최적화 기법

3.1 Static Batching

public class StaticBatchingExample : MonoBehaviour
{
    private void Start()
    {
        // 정적 배칭을 위한 설정
        StaticBatchingUtility.Combine(gameObject);
    }
}
특징:
  • 정적 오브젝트들을 하나의 큰 메시로 결합
  • CPU 메모리 사용량 증가
  • Draw Call 감소

3.2 Dynamic Batching

public class DynamicBatchingExample : MonoBehaviour
{
    private void Start()
    {
        // 동적 배칭을 위한 설정
        // Project Settings > Player > Other Settings > Dynamic Batching 활성화
    }
}
특징:
  • 작은 메시들을 자동으로 배칭
  • CPU 오버헤드 발생
  • 제한된 버텍스 수 (900개 이하)

3.3 GPU Instancing

public class GPUInstancingExample : MonoBehaviour
{
    [SerializeField] private Material instancedMaterial;
    
    private void Start()
    {
        // GPU 인스턴싱 활성화
        instancedMaterial.enableInstancing = true;
    }
}
특징:
  • 동일한 메시와 머티리얼을 사용하는 오브젝트들을 한 번에 렌더링
  • GPU 메모리 사용량 증가
  • 높은 성능 향상

4. 머티리얼 최적화

4.1 머티리얼 공유

public class MaterialSharingExample : MonoBehaviour
{
    [SerializeField] private Material sharedMaterial;
    
    private void Start()
    {
        // 여러 오브젝트가 동일한 머티리얼 공유
        GameObject[] objects = new GameObject[10];
        for (int i = 0; i < objects.Length; i++)
        {
            objects[i] = new GameObject($"Object_{i}");
            objects[i].GetComponent().material = sharedMaterial;
        }
    }
}

4.2 머티리얼 프로퍼티 블록

public class MaterialPropertyBlockExample : MonoBehaviour
{
    private MaterialPropertyBlock propertyBlock;
    private Renderer renderer;
    
    private void Start()
    {
        propertyBlock = new MaterialPropertyBlock();
        renderer = GetComponent();
        
        // 개별 오브젝트의 머티리얼 프로퍼티 변경
        propertyBlock.SetColor("_Color", Color.red);
        renderer.SetPropertyBlock(propertyBlock);
    }
}

5. 셰이더 최적화

5.1 셰이더 변형 최소화

public class ShaderVariantExample : MonoBehaviour
{
    [SerializeField] private Shader shader;
    
    private void Start()
    {
        // 셰이더 키워드 최소화
        Shader.DisableKeyword("_SPECULAR");
        Shader.DisableKeyword("_NORMALMAP");
    }
}

5.2 셰이더 LOD

public class ShaderLODExample : MonoBehaviour
{
    [SerializeField] private Shader shader;
    
    private void Start()
    {
        // 셰이더 LOD 설정
        shader.maximumLOD = 100;
    }
}

6. 렌더링 최적화

6.1 오브젝트 풀링

public class ObjectPoolingExample : MonoBehaviour
{
    [SerializeField] private GameObject prefab;
    private List pool = new List();
    
    private void Start()
    {
        // 오브젝트 풀 생성
        for (int i = 0; i < 10; i++)
        {
            var obj = Instantiate(prefab);
            obj.SetActive(false);
            pool.Add(obj);
        }
    }
    
    private GameObject GetFromPool()
    {
        // 풀에서 오브젝트 재사용
        foreach (var obj in pool)
        {
            if (!obj.activeSelf)
            {
                obj.SetActive(true);
                return obj;
            }
        }
        return null;
    }
}

6.2 LOD (Level of Detail)

public class LODExample : MonoBehaviour
{
    [SerializeField] private LODGroup lodGroup;
    
    private void Start()
    {
        // LOD 설정
        LOD[] lods = new LOD[3];
        lods[0] = new LOD(0.6f, new Renderer[] { GetComponent() });
        lods[1] = new LOD(0.3f, new Renderer[] { GetComponent() });
        lods[2] = new LOD(0.1f, new Renderer[] { GetComponent() });
        
        lodGroup.SetLODs(lods);
    }
}

7. 모니터링과 디버깅

7.1 Draw Call 확인

public class DrawCallMonitoring : MonoBehaviour
{
    private void OnGUI()
    {
        // 현재 Draw Call 수 표시
        GUI.Label(new Rect(10, 10, 200, 20), 
            $"Draw Calls: {UnityStats.drawCalls}");
    }
}

7.2 프레임 디버거 사용

  • Window > Analysis > Frame Debugger
  • Draw Call 시각화
  • 배칭 상태 확인

8. 결론

Draw Call 최적화는 게임 성능 향상에 중요한 요소입니다. 적절한 배칭 전략, 머티리얼 최적화, 셰이더 관리 등을 통해 Draw Call을 최소화하고 게임의 성능을 향상시킬 수 있습니다.

9. 추가 팁

  1. 텍스처 아틀라스 사용
    • 여러 텍스처를 하나로 결합
    • 머티리얼 수 감소
  2. 오브젝트 컬링
    • 화면에 보이지 않는 오브젝트 렌더링 제외
    • Draw Call 감소
  3. 셰이더 복잡도 관리
    • 필요한 기능만 포함
    • 셰이더 변형 최소화
  4. 렌더링 순서 최적화
    • 렌더 큐 적절히 사용
    • 오버드로우 최소화

주의사항: 이러한 최적화 기법들을 적절히 조합하여 사용하면, 게임의 성능을 크게 향상시킬 수 있습니다.

반응형
LIST

'Unity' 카테고리의 다른 글

Unity 렌더링 파이프라인  (0) 2025.05.19
유니티 쿼터니언(Quaternion)  (1) 2025.05.16
유니티 코루틴의 동작원리  (1) 2025.05.12
TIL: Unity 인벤토리 시스템 구현  (2) 2025.05.01
퀘스트 시스템  (2) 2025.04.28