3D 에셋 최적화 스팀팩으로 340% performance 개선하기

꼬꼬면·2025년 9월 25일
4
post-thumbnail

안녕하세요! 꼬꼬면 팀의 프론트엔드를 맡고 있는 조민형입니다. 이번 글은 저번 글과는 다르게 다소 기술적인 이야기를 해보려고 합니다!
저희가 기존보다 어떤 방식으로 서비스를 개선하려고 했는지, 그 과정에서 lighthouse 지표 중 performance가 높은 lcp로 인해 25까지 떨어진 상황에서 86점까지 올리며 약 0% 정도를 개선했던 과정을 이야기해보려고 합니다.

문제의 발단

저희의 서비스는 타 서비스들과 같이 랜딩 페이지에서 이탈하는 사람이 많았습니다.

모니터링 툴에서 보면 첫번째 페이지 -> 두번째 페이지로 가는 사람들의 수가 반 정도 사라지는 것을 볼 수 있습니다. 이러한 지수의 경우, 보통 이탈률(bounce rate)라고 하며 마케터와 기획자들이 주로 보는 수치입니다. 랜딩 페이지에서는 주로 CTA(Call To Action)를 통해서 사용자가 처음 해당 서비스에 진입했을 때, 저희가 예상하는 행동을 할 수 있도록 최대한 사용자를 유도해야 합니다. 저희의 경우에는 CTA 버튼이 면접 선택 창으로 이동하는 것이었습니다.

하지만 통계상으로 볼 때, 45%나 되는 많은 사람들이 랜딩 페이지만 보고 저희 서비스를 이탈했을을 알 수 있었습니다. 면접 화면도 제대로 보지 않은 채로 떠난다는 의미이기도 하기에 저희의 서비스를 제대로 체험하지 못하고 이탈하는 점에서 아쉬움을 많이 느꼈습니다.

추가적으로 세션 리플레이들을 보면 대부분의 사람들이 30초도 안되는 시간동안만 보고 떠나는 모습들을 볼 수 있었는데, 보다보니 마음이 아파지더라고요🥲

마음이 아파 볼 수 없는 세션 리플레이..

이에 저희는 저는 전환율을 조금이나마 더 늘리고자 이것저것 랜딩페이지를 개선하기 시작했습니다.

  • 서비스에 대한 소개 구체화
  • 애니메이션 추가 및 반응형 개선
  • 서비스에 대한 지인들의 추천사
  • 3D 요소를 통한 어그로(?)
    등을 랜딩페이지에 새롭게 추가하였습니다.

해당 개선사항을 반영한 뒤, 다른 지인들의 반응을 물어보았고, 생각보다 3D 요소같은 부분이 이목을 끌다 보니 바로 위에 있는 CTA가 눈에 띄어 눌러보게 됐다는 긍정적인 반응을 얻었습니다.

하지만 프로덕션으로 배포하기 전에 문제가 하나 새롭게 생기게 되었습니다.
바로 추가한 Threejs 에셋이 너무 크다는 점이었습니다.

8.7MB의 뚱뚱한 에셋 크기를 가진 3D 에셋은 가장 크게 잡히는 요소이기도 했기 때문에 급격하게 LCP 지표를 악화시켰고, 이에 따라 Core Web Vital 지수중 Performance 점수가 급락하기 시작했습니다.

처음에는 Ligthhouse CI 단계에서 Performance가 급격히 떨어지는걸 확인했고, 이를 개선할 필요성을 느끼게 되었습니다.
그렇게 3D 최적화의 여정이 시작되었습니다.

1. GLB → GLTF

가장 먼저 했던 작업은 GLB 파일에서 GLTF로의 변환이었습니다.

GLB와 GLTF는 모두 3D 에셋을 위한 확장자로 보이지만, 실제로는 구조적인 차이가 있습니다.

GLB(GL Transmission Format Binary) 는 모든 리소스(텍스처, 메시, 애니메이션 등)가 하나의 바이너리 파일에 통합된 형태입니다. 반면 GLTF(GL Transmission Format) 는 JSON 기반의 텍스트 형식으로, 외부 리소스 파일들을 참조하는 구조로 되어 있습니다.

본질적으로는 동일한 형식이며, GLB는 GLTF를 바이너리화한 것입니다. 하지만 개별 텍스처나 애니메이션 키프레임을 최적화하기 위해서는 각 요소에 접근할 수 있도록 분리할 필요가 있습니다.

따라서 저는 최적화를 하기 위해 여러 단계를 계획했습니다.

  1. GLB → GLTF 변환: 개별 리소스에 접근할 수 있도록 분리
  2. 개별 최적화: 텍스처 이미지와 GLTF 파일 자체를 각각 최적화
  3. GLTF → GLB 재변환: 최적화된 요소들을 다시 바이너리로 통합

마지막 단계에서 다시 GLB로 변환하는 이유는 바이너리 데이터의 효율성 때문입니다. 8비트 바이너리 데이터가 Base64(6비트 기준)로 인코딩되면 3바이트가 4문자로 표현되기 때문에 데이터 크기가 약 33% 증가할 가능성이 있습니다.

또한 GLTF는 JSON 형식으로 되어 있기 때문에 해당 파일을 파싱하고, GLTF 안에 선언되어 있는 텍스처와 같은 외부 리소스를 가져오는 과정 또한 있기 때문에, 이로 인한 네트워크 비용 증가 또한 불가피한 점이다 보니 하나의 파일로 가져오는 것이 더 효율적일 수 있겠다고 판단했습니다.

따라서 저는 GLB -> GLTF -> GLB의 과정을 통해 3D 모델 내부의 세부 에셋들을 고치고, 다시 바이너리로 변환하며 하나의 파일로 만들고자 했습니다. 그렇기에 일단 먼저 gltf 파일로 blender에서 변환을 진행했어요.

2. 텍스처 이미지 최적화 (JPG/PNG → WebP)

gltf로 export한 다음에는 텍스처 이미지에 대한 최적화를 진행했습니다. gltf로 변환한 뒤에 텍스처 이미지들을 봤는데 모두 jpg, png등의 확장자로 되어 있었어요. 따라서 이렇게 되어 있는 이미지들을 webp로 변환하는 과정을 거쳤습니다.

WebP 포맷의 이점으로는

  • PNG 대비 더 작은 파일 크기 (무손실 압축)
  • JPG 대비 더 작은 파일 크기 (손실 압축)
  • 알파 채널 지원으로 PNG 대체 가능
    의 이점이 있기 때문에 더 작은 용량을 위해 webp로 변환해주었습니다.

이 텍스처 이미지를 최적화함으로써 약 4MB정도를 최적화할 수 있었습니다.

3. gltfpack을 이용한 모델 데이터 최적화

추가적으로 이미지 텍스처 뿐만 아니라 gltf 파일 자체에 대해서도 진행하게 되었어요. gltf 파일에 대한 최적화의 경우, gltfpack 이라는 툴을 활용했습니다.
gltfpack은 C언어로 이루어진 메시 데이터 최적화 툴인 Meshoptimizer 기반의 GLTF 최적화 도구로, 메시 압축과 텍스처 최적화를 통해 파일 크기를 대폭 줄일 수 있습니다.

해당 툴을 통해

  • 정점 데이터 압축으로 파일 크기 감소
  • 중복 정점 제거 및 인덱스 최적화
  • 애니메이션 키프레임 압축
    의 최적화를 이룰 수 있었어요.
// 라이브러리 설치
npm install -g gltfpack

gltfpack -i input.gltf -o output.gltf

이를 통해 기존의 경우 애니메이션 키프레임과 같은 데이터를 담은 bin과 gltf 파일이 합쳐서 약 3MB정도 되었는데,

이제는 합쳐서 1.8MB 정도로 약 60% 정도를 개선할 수 있었습니다!

4. 다시 GLTF -> GLB로 변환하기


GLTF로 변환된 모델 데이터를 다시금 GLB로 blender에서 export 하면서 최적화 옵션을 통해 추가적으로 최적화를 진행했고, 3.7MB -> 1.3MB로 다시금 약 70%의 용량으로 줄일 수 있었습니다.

정리

이번 이야기에서는 3D 모델을 도입하면서 lighthouse performance가 25정도까지 떨어지던 문제를 해결하기 위해 최적화를 진행했던 과정들을 담았습니다.

최적화를 진행했던 부분들은 3D 에셋들에 대해서

  • 텍스처 이미지 최적화
  • gltfpack을 이용한 모델 데이터 최적화(메시, 애니메이션 키프레임 등)
  • 바이너리 파일로 재변환하면서 최적화
    등의 방법을 통해 최적화를 진행하였고, 처음 8.3MB였던 glb 파일 크기를 1.3MB까지 약 85% 용량을 개선할 수 있었으며, lighthouse 지표 중 Performance를 25에서 약 86까지 거의 약 340%를 개선할 수 있었습니다.

표를 통해서도 크게 에셋의 크기가 감소했음을 확인할 수 있었습니다.

추가적으로 해당 3D 에셋과 랜딩 페이지 개선 작업을 통해 기존에는 45%였던 bounce rate를 38% 정도까지 개선할 수 있었습니다. 일부 요소들과 마케팅 플랫폼의 증가로 제대로 변인 통제가 안됐다는 점은 다소 아쉽게 느껴졌지만, 그럼에도 기존보다 개선된 전환율을 통해 성취감도 얻을 수 있었습니다.

만약 여러분들도 threejs와 같은 3d 에셋을 사용할 때, 가장 크게 신경쓰는 부분이 이러한 에셋들의 크기일 것이라고 생각합니다. 저와 같은 방법으로 최적화를 진행해보고 많이 성능 개선을 이루셨으면 하는 마음으로 글을 마칩니다.

profile
꼬리에 꼬리를 무는 면접, 꼬꼬면!

0개의 댓글