뒤로

3D 뮤직 카드

전체 화면 인터랙티브 음악 공간입니다. 중앙에는 Tripo 캐릭터가 서 있고, 실제로 재생할 수 있는 여섯 개의 유리 레코드 패널이 불규칙한 3D 별자리 형태로 캐릭터를 둘러쌉니다. 트랙을 선택하면 해당 패널이 공간에서 빠져나와 전면으로 날아온 뒤, 화면 하단에 2D 플레이어로 안착합니다.

제작자: Theodore
라이브 체험
3D 뮤직 카드라이브 체험

프로젝트 소개

여섯 개의 패널은 Scene 안에 존재하는 실제 WebGL 지오메트리입니다. 두께와 곡률이 있고, 캐릭터를 가리기도 하며 캐릭터에 가려지기도 합니다. 어느 각도에서 보더라도 깊이 순서가 정확하게 유지됩니다. canvas 위에 띄운 DOM 카드가 아닙니다.

전체 인터랙션은 하나의 역할 분담을 바탕으로 합니다. 탐색은 3D가, 제어는 2D가 담당합니다. 패널은 캐릭터 주위를 떠다니고 제스처에 따라 회전하면서 탐색과 선택을 맡습니다. 실제 재생 제어는 화면 하단의 안정적인 화면 공간 인터페이스가 담당합니다. 곡 선택은 단순한 상태 전환이 아니라 연속적인 인계 과정입니다. 패널 자체가 아래로 날아가 플레이어가 되고, 다른 트랙을 선택하면 기존 패널이 원래 3D 위치로 날아갑니다.

체험 포인트

  1. 빈 공간을 드래그하면 뮤직 카드가 캐릭터 주위를 돌고, 손을 놓은 뒤에도 관성으로 움직입니다. 캐릭터를 드래그하면 캐릭터만 회전하고 카메라와 패널은 그대로 유지됩니다. 둘은 서로 반대 방향으로 천천히 떠다닙니다. 이 상반된 움직임 덕분에 전체 클러스터가 배경이 아니라 궤도를 도는 하나의 천체처럼 느껴집니다.
  2. 패널을 클릭하면 3D 공간을 벗어나 캐릭터 옆을 스쳐 지나간 뒤, 화면 하단의 가로형 플레이어로 펼쳐집니다. 다른 패널을 선택하면 두 패널이 동시에 비행합니다. 새 패널이 앞으로 나오는 동안 기존 패널은 접히며 정확히 원래 자리로 돌아갑니다.
  3. 휠로 카메라를 4.6~16 월드 단위 사이에서 돌리 이동합니다. 밀어 넣으면 전경 패널이 프레임 밖으로 넘치고, 뒤로 당기면 전체 공간이 모여 위에서 내려다보는 하나의 음악 별자리가 됩니다.
  4. 커스텀 커서의 네 모서리 프레임은 각 패널이 실제로 투영된 쿼드에 고정됩니다. 브래킷은 원근법이 반영된 정확한 모서리에 맞춰지고, 패널의 기울기에 따라 함께 회전합니다.

기술 분석

  • 3D 에셋 · 손대지 않은 Tripo 내보내기 결과

    Artist.glb는 Tripo에서 내보낸 그대로 제공합니다. 59 MB, 1.02M 정점, 8192² 베이스 컬러 맵을 유지해 디시메이션도 리사이즈도 하지 않았으며, 제작된 디테일을 온전히 담았습니다. 그 비용(mipmap 적용 후 ~350 MB VRAM, 매 프레임 다시 그리는 100만 개의 정점)은 처음부터 감안하고, 두 가지 결정으로 관리 가능한 수준을 유지합니다. 무거운 메시는 raycasting에서 제외합니다. 포인터가 움직일 때마다 100만 개의 삼각형을 검사하면 메인 스레드가 멈추기 때문입니다. 대신 모델 자체의 경계를 기준으로 크기를 정한 보이지 않는 캡슐을 사용합니다. 또한 내보내기 파일에 애니메이션 클립이 없으므로 가상의 스켈레톤을 만들지 않고, 그룹 단위의 유휴 동작(느린 흔들림과 1밀리미터 정도의 호흡)을 적용합니다.

    scripts/의 meshopt 파이프라인은 같은 파일을 2.9 MB로 줄입니다. 로드 시 모델을 측정하고 정규화하므로 빌드를 교체해도 코드를 변경할 필요가 없습니다.

  • 머티리얼 · Tripo 내보내기의 볼륨 머티리얼 다운그레이드

    Tripo 내보내기는 메시에 KHR_materials_volume 태그를 추가합니다. three.js에서는 이 태그가 transmission/thickness 경로를 지닌 MeshPhysicalMaterial로 들어오지만, 이 Scene에는 필요하지 않고 비용도 감당하기 어렵습니다. 로드할 때 모든 머티리얼을 MeshStandardMaterial로 다운그레이드하되 전체 PBR 맵 세트는 유지합니다. 외형은 그대로 두고 비용만 제거합니다.

    커스텀 ShaderMaterials에는 colorspace_fragment를 명시적으로 포함합니다. 이 코드가 없으면 선형 값을 sRGB 프레임버퍼에 바로 기록해 거의 검게 렌더링됩니다.

  • 뮤직 패널 · 곡면 위의 실제 지오메트리

    각 패널은 네 종류의 지오메트리로 구성됩니다. 앞면, 실제 두께를 만드는 스윕 림 스트립, 반투명 백 플레이트, 보이지 않는 히트 쿼드입니다. 모두 하나의 캐시된 버퍼 세트를 공유하며 카드마다 다른 것은 그룹 변환뿐입니다. 모든 요소는 평면으로 제작한 뒤 커다란 수직 원통에 감쌉니다. 진행 홈과 시계는 부모로 연결하지 않고 같은 곡면에 베이크하며, 진행 표시 채움은 MeshBasicMaterial에 주입한 UV cutoff로 구현합니다. 메시를 스케일링하면 반대쪽 끝이 곡면에서 들뜨기 때문입니다.

    패널 아트워크는 업데이트 빈도에 따라 세 개의 canvas로 나눕니다. 1320×680 앞면은 한 번만 그리고, 시간 스트립은 표시되는 초가 바뀔 때, 아이콘은 재생 상태가 전환될 때만 다시 그립니다. 렌더 루프에서는 비용이 큰 작업을 수행하지 않습니다. 여섯 개의 투명 패널은 모두 depth write를 건너뛰고, 매 프레임 카메라 거리에 따라 구간별 renderOrder를 부여하므로 어느 각도에서도 오클루전이 정확하게 유지됩니다.

  • 3D에서 2D로의 릴레이 · 카드가 플레이어로 안착하는 과정

    WebGL 메시는 DOM 노드가 될 수 없으므로, 연속성은 세 가지 장치를 조합해 만듭니다. 프로젝터가 매 프레임 모든 카드의 화면 공간 박스를 최신 상태로 유지합니다. 돌아가는 비행에도 착륙 지점이 필요하므로 숨겨진 카드까지 포함합니다. DOM 패널의 첫 프레임에는 HTML로 다시 만든 화면이 아니라, 카드의 WebGL 텍스처에 이미 그려진 canvas 비트맵 자체를 사용합니다. HTML로 재현하면 위치가 미묘하게 어긋날 수밖에 없습니다. 그리고 같은 프레임에 카드를 숨깁니다. 같은 자리에 두 개가 있지만 하나만 보이지 않는 상태입니다.

    가로 확장은 비행이 ~35% 진행될 때까지 보류합니다. 비행 도중 2:1 카드를 11:1 바로 늘리면 아트워크가 뭉개지기 때문입니다. 이동 경로에는 옆으로 휘어진 이차 베지어 곡선을 사용해, 왼쪽 위에서 도킹하는 카드가 아티스트를 돌아 들어오도록 했습니다. 목적지는 매 프레임 다시 읽습니다. 별자리 배치가 계속 움직이기 때문에 출발 시점에 샘플링한 rect를 사용하면 패널이 원래 카드 옆에 착륙하게 됩니다.