연구 블로그

잘 돌아가던 렌더러를 갈아엎은 이유

컴퓨터 비전2026.06.09 · 5분 읽기
잘 돌아가던 렌더러를 갈아엎은 이유

손으로 그린 캐릭터를 브라우저에서 실시간으로 움직이는 렌더러는 사실 잘 돌아가고 있었다. 캔버스 2D 위에서 벡터 그래픽 라이브러리가 SVG 경로를 그리고 관절을 따라 변형했다. 데모는 부드러웠고 버그 리포트도 잠잠했다.

그런데도 이 렌더러를 통째로 걷어내기로 했다. 잘 돌아가는 코드를 갈아엎는 건 가장 욕먹기 쉬운 결정이다. 이유는 하나였다. 이 구조로는 더 갈 데가 없었다.

잘 돌아가는데 왜 갈아엎나

구 렌더러는 캔버스 2D 컨텍스트 위에서 동작하는 벡터 그래픽 라이브러리에 묶여 있었다. 평면 그래픽에는 충분했지만 세 가지가 천장이었다.

  • GPU를 적극 활용하기 어렵다. 캔버스 2D는 복잡한 메시 변형을 GPU 파이프라인으로 처리하기에 한계가 있어, 캐릭터 수가 늘거나 변형이 무거워지면 메인 스레드 부담이 커진다.
  • 번들이 무겁다. 라이브러리가 SVG 파서와 기하 연산을 통째로 들고 오는데 실제로 쓰는 건 일부였다.
  • 확장 경로가 막혀 있다. GPU 스키닝, 셰이더 기반 변형 같은 다음 단계를 얹을 길이 없었다.

"지금 안 깨졌다"와 "여기서 더 못 간다"는 다른 문제다. 우리가 풀려던 건 후자였다. 만들려던 다음 단계는 실시간 포즈 렌더링이었다. 웹캠 포즈 추정 결과를 렌더링에 바로 반영하려면 GPU 친화적인 렌더러가 필요했다.

한 번에 갈아엎지 않았다

렌더러 교체의 가장 큰 위험은 교체 도중 아무것도 안 돌아가는 구간이다. 그래서 세 단계로 나눴다. 먼저 렌더러에 묶여 있던 코어 로직(변환 행렬, 본·가중치 포맷)을 라이브러리와 무관한 형태로 떼어내 단위 테스트로 고정했다. 다음으로 새 WebGL 2D 엔진과 SVG를 GPU 메시로 굽는 자산 파이프라인(rig.json + rig.svg)을 옆에서 구축했다. 마지막으로 구 라이브러리를 빌드 설정의 흔적까지 제거하고 앱에 통합했다.

구 렌더 경로와 새 경로는 어댑터 뒤에 두고 하나씩 옮겼다. 코어가 테스트로 고정돼 있으니 렌더러를 바꿔도 결과가 같은지 기계가 검증했고, 베이크된 자산도 CI 검증 스크립트로 삼각분해 실패와 가중치 누락을 빌드 단계에서 잡았다.

라이브러리를 바꾸면 데이터 계약이 바뀐다

새 엔진에 기존 RGBA 정수 색상을 그대로 넘기자 "색상 변환 불가" 예외가 터졌다. 구 라이브러리는 알파가 합쳐진 RGBA 정수를 받았는데, 새 엔진은 RGB와 Alpha를 분리해서 기대했다.

해결은 드로잉 시점에 색상을 분리 변환하는 어댑터를 끼우는 것이었다. 라이브러리를 바꾸면 데이터 표현 규약이 조용히 달라진다는 걸 가장 먼저 가르쳐준 버그였다.

자산 실패도 설계해야 한다

가장 아팠던 건 자산 로딩이었다. SVG 텍스처와 스키닝 지오메트리는 비동기로 로드되는데, 이 중 하나라도 실패하면 렌더 기능 전체가 멈췄다. 새 엔진은 자산 의존이 더 깊어서 구 렌더러보다 이 실패에 취약했다.

그래서 우아하게 실패하도록 다층 방어를 깔았다. 로딩 상태를 상위 컴포넌트에 전달해 UI가 진행 상황을 알게 하고, 실패하면 캐시를 정리한 뒤 재시도하고, 그래도 실패하면 폴백 스켈레톤으로 떨어져 화면이 빈 채로 멈추지 않게 했다. "실패하면 멈춤"이 "실패해도 뭔가는 보임"으로 바뀌어야 프로덕션에 올릴 수 있다.

결과와 트레이드오프

렌더 방식은 Canvas 2D에서 WebGL로 전환했고, 벡터 그래픽 라이브러리 의존은 빌드 설정까지 완전히 제거했다. 스키닝은 CPU LBS로 초기 구현을 마쳤고 GPU 셰이더 스키닝은 다음 단계로 남겼다.

트레이드오프도 분명하다. 자산 의존이 무거워졌고, 색상·데이터 규약이 달라져 변환 레이어가 늘었으며, CPU LBS는 한 번 더 갈아탈 빚을 남겼다. 천장을 뚫는 대신 복잡도를 얻은 셈이다.

잘 돌아가는 코드를 버리는 이유는 현재가 아니라 다음 때문이다. 이번 마이그레이션은 버그를 고친 작업이 아니라, 다음 기능을 얹을 기반을 다시 만드는 작업이었다.

#실시간렌더링#WebGL#마이그레이션#모션엔진
잘 돌아가던 렌더러를 갈아엎은 이유5분 읽기 · 0%