본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 25. 14:33

공간 기억 구축 파트 3: 위치 기반 기억을 위한 AR 앱을 만들며 배운 점

요약

위치 기반 AR 앱 개발 과정에서 겪은 GPS 좌표계와 ARKit 좌표계 간의 불일치 및 트래킹 드리프트 문제를 다룹니다. 실제 환경에서 발생하는 기술적 한계와 이를 극복하기 위한 좌표 변환의 필요성을 설명합니다.

핵심 포인트

  • GPS의 낮은 정확도와 도시 환경의 '어반 캐년' 효과로 인한 오차 발생
  • GPS(위도/경도)와 ARKit(로컬 좌표계) 간의 좌표계 변환 필수
  • 이동 시 발생하는 AR 트래킹 드리프트 현상과 그로 인한 위치 이탈 문제

공간 기억 구축 파트 3: 위치 기반 기억을 위한 AR 앱을 만들며 배운 점

솔직히 말씀드릴게요 — 이 프로젝트를 시작했을 때 AR (증강 현실) 개발이 실제로 얼마나 어려운지 전혀 몰랐습니다.

몇 달 전 산을 걷다가 멋진 아이디어가 떠올랐습니다: "만약 실제 세계의 좌표에 디지털 메모와 사진을 고정할 수 있다면 어떨까? 물리적 세계를 위한 Pinterest처럼 말이죠. 오직 그 장소에 실제로 서 있을 때만 그 기억을 잠금 해제할 수 있는 겁니다."

머릿속에서는 그 아이디어가 정말 멋지게 들렸습니다. 이미 PostGIS와 Redis GEO를 사용하여 백엔드(backend)를 구축해 두었기에 (이전 포스트에서 관련 내용을 읽어보실 수 있습니다), 저는 "좋아, 프론트엔드 AR 부분은 그렇게 어렵지 않겠지? 지금은 2026년이고, 모든 API가 다 갖춰져 있잖아."라고 생각했습니다.

네. 그 부분에 대해서 말이죠. 저는 혹독한 경험을 통해 배웠습니다.

현실 점검: AR은 (아직) 마법이 아니다

그래서 옵션들을 살펴보기 시작했습니다. 저는 주로 iOS 사용자이기 때문에 ARKit이 당연한 선택이었습니다. 사람들이 놀라운 AR 경험을 구축하고 있다는 좋은 이야기를 많이 들었습니다. 하지만 실제로 코딩을 시작했을 때...

솔직히 말해서, 첫 일주일은 그저 끊임없는 당혹감(WTF)의 연속이었습니다.

제가 기대했던 것과 실제로 겪은 것을 보여드리겠습니다.

기대했던 것:

  • GPS 좌표를 입력한다 → 해당 좌표에 콘텐츠를 보여준다 → 완료.
  • ARKit이 트래킹 (tracking)의 힘든 작업을 처리해 준다.

실제로 일어난 일:

  • 탁 트인 지역에서 GPS는 오직 5~10미터 정도의 정확도만 가짐
  • 도시에서는 GPS 정확도가 20~50미터로 떨어짐 (높은 건물로 인한 "어반 캐년 (urban canyon)" 효과 때문)
  • 1분 이상 가만히 서 있으면 AR 트래킹이 드리프트 (drift) 현상을 일으킴
  • 특징이 없는 영역(탁 트인 들판, 민무늬 벽)에서는 월드 트래킹 (world tracking)이 잘 작동하지 않음
  • 기기마다 성능 차이가 매우 심함

오, 그리고 이건 시작에 불과합니다.

첫 번째 큰 문제: GPS vs AR 좌표계

그 어떤 튜토리얼도 명확하게 설명해주지 않는 사실이 하나 있습니다. GPS는 구체(sphere) 위의 위도/경도를 제공합니다. 반면 ARKit은 세션을 시작한 위치를 기준으로 하는 좌표계(coordinate system)를 제공합니다. 이 둘은 자동으로 서로 통신하지 않습니다.

사용자가 직접 이 둘 사이의 변환을 수행해야 합니다.

제가 결국 구현하게 된 코드를 보여드리겠습니다 (원리를 이해하고 나면 사실 그렇게 나쁘지 않습니다):

import ARKit
import CoreLocation

...

이것이 핵심적인 변환 과정입니다. 충분히 간단해 보이죠? 하지만 여기서부터 까다로워집니다...

두 번째 큰 문제: 드리프트(Drift), 도처에 깔린 드리프트

ARKit의 월드 트래킹(world tracking)은 매우 뛰어납니다. 방 안에 있는 주변 사물들에 대해서는 말이죠. 하지만 50미터 떨어진 곳에 무언가를 배치하고 그곳까지 걸어가는 상황이라면, 드리프트(drift)는 거대한 문제가 됩니다.

발생하는 현상은 다음과 같습니다:

  1. 지점 A에서 시작하여, GPS 고정(fix)을 얻고 AR 세션을 시작합니다.
  2. 지점 B까지 50미터를 걸어갑니다.
  3. 그 과정에서 ARKit의 트래킹이 2~5미터 정도 드리프트(drift)됩니다.
  4. 고정된 기억(pinned memory)은 원래 있어야 할 위치가 아닌 공중에 둥둥 떠 있게 됩니다.

저는 이 문제를 해결하기 위해 다양한 솔루션을 시도하며 약 2주를 보냈습니다. 여러분의 시간을 아껴드리기 위해 정리해 드립니다:

효과가 없었던 방법들

1. 단순히 ARKit에만 의존하기

  • 50미터 이상 이동하면 드리프트(drift)가 너무 심해집니다. 핀(pin)이 예상했던 위치에 절대 있지 않습니다.

2. 10미터마다 트래킹 리셋하기

  • 월드 앵커(world anchor)의 연속성이 깨지며, 리셋할 때마다 핀들이 제멋대로 점프합니다. 사용자에게 매우 혼란스러운 경험을 줍니다.

3. 이미지 특징점(image features)을 사용하여 재지역화(relocalize)하기

  • 고유한 특징점(동상, 독특한 건물 등)이 있다면 매우 잘 작동합니다. 하지만 탁 트인 들판이나 특징 없는 교외 지역에서는 완전히 실패합니다. 일반적인 용도로 사용하기에는 신뢰도가 낮습니다.

어느 정도 작동하는 방법 (사이드 프로젝트 수준에서는 충분함)

저는 결국 완벽하지는 않지만 80%의 케이스에서 작동하는 하이브리드 접근 방식을 선택했습니다:

func updatePosesIfNeeded(currentLocation: CLLocation, anchors: [ARAnchor]) {
    // GPS 정확도가 높으면 (< 10m), AR 위치를 보정합니다
    if currentLocation.horizontalAccuracy < 10 {
...

핵심 통찰: GPS는 전역적(global) 규모에서 더 정확하고, AR은 지역적(locally) 규모에서 더 정확합니다. GPS 정확도에 따라 이 둘을 혼합하세요. GPS가 양호한 고정(fix)을 얻으면, 이를 사용하여 모든 것을 다시 정렬(alignment)하도록 유도합니다.

완벽하지는 않지만, 취미 프로젝트로서는 충분합니다. 어차피 사용자들도 AR에서는 어느 정도의 불안정함(wonkiness)을 예상하니까요.

세 번째 큰 문제: 사용자 경험(UX)은 기술보다 실제로 더 어렵다

좋습니다, 좌표를 변환하고 드리프트(drift)를 어느 정도 제어할 수 있게 되었습니다. 이제 무엇을 해야 할까요?

사용자가 실제로 핀을 어떻게 *배치(place)*할까요?

저는 어느 정도 작동하는 방식을 찾기 전까지 세 가지의 서로 다른 UX 디자인을 거쳤습니다.

시도 1: "원하는 곳을 그냥 탭하세요"

사람들은 화면을 탭했지만, 그것이 어느 정도의 거리에 해당하는지 전혀 알 수 없었습니다. 탭한 위치가 2미터 떨어져 있거나 200미터 떨어져 있는 식이었죠. 사용자에게는 완전히 추측에 의존하는 일이었습니다. 한 명을 대상으로 한 사용자 테스트 이후 이 방식은 포기했습니다.

시도 2: "현재 위치에 핀을 꽂으세요"

기술적으로는 더 쉽지만, 그러면 재미가 없지 않을까요? 당신이 바라보고 있는 경치 좋은 전망대 너머 계곡에 핀을 꽂을 수 없습니다. "실제로 있는 곳에 핀을 꽂는다"는 개념 자체를 무색하게 만듭니다.

시도 3 (현재): 슬라이더 거리 + 탭 방향

사용자가 핀을 배치하고 싶은 방향을 탭한 다음, 슬라이더를 드래그하여 거리를 설정합니다. 드래그하는 동안 핀의 위치를 미리 보기(preview)로 보여줍니다. 위치가 적절해 보이면 배치합니다.

// 사용자가 화면을 탭했을 때
func handleTap(_ gesture: UITapGestureRecognizer) {
    let location = gesture.location(in: sceneView)
...

이것이 제가 출시(ship)한 방식입니다. 여전히 완벽하지는 않지만, 사용자들이 10~15초 정도 조작하면 실제로 원하는 위치에 핀을 놓을 수 있습니다. 제 기준에서는 성공입니다.

개인정보 보호: 놀라울 정도로 쉬운 승리

시작할 때 가졌던 가장 큰 우려 중 하나는 개인정보 보호(privacy)였습니다. 사람들이 개인적인 기억을 특정 위치에 핀으로 고정한다면, 그 모든 사진을 제 서버에 저장하고 싶은 걸까요?

제가 최종적으로 선택한 방식이며, 완벽하게 작동하고 있는 방법은 다음과 같습니다:

모든 사진은 사용자의 휴대폰에서 Cloudflare R2로 직접 전송됩니다. 제 백엔드(backend)는 사진에 절대 손을 대지 않습니다.

흐름은 다음과 같습니다:

  1. 사용자가 앱에서 사진을 촬영합니다.
  2. 앱이 제 백엔드(backend)에 사전 서명된 PUT URL (pre-signed PUT URL)을 요청합니다.
  3. 앱이 R2로 직접 업로드합니다.
  4. 백엔드는 이미지 바이트(image bytes)를 전혀 보지 못합니다.

Go 백엔드 코드 스니펫 (Code snippet):

func (s *Server) createPreSignedUploadHandler(w http.ResponseWriter, r *http.Request) error {
    userID := getCurrentUserID(r)
    objectKey := fmt.Sprintf("%s/%s.jpg", userID, uuid.New().String())
...

이 방식은 세 가지 이유로 매우 훌륭합니다:

  1. 데이터 전송 비용(egress fees) 제로 (Cloudflare R2 덕분입니다!)
  2. 사용자 이미지를 저장하거나 처리할 필요가 없음 → 책임 소지가 줄어들고 인프라 부담이 감소합니다.
  3. 설계에 의한 개인정보 보호 (Privacy by design) — 제 서버에 문제가 생기더라도, 제가 이미지를 보유하고 있지 않기 때문에 여러분의 사진은 여전히 비공개로 유지됩니다.

장점 (Pros):

  • 매우 저렴함 (R2 무료 티어에서 10GB를 무료로 제공하며, 제 스토리지 비용은 보통 월 $0.50 미만입니다)
  • 무한한 확장성 (Scales infinitely) — 아무것도 변경하지 않고도 10명의 사용자나 10,000명의 사용자를 처리할 수 있습니다
  • 이미지 처리나 남용 보고(abuse reports)에 대해 고민할 필요가 없음 (물론, 필요한 경우 DMCA에 대응해야 하긴 하지만, 이는 당연한 일입니다)

단점 (Cons):

  • 서버에서의 자동 이미지 압축(image compression) 불가 — 클라이언트(client)에서 수행해야 합니다
  • 연결 상태가 좋지 않은 사용자는 업로드 도중 실패하여 재시도해야 할 수 있습니다
  • 서버에서 썸네일(thumbnails)을 생성할 수 없으므로, 클라이언트에서도 이를 수행해야 합니다

전반적으로, 사이드 프로젝트(side project)로서 충분히 가치가 있습니다.

솔직하게 말해서: 이 접근 방식 전체의 장단점

이 작업을 약 3개월 동안 진행해 왔으며, 몇 가지 생각이 정리되었습니다.

잘 작동하는 부분 ✅

  1. 아이디어는 여전히 멋집니다 — 실제로 작동할 때면 정말 마법 같습니다. 결혼식 사진을 찍었던 장소에 서서 앱을 열면, 당신이 서 있던 바로 그 자리에 원래의 사진이 떠 있습니다. 전율이 느껴질 정도입니다.

  2. 백엔드 아키텍처 (Backend architecture)는 견고합니다 — PostGIS + Redis GEO + R2 조합은 단 한 번도 저를 실망시키지 않았습니다. 모든 쿼리는 50ms 미만이며, 비용은 무시할 수 있는 수준입니다. 그 부분은 사실상 완료되었습니다.

  3. 개인정보 보호 모델이 잘 작동합니다 — 사용자들이 제가 그들의 사진을 수집하지 않는다는 점을 높게 평가하는 것 같습니다. 직접 업로드 방식은 아주 잘 작동합니다.

  4. ARKit이 80%를 무료로 해결해 줍니다 — 트래킹 (Tracking) 기능을 직접 구축할 필요가 없습니다. Apple이 어려운 작업을 이미 다 해두었습니다. 그 부분은 꽤 잘 작동합니다.

여전히 문제가 되는 부분 ❌

  1. GPS 정확도가 여전히 가장 큰 문제입니다 — 고층 빌딩이 많은 도시에서는 20m 이상 오차가 발생할 수 있습니다. 당신의 핀 (Pin)이 엉뚱한 건물에 찍히게 됩니다. 스마트폰만으로는 이 문제를 해결하는 데 한계가 있습니다.

  2. AR 드리프트 (AR drift)는 항상 따라다닙니다 — 걷는 시간이 길어질수록 상태가 악화됩니다. 저의 하이브리드 블렌딩 (Hybrid blending) 방식이 도움이 되긴 하지만, 문제를 완전히 해결하지는 못합니다.

  3. 배터리 수명이 최악입니다 — ARKit + GPS + 화면 상시 켜짐 = 스마트폰이 2~3시간 만에 방전됩니다. 하루 종일 하이킹을 하며 이 앱을 사용하는 것은 불가능합니다. 현실적으로 실행 가능하지 않습니다.

  4. 콜드 스타트 (Cold start)가 가혹합니다 — 흥미로운 핀이 충분히 쌓이기 전까지는 아무도 사용하지 않지만, 사용자가 생기기 전까지는 아무도 흥미로운 것을 핀으로 찍지 않습니다. 전형적인 '닭과 달걀' 문제입니다. 사이드 프로젝트이다 보니 수천 개의 핀을 직접 심어둘 자원도 부족합니다.

  5. Android 지원은 할 일 목록 (TODO list)에 있지만... — ARCore는 유사하지만 다릅니다. 코드를 대량으로 다시 작성해야 합니다. 실제적인 수요가 없다면 구현할 계획은 없습니다.

누가 이것을 시도해봐야 할까요?

  • 특정 도시나 지역을 위한 관광 앱을 구축하는 경우 — GPS 정확도가 충분하고, 모든 핀을 미리 배치할 수 있으며, 사용자가 멀리 걷지 않는다면(따라서 드리프트 (drift)가 최소화됨) 매우 잘 작동합니다.
  • 실내 위치 기반 경험 — 실내에서는 GPS가 작동하지 않지만, 블루투스 비콘 (Bluetooth beacons)을 사용할 수 있습니다. 공간을 직접 제어할 수 있다면 이는 놀라운 경험이 됩니다.
  • 실험적 / 예술 프로젝트 — 멋진 컨셉이며, 아이디어가 흥미롭다면 사람들은 다소 거친 부분들을 너그럽게 이해해 줍니다.

누가 피해야 할까요?

  • 모든 곳에서 1미터 단위의 정확도가 필요한 경우 — 고생하게 될 것입니다. 더 나은 AR/VR 하드웨어가 나올 때까지 3~5년 정도 더 기다리세요.
  • Google Maps를 대체하고 싶은 경우 — 시도조차 하지 마세요. Google은 아주 오랫동안 이 분야에 매진해 왔으며, 훨씬 더 많은 데이터를 보유하고 있습니다.
  • 첫 시도에 완벽하게 작동하기를 기대하는 경우 — AR 위치 기반 기술은 여전히 서부 개척 시대와 같습니다. 예외 케이스 (edge cases)를 디버깅하는 데 몇 주를 보낼 준비를 하세요.

3개월 후의 놀라운 깨달음

솔직히 말할까요? 저는 AR이 가장 어려운 부분일 것이라고 생각하며 이 프로젝트를 시작했습니다. 하지만 알고 보니 AR은 쉬운 부분이었습니다.

진짜 어려운 부분은 모두 단순해 보이는 것들이었습니다:

  • 서로 다른 두 시스템으로부터 얻은 좌표를 일치시키는 것
  • 일반 사람들에게 납득이 가는 UX (사용자 경험) 디자인
  • 다양한 환경에서 휴대폰 GPS의 한계를 다루는 것
  • 실제로 사용 가능한 수준의 배터리 수명

그럼에도 불구하고 — 여전히 즐거운 프로젝트입니다. 제대로 작동할 때면 마치 마법처럼 느껴집니다. 그리고 그것이 우리가 사이드 프로젝트를 하는 이유 아니겠습니까? 모든 것이 수십억 달러 규모의 스타트업이 될 필요는 없습니다. 때로는 그저 세상에서 구현되는 것을 보고 싶은 아이디어가 있을 뿐입니다.

코드를 확인하고 싶다면 (오픈 소스입니다), 여기서 찾을 수 있습니다: https://github.com/kevinten10/spatial-memory. 백엔드 Go 코드, iOS Swift 코드 등 모든 것이 준비되어 있습니다.

여러분에게 드리는 질문

AR 위치 기반 앱을 구축해 본 적이 있으신가요? 무엇이 가장 놀라웠나요? 저보다 드리프트 (drift) 문제를 더 잘 해결하셨나요? 여러분의 경험을 댓글로 들려주세요. 저도 여전히 이 분야를 배우는 중입니다.

혹은 "미래의 나를 위해 여기에 메모를 남겨둘 수 있다면 좋을 텐데"라고 생각했던 순간이 있었다면, 이것이 여러분이 사용할 만한 서비스처럼 들리시나요? 아래에 댓글을 남겨주세요.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0