Gps와 Rendering 사이의 간극 고찰

모기·2025년 9월 12일

현재 구현 중인 MR 기반 어플이다.
화면에 보이는 메시지나 큐브들은 테스트를 위한 목업데이터이다.
보면 알겠지만, 둘 다 위치 기반의 서비스라 데이터의 선택 방식에 초점을 맞추려 한다.

데이터와 구역

현재 어느정도 구현된, 그리고 구현할 상황은 다음과 같다.

        C
 ---------------
|       B       |
|     -----     |
|    |  A  |    |
|     -----     |
|               |
 ---------------

위 그림에서는 사각형이지만, 정확하게는 원의 형태로 되어있다.

  • A 구역
    사용자가 중심에 있으며 반지름이 20m 정도로 메시지를 실제로 렌더링하는 구역이다.
  • B 구역
    데이터가 메시지 리스트에 캐싱돼 있으나 렌더링은 되지 않았다.
  • C 구역
    데이터가 서버에 있다.

구현 사항

  1. 각 메시지는 고정된 GPS 좌표가 있다.
  2. A구역에서 렌더링된 메시지들은 A구역을 벗어나지 않는 이상 GPS가 업데이트 되더라도 A구역에서 리렌더링 되지 않는다.
  3. GPS는 일정 시간마다 업데이트 된다.
  4. C에 있던 데이터들은 B구역 안으로 들어오면 메시지 리스트에 캐싱되고, B구역에 있던 데이터들은 A구역 안으로 들어오면 메시지가 렌더링 된다.

고민해봤는데, 위 내용은 필수적으로 들어가야하는 사항이다.

챌린지 지점

좌표가 일정 수준 변경되면 다음과 같은 일들이 발생해야한다.

  • C구역에서 B구역으로 들어온 데이터들은 서버에서 캐시 리스트에 데이터를 중복없이 효율적으로 제공한다.
  • B구역에서 C구역으로 나간 데이터들은 캐시 리스트에서 제거한다.
  • A구역에서 벗어난 데이터는 오브젝트를 파괴하고, 새롭게 A구역으로 들어온 데이터의 오브젝트는 렌더링 시킨다.
  • 리스트를 새롭게 교체하면 안된다. 모든 오브젝트들이 리렌더링되므로 기존의 위치에 오브젝트가 생성되지 않을 수도 있다.

원형 구역 방식

사용자 근처에 메시지를 렌더링 혹은 캐싱하는 구역이 원형(초록색)이라고 할 때 사용자가 앞으로 가면 위와 같이 변할 것이다.

빨간색 부분은 새로 렌더링/캐싱해야하는 부분이고, 초록색 부분은 제거해야하는 부분이다. 그리고 주황색은 데이터와 오브젝트를 유지해야하는 구간이다.

다만 위와 같은 경우는 불러오거나 삭제할 때 한 번에 하지 못하고 주황색 구역의 데이터와 비교가 필연적이게 된다.

따라서
1. 현재 위치 전송
2. 현재 구역에 해당하는 데이터 Get
3. 데이터 비교후 삭제 및 추가

같은 절차가 필요한데,
3번 같은 경우는 데이터의 수에 따라 필요한 시간이 선형 시간으로 증가한다.

격자 구역 방식

위 방식을 활용하면 겹치는 데이터를 검증해야할 필요가 없다. 왜냐하면 사용자의 위치에 따라서 받아와야하는 데이터 셋이 정해져있기 때문이다.

원형 구역 방식에서는 데이터 하나하나에 대해서 신경을 써야했다면
격자 구역 방식에서는 데이터 셋을 한 번에 처리하면 되기 때문이다.

예를 들어 위와 같은 위치(3,3)에서 (4,3)으로 이동한다고 하면
(1,1)부터 (1,5) 데이터와 (6,1)부터 (6,5) 데이터까지 신경쓰면 된다.

다만 사용자가 어디서 왔는지,
그리고 데이터 셋을 어떻게 관리할 지가 중요할 것 같다.

구현

격자 형태로 관리해야할 예정이므로 기준점이 필요하다.

처음에는 간단하게 생각했다.
격자간 거리를 3이라고 하면

float 형태의 수를 float 3으로 나누고 int로 만든뒤 다시 3을 곱하면 되겠구나

라고 생각했다.

예를 들어 저 위의 사용자 위치가 (17, 20)이라고 하면
17/3 = 5.6666 이고
int로 형변환하면 5가 된다.
여기에 다시 3을 곱하면 5*3 = 15 즉 15의 배수가 된다.

사용자의 위치가 (17, 20)이라고 하면 격자 기준점은 (15, 18)이 될 것이다.
이런 식으로 그리드를 관리하려고 했으나,

저 그리드는 사실 '구'의 그리드이다.

말이 안되는 적용방식이다.
따라서 진짜 딱 구든 평면이든 상관없이 격자점을 구하는 방법을 고민했고

    private Vector2 calculateBenchMark(Vector2 pos)
    {
        Vector2 benchMark;
        benchMark.x = Mathf.Floor(pos.x * 100000f / messageGetRadius) * messageGetRadian / 100000f;
        benchMark.y = Mathf.Floor(pos.y * 100000f / messageGetRadius) * messageGetRadian / 100000f;
        return benchMark;
    }

위와 같이 생각하게 되었다.
Radius는 추후 수정했지만
각도라고 생각하면 될 것 같다.

사실 float이나 double의 특성을 생각하면
이게 과연 괜찮은 방법인가... 싶기도 하다.

profile
안녕

0개의 댓글