반응형
안녕하세요 백삼개일의 지프입니다. 오늘부터 Unity DOTS에 대해서 공부를 해보려고 합니다.
매일 매일의 공부 기록을 이곳에 남겨보려 합니다. DOTS 공부를 시작하시려는 분들에게 조금이나마 도움이 된다면 좋겠네요.
1. 개념정리 및 용어 정리 (Unity DOTS, ECS, DOP)
- Unity DOTS ( Data Oriented Technology Stack)?
Unity DOTS를 이해하기 위해선 우선 DOP의 개념을 알아야 합니다. 또한 DOP를 알기 위해선 우선 지금까지 사용해 오던 OOP라는 개념도 중요합니다. OOP (Object Oriented Design Programing 객체지향프로그래밍) 라는 단어인데, 지금까지 유니티에서는 프로그래밍을 객체들이 중심이 되어서 코드가 동작하는 방식으로 프로그래밍 하는 방식으로 되어있었습니다. 플레이어라는 객체 속에 플레이어 컨트롤러, 플레이어 인벤토리, 플레이어 스테이트 등 플레이어에 필요한 요소들이 부착되어 하나의 플레이어라는 오브젝트를 구성하는 프로그래밍 방식입니다. 다만 이러한 OOP 프로그래밍은 프로그램의 크기가 커지거나 그 시간이 지나면서 구조가 점점 복잡해지고 개선이 어려워진다는 단점이 있었습니다. 또한 CPU를 최대로 활용하지 못한다는 문제가 있습니다. Ram의 성능향상은 한계점에 다다르고 있는데, 이에 대하여 CPU는 쿼드 코어와 같이 여러개의 CPU를 동시에 활용하는 방식으로 변화함에 따라서 CPU의 성능을 100% 활용하기 위해서는 다른 프로그래밍 방식이 필요하게 되었습니다.이에 대응하여 나온것이 DOP (Data Oriented Programing) 라는 개념입니다. - DOTS를 꼭 사용해야해?
DOTS를 반드시 채택해야 하는것은 당연히 아닙니다. 가장 큰 단점으로는 Unity의 기존 개발 방식과 다른 패러다임을 제공하기 때문에, 이를 익히고 적용하는 데 시간이 걸릴 수 있다는 점입니다. 기존의 MonoBehaviour 기반 스크립트와는 다른 개념 및 구조를 사용하므로 새로운 방식에 적응하는 것이 어려울 수 있습니다. 다만, 앞으로의 프로그래밍은 DOTS를 활용한 방식으로 변화될 수 있으므로, 해당 방식에 대한 프로그래밍도 익혀두는 것은 중요하다고 생각됩니다. - ECS란?
Entity Component System의 약자로서, Entity는 식별을 위한 Index의 역할을, Component는 우리가 사용할 변수인 Data의 역할을, System은 해당 데이터의 처리를 위한 Behaviour의 역할을 담당합니다. 앞서서 소개한 DOTS는 이러한 ECS를 기반으로 프로그래밍 되어, 데이터 중심의 접근 방식을 채택하고 있고, 이로 인하여 캐시의 활용을 좀더 높일 수 있어 성능 향상을 기대할 수 있습니다. 또한 ECS방식의 코드는 객체지향프로그래밍에서 보다 복잡도를 낮출 수 있는 병렬적 구조로 프로그래밍 가능하다는 장점도 가지고 있습니다.
2. 주요논점
- ECS에서 메모리모델 ( SparseSet vs Archetype )
ECS에서는 메모리를 병렬화하여 데이터를 관리하는 방식을 취하는데, 이때 데이터를 모아오는 메모리모델에 대하여 알아두어야 합니다. 대표적으로 알려진 메모리모델은 Sparse Set방식과 Archetype방식이 있습니다. SparseSet은 Structure에 따라서 배열을 두고 관리하는 방식이며, Archetype의 경우 Structure들의 조합이 같은 데이터들을 패킹하여 관리하는 방식입니다. 방식에 따라서 다른 연산에 대하여 다른 성능을 보이게 되는데, 예를들어 Archetype의 경우 하나의 Structure의 변경이 생기는 경우에 그 조합방식이 변경되므로 다른 패킹으로의 복사가 이뤄지며, 이때 모든 Structure가 복사가 이뤄지며 성능의 문제가 발생합니다. 다만, 특정한 Structure조합을 갖는 구성요소들을 검색하는 경우에는 Archetype은 연산이 필요없이 이미 정렬되어있어서 성능상 우위를 갖을 수 있습니다. 이러한 특징을 알아두시는 것이 중요합니다.
두 모델의 차이를 확실히 알고싶다면 https://habr.com/en/post/651921/에 가시면 자세히 보실 수 있습니다. - Entity 만드는 방법
아래의 예시와 같이 Entity를 만들어주고 그 안에 스트럭쳐들을 달아주면 됩니다.
const auto player_paddle = m_registry.create();
m_registry.emplace<Sprite>(player_paddle, ~~~);
m_registry.emplace<Position>(player_paddle, ~~~);
m_registry.emplace<Player>(player_paddle, ~~~);
const auto AI_paddle = m_registry.create();
m_registry.emplace<Sprite>(AI_paddle, ~~~);
m_registry.emplace<Position>(AI_paddle, ~~~);
m_registry.emplace<AI>(AI_paddle, ~~~);
- Component 만들기
Data역시 내가 원하는 스트럭쳐들이 어떤 데이터를 담고 있는지를 정의해 주면 됩니다.
Struct Sprite
{
int m_width;
int m_height;
};
Struct Position
{
double m_x;
double m_y;
};
Struct Player
{
enum class MoveDirection : short
{
STOPPED;
UP;
DOWN;
}
};
- System 만들기
게임은 전에 만들어둔 엔티티들을 순회하면서, 우리가 원하는 구조의 엔티티들을 찾아서 연산을 해주는 방식입니다.
게임의 코드를 보면 전반적으로 게임이 어떻게 진행되는지 한눈에 볼 수 있습니다. 해당 게임은 각 엔티티들의 위치를 조절해주는 무브 시스템을 지나, 변화된 위치에 맞게 ai시스템이 돌고, 마지막으로 충돌처리 시스템이 도는 방식으로 구현되어 있다는 것이 한눈에 들어옵니다.
void Game::update(const double time)
{
m_move_system.update(time, m_registry);
m_ai_system.update(time, m_registry);
m_collision_system.update(time, m_collideables);
}
void MoveSystem::update(const double time, entt::registry& registry)
{
auto player_view = registry.view<Player, Position>();
player_view.each([&](auto& plr, auto& pos) {
plr.m_movement = m_player_movement;
if(plr.m_movement == Player::MoveDirection::UP)
{
pos.m_y -= 0.15 * time;
}
//// 생략 ///
});
아직 Unity DOTS의 개념설명은 시작하지 못했지만 오늘은 DOTS에서 중요한 ECS라는 개념을 공부를 해보았습니다.
OOP에서는 객체가 중심이 되어서 오브젝트 안에 MonoBehaviour를 통해서 오브젝트의 데이터가 업데이트를 통해서 그 안의 로직에 따라서 데이터를 변경시키고 변경된 데이터에 따라 렌더링되어서 게임이 진행되었다면, DOTS에서는 오브젝트들은 Entity라는 ID로서만 존재할 뿐 그 데이터들의 움직임을 정의해주는 코드들은 system으로 구성되어 모든 Entity들을 모아서 움직임을 계산해주는 방식으로 변화된 느낌입니다. DOTS관련 공부자료들을 열심히 찾아보는 중인데 어디서부터 해야하는지 조금은 어지럽네요. 다음에는 실제로 UnityDOTS를 이용해서 공부를 하는 내용으로 찾아뵐 수 있었으면 좋겟네요.
참고했던 사이트 <https://www.youtube.com/watch?v=7UphiG8UtTg&t=301s>
반응형
'Unity Study > UNITY DOTS' 카테고리의 다른 글
UnityDOTS 공부하기 2일차 (1) | 2024.02.04 |
---|