Sunnyvale 구역·시대·설명 결합과 충돌 재사용
2026-10-03. Sunnyvale의 실제 촬영 자산·공식 충돌 메시 분할본에 시대별 시험 벽과 설명을 결합했다. Three.js의 구역 충돌 교체도 전체 재구성에서 변경된 객체만 추가·제거하는 방식으로 바꿨다.
확인할 화면
장면 선택에서 Sunnyvale · 구역·시대·설명 결합 시험을 고른다.
현재 벽은 시작점 오른쪽 4m, 과거 벽은 6m에 있다. 시작 구역과 오른쪽 다음 구역에는 시대별 설명이 있다. WASD로 이동하며 벽·설명·구역 로딩을 확인하고 시대 버튼으로 전환한다.
과거 표현은 가상 변경이다. 양쪽 시대가 오늘의 촬영 배경과 분할 충돌을 재사용하고 황색 벽과 설명만 다르게 구성한다. 실제 과거 건물·가구·지형을 복원했거나 역사 자료를 검수한 결과가 아니다. 화면과 콘텐츠에도 이를 명시했다. 서로 다른 대형 시대 자산 두 벌의 다운로드·메모리 비용은 이 시험으로 판단할 수 없다.
데이터와 구현
scripts/compile-sunnyvale-era.mjs가sunnyvale-stream.json과 별도 작성 원본shared/source/sunnyvale-era.author.json에서 결합 월드와 설명을 생성한다.make-sunnyvale-era.py는 호환 실행 경로다. SOG와 분할 GLB를 다시 인코딩하거나 복제하지 않는다.- 현재·과거 객체는 별도 ID와 layer를 가지며 같은 자산 경로를 참조한다. 구역에는 시대별 상세·원거리 객체 ID를 연결했다. 황색 벽에는 시대별 시각 객체·충돌·전환 겹침 범위를 지정했다.
- 시작 구역
sunny-strip-3, 다음 구역sunny-strip-4에 설명 소유권을 지정했다. 이동·시대 전환 시 이전 패널 정리와 준비되지 않은 구역으로의 이동 제한을 기존 공통 정책으로 처리한다. - Three.js
CollisionSurfaces는 객체별로 월드 좌표를 구운 geometry/BVH를 보관한다. 유지되는 객체는 재사용하고 추가 객체를 준비한 뒤 제거 객체를 해제한다. 준비·게시 실패 시 기존 BVH를 유지한다. - Rapier도 객체별 static collider를 보관한다. 추가 물리 형상을 먼저 생성하고 더 이상 쓰지 않는 형상만 제거한다. PlayCanvas는 기존 구역별 Ammo 추가·제거를 유지한다.
- 상주 객체의 변환은 고정이어야 한다. 위치·회전·스케일·형상이 바뀌면 새 객체로 교체해야 한다. 같은 객체를 직접 움직여도 충돌이 자동 갱신되는 계약은 아니다.
- 이번 재사용은 구역 로딩·해제에 적용했다. 시대 전환에서는 여전히 제어기 전체를 새로 구성한다. 시대 간 충돌 재사용이나 실제 시대별 바닥 제작까지 완료한 것으로 보지 않는다.
데스크톱 기능 검증
별도 headed Chromium에서 Playwright MCP로 한 번에 한 앱을 열고 실제 키보드·버튼을 조작했다. Chrome 154, Apple M4 Pro의 ANGLE Metal GPU, 화면 표시·포커스 상태를 기록했다. 시험 릴리스는 local-4d5905679d2e-89a5df9eff9e다.
| 확인 | BVH | Rapier | Ammo |
|---|---|---|---|
| 현재·과거 설명, 전환 시 패널 정리 | 통과 | 통과 | 통과 |
| 현재 벽 제거·과거 벽 생성, 반복 전환 | 통과 | 통과 | 통과 |
| 다음 구역 로딩·이전 구역 해제·시작점 재로딩 | 통과 | 통과 | 통과 |
| 새 시대 벽과 겹친 위치에서 안전 시작점 이동 | 통과 | 통과 | 통과 |
| 시대 전환 중 충돌 자산 실패 → 이전 시대 복구 | 통과 | 통과 | 통과 |
| 복구 후 벽 충돌·전환 재시도 | 통과 | 통과 | 통과 |
일반 시나리오는 구성별 8개 시점, 실패 시나리오는 5개 시점을 저장했다. 종료된 이전 스트림의 준비·로딩·충돌 자원이 비워졌는지 확인했다. 실패 주입은 전환의 loading 단계 동안 대상 충돌 GLB 요청을 차단하고 restoring 단계에는 허용했다. Ammo의 자동 요청 재시도도 포함한다. 실패 시험의 네트워크 오류와 전환 오류는 의도한 기록이다.
일반 시험에서 예기치 않은 오류나 추락 복구는 없었다. PlayCanvas에서는 1 splats lost due to sortKey overflow 경고가 7회 기록됐다. 자산 AABB와 정렬 키 범위를 추가 확인해야 하며 이 문서에서 해결됐다고 판단하지 않는다.
구역 충돌 교체 비용
기존 sunnyvale-stream 장면에서 이전 시험과 같은 오른쪽 이동·경계 왕복·다음 구역 이동·시작점 복귀 경로를 사용했다. 각 구성에서 추가 4회와 제거 4회의 동기 충돌 교체 호출 시간을 기록했다. 다운로드·해독·전체 프레임 p95는 포함하지 않는다.
| 구성 | 이전 추가 (ms) | 이번 추가 (ms) | 이전 제거 (ms) | 이번 제거 (ms) |
|---|---|---|---|---|
| Three.js BVH | 40.5–65.9 | 6.8–28.9 | 20.7–50.2 | 0.0–0.1 |
| Three.js Rapier | 100.7–176.6 | 18.2–65.9 | 60.6–91.6 | 0.0–0.4 |
두 구성 모두 최초 2개와 이후 추가 4개를 합쳐 6개 형상을 만들었다. 제거 4회, 유지 재사용 누계 8개, 종료 상주 2개를 확인했다. Rapier static collider도 종료 시 2개다. 전체 활성 구역 재구성이 제거됐다는 동작 근거와 비용 감소가 일치한다.
동일 Mac·경로·자산 예산의 변경 전후 단일 실행 비교다. 무작위 반복 대조나 엔진 우열 판정은 아니다. Rapier 추가 최대 65.9ms는 메인 스레드 멈춤 위험이 남아 있다는 근거다. PlayCanvas 교체 코드는 이번에 바꾸지 않았으며 새 비용 비교 실행도 하지 않았다. 이전 수치는 화면·충돌 분할 기록에 남겨 두었다.
근거와 검사
측정 폴더 (원본 저장소 파일)에 기능 3개, 실패·복구 3개, 교체 비용 2개의 결과 JSON을 저장했다. 여덟 결과 모두 passed: true다. 기능·비용 화면 PNG와 세 종류의 driver JS도 같은 폴더에 있다.
bvh/rapier/ammo-era.json: 기능 시점과 앱 상태·환경.bvh/rapier/ammo-era-fault.json: 겹침 안전 이동·실패·복구·재시도.bvh/rapier-incremental-cost.json: 교체 시간과 형상 재사용 누계.
pnpm check가 자산 검사, 스크립트 11개·공통 31개·Three.js 26개 테스트, 양쪽 타입 검사·프로덕션 빌드·릴리스 산출물 검사를 통과했다. 추가된 테스트는 유지 형상 재사용·제거 시 해제·실패 시 기존 형상 유지·여러 BVH 중 가까운 교차점·Rapier 교체 직후 충돌을 확인한다.
남은 한계와 다음 작업
- 계단·벤치 조사에서 계단 직진과 정지는 확인했다. 벤치 부근은 충돌면 높이가 약 69cm 바뀌며 세 구성 모두 복귀 실패가 남는다. 실제 바닥·이동 금지 경계를 확인한 메시 보정이 필요하다. 벽 비침도 미해결이다.
- 별도 작성 원본·재생성 검사와 한 구역 제작·검수 절차를 마련했다. 실제 현재·과거 자료와 시대별 바닥을 제작하고 사람의 시간을 기록하는 작업은 남아 있다. 이 생성기는 가상 변경 시험이며 범용 편집 도구가 아니다.
- 새 결합 장면과 충돌 재사용 변경은 iPhone에서 아직 확인하지 않았다. 이전 화면·충돌 분할 시험의 iPhone 성공과 구분한다. 모바일 메모리·물리적 터치 사용성·장시간 유지, 원본 SH3 해독 문제도 남아 있다.
- 논리적 상주 자원과 해제 상태를 확인했지만 실제 GPU 메모리 절감을 측정하지 않았다. 큰 장소의 2D 분할·원거리 선택 로딩과 시대별 대형 자산 예산도 후속 과제다.
일반 성능 경로를 반복하기보다 보행 품질과 실제 콘텐츠 변경 작업에서 드러나는 실패를 다음 판단 근거로 삼는다.