by

(유니티) DOTS 쉽게 이해하기

요즘 유행하는 DOTS(데이터 지향 기술 스택)가 뭔가요? 라고 물어본다면 난 이렇게 (조금 왜곡해서) 최고로 쉬운 비유로 대답함.

“오브젝트 사이의 공통적인 기능을 하나의 전역 기능-하나의 파이프라인으로 떼어놔요. 그다음, 오브젝트에서 데이터만 뽑아 일렬로 늘여놓고선 하나의 파이프에 한번에 밀어넣는 거요. 그러면 IO 속도가 올라감”

OOP에서는 오브젝트 스스로의 완결성을 중요시 하기 때문에, 자기 자신을 스스로 챙겨야 한다. 

100만개의 파티클 오브젝트가 있고, 100만개의 파티클 효과가 오른쪽으로 1칸 이동해야 한다고 가정해 보자.

OOP에서는 오브젝트 스스로가 스스로의 기능을 가진다. 따라서 각각의 파티클들이 내부에 Move() 메서드를 가지고 스스로 1칸 이동한다. 즉, 100만개의 파티클이 독립적으로 각자 Move()를 실행시켜 오른쪽으로 움직인다.

이 방법의 문제점은, 오브젝트는 레퍼런스로 동작하며, 오브젝트 내부는 필드 + 메서드로 이루어지기 때문에,

1. 다루어야할 데이터가 스택에 순서대로 쌓이는게 아니라, 힙에 무작위로 나열됨.
2. 설사, 100만개의 오브젝트를 메모리 상에 일렬로 나열할 수 있다고 해도, 다루어야할 데이터가 연속으로 이어지지 않고, 데이터(필드)와 데이터 사이에 메서드를 위한 공간이 끼어들어가서, 다루어야할 데이터가 일렬로 나열되지 않음.

=> 따라서 프로세싱에는 문제 없어도 IO 속도가 저하됨.

따라서 이 방법의 해결책은, 100만개의 파티클 효과가 각자 총 100만개의 Move() 메서드를 가지게 하는 것이 아니라, 어짜피 공통된 기능이잖아? 단 하나의 전역 Move() 메서드로 때어내고, 100만개의 오브젝트가 그것을 공유하는 것이다.

그렇게, 100만개의 오브젝트는 메서드가 존재하지 않는, 필드만 가지고 있는 엔티티가 된다. 그리고 이것을 클래스가 아닌 구조체로 만들어 힙이 아닌 스택에 일렬로 쌓이게 한다.

그러면 일렬로 나열된 100만개의 데이터를, 하나의 통로(전역 Move 메서드)에 밀어넣는 형식이 되서, IO 속도가 존나 올라가게됨.

그런데 여기서, 100만개의 파티클 엔티티를 위한 특별한 식별자를 부여하지 않는 것도 중요.

각자의 식별자를 따로 구별하지 않고, 파티클 효과를 포함한 게임상 수백만개의 엔티티들을 ‘일단 그냥’ Move() 파이프라인에 죄다 집어넣은 다음, 내부에서 필터링을 통해 효과를 적용할 친구만 걸러낸다. 따라서 데이터를 집어넣는데 있어서, ‘파티클’에 해당하는 데이터만 따로 골라 Move()를 실행할 필요가 없음.

이런식.

파티클, 적, 플레이어 등 수백만개의 엔티티 ===> | Move() : ‘파티클 위치’ 라는 내부 데이터를 가진 엔티티라면 위치 1 이동 |

추상적으로 이 정도 이야기만 납득하면, 본격적으로 DOTS 구현할때 도움뎀.