라이브 체험 프로젝트 소개
「숲속의 작은 사슴」은 브라우저에서 실행되는 실시간 three.js 장면입니다. 작은 사슴이 야쿠시마풍의 거대한 삼나무 숲을 거닐고, 수관 틈새로 햇빛이 쏟아져 내리며, 풀은 바람에 흔들리고 나비가 꽃 주위를 맴돕니다. 사슴과 함께 산책하고, 숲속의 빛 알갱이를 모으고, 낮과 달밤을 오갈 수 있으며, 시네마틱 카메라에 맡겨 페이지 안에서 바로 영상을 녹화할 수도 있습니다.
사슴은 Tripo API로 생성한 뒤 스마트 로우폴리, 리깅 가능 여부 검사, 사족보행 자동 리깅을 거쳐 리그가 포함된 GLB로 내보냈고, 숲은 전부 프로시저럴로 생성했습니다. 텍스처는 Poly Haven(CC0) 소재를 사용했습니다.
키보드가 있는 데스크톱 브라우저에서 가장 온전하게 즐길 수 있습니다. 휴대폰에서는 땅을 탭하면 사슴이 그곳으로 걸어가고, 드래그로 시점을 회전할 수 있습니다.
체험 포인트
- WASD로 사슴을 걷게 하거나 땅을 클릭해 그곳으로 보낼 수 있습니다. Shift를 누르고 있으면 종종걸음으로 뛰고, 드래그로 시점을 회전합니다
- 빛나는 빛 알갱이 속으로 걸어 들어가면 모을 수 있고, 아홉 개를 모두 모으면 윈드차임이 연달아 울리며 빛줄기가 환하게 밝아집니다. E를 누르거나 사슴을 클릭하면 고개를 들어 이쪽을 바라봅니다
- R로 낮과 달밤을 전환하고, G를 누르면 돌풍이 불어 풀이 눕고 나비가 흩어집니다
- C로 시네마틱 카메라를 켜고, V로 페이지 안에서 바로 소리가 담긴 영상을 녹화합니다. H는 키 안내 패널을 숨깁니다
기술 분석
사슴 · Tripo로 생성하고 자동 리깅
사슴은 Tripo API 파이프라인에서 나왔습니다. 모델 생성, 스마트 로우폴리, 리깅 가능 여부 검사, 사족보행 자동 리깅을 거쳐 약 15,000개의 삼각형, 41개 본으로 된 사족 골격, PBR 텍스처를 갖춘 GLB로 출력됩니다. 페이지에서는 GLTFLoader로 불러와 머리 높이가 약 1.55m(꽃사슴 체격)가 되도록 크기를 맞춥니다.
Tripo 리그는 이름이 깔끔하게 정리되어 있습니다. 네 다리는 각각 Limb_0부터 Limb_3까지 나뉘고, 척추·목·머리도 순서대로 번호가 매겨져 있어 코드가 이름만으로 각 다리와 척추, 목을 찾아 바로 움직일 수 있습니다. 본을 하나하나 손으로 매핑할 필요가 없죠. 셰이더로 털빛을 꽃사슴의 붉은 갈색 여름털로 물들이고, 등을 따라 옅은 반점을 한 줄 흩뿌립니다. 반점은 바인드 포즈 좌표에 고정되어 있어 걸을 때도 피부 위에서 미끄러지지 않고, 역광에서는 털 가장자리에 따뜻한 빛 테두리가 생깁니다.
걸음걸이 · 리그 위에서 실시간으로 계산하는 걸음
걸음은 페이지가 로드될 때 이 리그 위에서 IK로 즉석 계산됩니다. 먼저 발굽의 궤적을 정합니다. 땅에 닿아 있는 동안 각 발굽은 몸의 속도와 정확히 같은 속도로 뒤로 밀려나고, 공중에서는 들어 올려져 앞으로 뻗었다가 다시 내려앉습니다. 다리는 왼쪽 뒤, 왼쪽 앞, 오른쪽 뒤, 오른쪽 앞 순서로 내딛고, 각각 전체 시간의 약 70% 동안 땅에 닿아 있으며, 몸은 살짝 오르내리고 흔들릴 뿐입니다. 각 다리는 위아래 구간을 바인드 포즈 각도로 유지하는 3구간 IK로 풀고, 앞다리를 들 때는 손목을 한 번 더 접습니다. 걸음 전체는 48프레임 루프로 베이크해 AnimationMixer에 넘깁니다.
재생 속도는 ‘몸의 속도 ÷ 발굽이 뒤로 쓸려 가는 속도’로 환산하므로, 천천히 걷든 Shift를 누른 채 종종걸음으로 달리든 발굽이 땅에서 미끄러지지 않습니다. 멈춰 서 있을 때는 코드가 등 위쪽부터 머리까지 네 개의 본을 돌려, 사슴이 한동안 풀을 뜯다가 고개를 들어 한쪽을 바라보고 다시 고개를 숙입니다. 그리고 걸음을 떼는 순간 목이 올라갑니다.
삼나무 숲 · 코드로 키워 낸 숲
사슴을 제외하면 숲속의 모든 것은 코드로 생성됩니다. 텍스처는 Poly Haven의 CC0 소재(삼나무 껍질, 이끼 낀 바위, 숲 바닥) 세 가지뿐입니다. 거대한 삼나무는 높이가 약 44m로, 가까이 있는 주인공 나무는 개별 메시로, 뒤쪽 줄은 InstancedMesh로 한꺼번에 그리며, 줄기의 휘어짐은 셰이더와 JS에서 같은 공식을 써서 가지가 휜 줄기에 그대로 붙어 있게 했습니다. 거목들 사이에는 8–17m의 어린 나무가 한 층을 이루고, 관목과 고사리, 바위, 쓰러진 통나무가 숲의 하층을 채웁니다.
땅에는 버텍스 셰이더에서 흔들리는 12만 개의 인스턴스 풀잎이 깔려 있고, G를 누르면 6초 동안 돌풍이 불어 풀이 눕고 나비가 흩어집니다. 풀은 사슴의 위치도 알고 있어서 사슴 주변에서는 바깥쪽으로 휘어집니다. 나비 18마리는 꽃 주위를 느긋하게 날다가 사슴이 다가오면 놀라 흩어지고, 잎자루와 잎맥까지 갖춘 낙엽 70장은 빙글빙글 떨어지다가 빛줄기를 지날 때 환하게 빛납니다.
빛 · 볼류메트릭 빛줄기와 얼룩진 햇살
수관은 납작하게 눌린 잎 덩어리 수백 개로 이루어져 있습니다. 덩어리를 하나 놓을 때마다 햇빛 방향을 따라 땅에 투영해 미리 정해 둔 29개의 빛줄기 낙하 지점을 피하게 하므로, 빛줄기가 한 줄기씩 갈라져 내려옵니다. 볼류메트릭 라이트는 시선을 따라 조금씩 태양의 섀도 맵을 샘플링해 절반 해상도로 산란을 계산한 뒤, 원경 안개, ACES 톤 매핑, 블룸, FXAA와 차례로 합성해 화면을 완성합니다.
그림자는 PCSS 소프트 섀도로 다시 작성해, 가리는 물체에서 멀어질수록 가장자리가 부드러워집니다. 수관 사이로 새어 드는 빛 얼룩은 광원 공간에서 한꺼번에 계산하므로 풀, 나무껍질, 사슴, 빛줄기가 모두 같은 무늬를 공유합니다. 공기 중의 먼지는 빛줄기 안에서만 반짝이고 그늘에서는 거의 보이지 않습니다. R을 누르면 3초에 걸쳐 밤으로 바뀌며, 태양은 차가운 달빛으로 바뀌고 빛줄기는 희미해지며 빛 알갱이는 반딧불처럼 빛납니다.
카메라와 녹화 · 페이지 안에서 바로 촬영
C를 누르면 시네마틱 카메라로 전환되어, 사슴 주위를 천천히 돌며 높낮이를 바꾸고 UI는 모두 사라집니다. V를 누르면 녹화가 시작되며, MediaRecorder가 WebGL 캔버스와 소리를 60fps·16Mbps로 그대로 기록합니다. 브라우저가 지원하면 MP4, 아니면 WebM으로 저장하고, 녹화 중에는 화질 단계를 고정해 클립 도중에 해상도가 바뀌지 않습니다.
모든 소리는 Web Audio로 실시간 합성합니다. 빛 알갱이를 모을 때마다 윈드차임이 울리는데 음높이가 5음 음계를 따라 올라가고, 바람이 불면 바람 소리가 납니다. 평소에는 프레임 레이트에 맞춰 해상도를 자동으로 조정해 프레임이 떨어지면 한 단계 낮추고, 1 / 2 / 3 키로 저·중·고화질을 직접 고정할 수도 있습니다.


