공간 분할·선택 로딩 시험
2026-10-02. 같은 Knock Hall 마스터를 실제로 나눈 다섯 SOG를 두 앱에서 사용했다. 시작 시 전체 SOG를 요청하지 않고, 이동에 따라 구역 파일을 로드하고 렌더러 자원을 해제하는 동작을 확인했다. 이 단계는 데스크톱의 기능 검증이며 엔진 성능 순위는 정하지 않는다.
2026-10-03 후속: 원거리 저해상도 표현을 추가했다. 아래 최초 65.4% 절감과 브라우저 기록은 원거리 생략 단계의 결과다. 현재는 저해상도 포함 약 54.2% 절감이며 교체 순간 선명도 변화가 남는다.
분할 자료와 최초 로딩량
scripts/make-spatial-chunks.py가 900,000개 원본 레코드를 Gaussian 중심의 X 좌표로 4 m씩 나눈다. 각 레코드는 인코딩 전에 한 구역에만 들어간다. SH0으로 다시 인코딩한 결과와 해시는 분할 메타데이터에 있다. 기존 런타임 current.sog도 SH0이다.
| 구역 | X 범위(m) | Gaussian 수 | SOG 크기(B) |
|---|---|---|---|
| 0 | 0–4 | 69,967 | 931,680 |
| 1 | 4–8 | 231,735 | 3,060,137 |
| 2 | 8–12 | 267,979 | 3,541,172 |
| 3 | 12–16 | 215,380 | 2,836,047 |
| 4 | 16–20 | 114,939 | 1,510,967 |
| 합계 | 0–20 | 900,000 | 11,880,003 |
시작 위치 X=3에서는 구역 0·1만 준비한다. 301,702점, 3,991,817 B로 분할본 전체의 33.5% 점 수·33.6% 파일 크기다. 기존 단일 SOG 11,543,748 B와 비교하면 최초 SOG 파일 크기를 약 65.4% 줄였다. HTML·JS·물리 엔진·JSON·충돌 메시까지 합한 페이지 전송량이나 GPU 메모리 감소율은 아니다. 전체 분할본은 개별 압축 때문에 단일 파일보다 약 2.9% 크다.
Gaussian의 중심은 중복되지 않지만 타원체의 범위는 경계를 넘을 수 있다. 재인코딩의 양자화와 압축도 있으므로 원본과 픽셀이 완전히 같다는 의미는 아니다.
실행 정책
- 공통
SpatialStreamer가 요청·준비·실패·해제 상태와 예산을 관리한다. 엔진별 어댑터가 실제 Splat 생성·표시·해제를 맡는다. - 로드 거리 1.5 m, 해제 거리 2.5 m, 상주 예산 최대 3구역·750,000점이다. 로딩 중인 구역도 예산에 예약하며 해독을 한 번에 하나씩 수행한다.
- 구역 경계에 캡슐이 닿기 전에 필요한 구역이 준비돼야 이동할 수 있다. 지연 때 수평 이동을 막고 중력 처리는 유지한다.
- 멀어진 구역은 실제 렌더러 객체를 정리한다. 이미 진행 중인 SDK 해독은 취소하지 못하므로 늦은 결과가 오면 표시하지 않고 해제한다.
- 실패는 자동 반복 요청하지 않는다. 사용자가
구역 로딩 재시도로 다시 요청한다. - 전체 공통 충돌 메시 24삼각형·1,052 B는 유지한다. 구역별 충돌 메시의 로드·해제까지 구현한 시험은 아니다.
- 설정 검증은 연속된 X 구역과 공통 Y/Z 범위를 요구한다. 해제 거리 안의 구역들이 예산을 초과하는 설정은 거부해 경계에서 영구 대기하는 구성 오류를 막는다. 임의 모양의 공간 분할이나 LRU 스케줄러는 지원하지 않는다.
브라우저 확인
Playwright MCP의 headed Chromium에서 앱을 하나씩 실행했다. 릴리스 local-4d5905679d2e-cbfaf693149e, 화면 1200×863·DPR 1.5. 전체 JSON, 정상 경로 (원본 저장소 파일), 실패 주입 경로 (원본 저장소 파일).
| 구성 | 시작 준비 | 경로 중 최대 예약 | 끝 구역 이동→시작 복귀 | 로드/해제 횟수 | 낙하 복구 / JS 예외 |
|---|---|---|---|---|---|
| Three.js + BVH | 0·1 / 301,702점 | 2구역 / 499,714점 | 통과 | 9 / 7 | 0 / 0 |
| Three.js + Rapier | 동일 | 동일 | 통과 | 8 / 6 | 0 / 0 |
| PlayCanvas + Ammo | 동일 | 동일 | 통과 | 8 / 6 | 0 / 0 |
세 구성 모두 전체 current.sog 요청 없이 이동과 복귀가 됐다. 로드 횟수 차이는 시간과 위치에 따른 해제·재요청 차이이며 성능 우열의 근거가 아니다. requestedBytes는 논리적 파일 요청 크기의 합이다. 브라우저 캐시 재사용을 포함한 실제 네트워크 전송량과 다르다.
BVH·Ammo에서는 구역 2의 응답 지연 중 경계 정지, 응답 후 이동 재개, 요청 실패 후 자동 재시도 없음·수동 복구, 로딩 중 시작점 복귀 후 늦은 구역 결과 폐기를 확인했다. Rapier는 정상 경로와 공통 상태 관리 단위 검사를 통과했지만 이 실패 주입 브라우저 시험은 별도로 하지 않았다.
추가로 Three.js BVH에서 전체 경로를 세 번 왕복했다. 각 복귀 후 renderer.info.memory는 geometry 2개·texture 10개로 유지됐고 상주 구역은 0·1로 돌아왔다. 자원 수 기록. GPU 바이트·프로세스 RAM을 측정한 결과가 아니며 PlayCanvas의 동등한 GPU 자원 수는 확보하지 않았다.
최종 릴리스 local-4d5905679d2e-f6ec268ff18a에서 pnpm check를 통과했다. 15개 자산의 크기·해시, 54개 자동 검사, 타입 검사와 두 앱 빌드·배포 목록 검증을 포함한다. 이후 headed Chromium으로 세 구성의 최초 선택 로딩과 PlayCanvas 왕복, BVH 패널 입력 복귀를 추가 확인했다. 최종 확인 JSON. 최종 확인에서 실패 주입과 전체 콘텐츠 경로를 모두 다시 실행한 것은 아니다.
아직 남은 핵심 제한
이 문서의 초기 시험에서는 로드하지 않은 먼 구역이 보이지 않았다. 현재는 저해상도 표현으로 유지하지만 정밀 자산 교체 순간의 선명도 변화와 경계 품질 검수가 남아 있다. 엔진 고유 LOD 기능을 비교한 결과도 아니다.
이 시험은 작은 공통 충돌 바닥 위의 현재 장면만 지원한다. 분할과 시대 전환의 결합, 실제 복잡한 충돌 메시 분할, iPhone에서 분할 장면의 준비·이동·장시간 유지, 큰 야외 공간의 배경 유지가 남아 있다. 데스크톱의 성공을 모바일 안전 한도로 사용하지 않는다.
직접 확인
./dev.sh --preview both 후 장면 메뉴에서 구역별 로딩 · 분할 시험을 선택한다. Three.js BVH, Rapier, PlayCanvas.
마우스를 잠그지 않아도 D로 오른쪽 구역까지, A로 시작 구역까지 이동할 수 있다. 상단 구역 상태가 바뀌는지, 경계에서 바닥을 잃지 않는지 확인한다. 현재 먼 구역은 저해상도로 유지된다. 이동 중 건물의 선명도가 바뀌는 정도도 확인한다.