Files
sunrise/docs/performance/mobile/README.md
T

72 lines
8.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 모바일 렌더링 최적화 검증 — 2026-10-30
## 측정 환경과 한계
Windows PC의 ChatGPT 내장 Chromium, CSS 412×915, 개발용 강제 DPR 설정으로 비교한다. 이는 모바일 **화면 크기 실험**이며 중급 안드로이드/Safari 실기기 검증이 아니다. 실제 모바일의 GPU, 발열, 메모리, 터치 입력 성능을 대체하지 않는다. 다른 데스크톱 프로그램도 실행 중인 환경이다.
앱 개발 서버에서 `/?profile&dpr=2`를 연 뒤 우측 DEV 패널의 시나리오 버튼을 누른다. 8초 준비 후 20초(지속 테스트는 300초)를 기록한다. 날짜 2026-10-30 07:00 KST, 기상은 맑음으로 고정된다. 낮 비교는 `&time=day`(12:00), 후처리 분리 실험은 `&post=off`를 사용한다. `dpr=1.5`, `dpr=1.25`는 내부 해상도만 바꾸며 CSS 크기는 같다.
일반 정지 장면은 기존과 같이 필요할 때만 렌더링한다. DEV 정지 시나리오는 GPU 비교를 위해 연속 렌더링을 강제한다. 보고된 FPS는 입력 콜백 빈도나 정지 시의 절전 효율이 아니라 **연속 렌더링 프레임 간격**의 역수다.
## 시나리오
- static: 초기 관측점과 시선을 유지한다.
- rotation: 초기 관측점에서 20초마다 360° 회전한다.
- movement: 관측점 동서 방향 ±3m 사인 왕복(8초 주기), 기존 지면 높이와 이동 가능 영역 검사를 사용한다.
- dense: 같은 왕복 이동 중 과천 건물 방향을 바라본다. 현재 관측점에서는 능선이 건물을 가릴 수 있으므로 도시 전체가 화면에 보이는 고부하 테스트를 의미하지 않는다.
- endurance: 위 왕복 이동과 360° 회전을 300초간 함께 실행한다.
스크립트 경로는 FPS와 독립된 위치를 입력한다. 일반 WASD 속도·터치·Pointer Lock의 수동 검증을 대신하지 않는다. 태양·좌표 갱신과 충돌·높이 처리는 기존 코드를 통과한다. 탭이 숨겨지면 측정을 취소한다. 초기/종료 카메라, 실제 이동거리, 충돌 거부 횟수와 렌더 크기를 JSON으로 남긴다.
## 계측 해석
- FPS = 1000 / 평균 프레임 간격. p95는 nearest-rank 방식이다. 50ms 초과 정지 프레임도 제거하지 않는다.
- Draw Call/삼각형은 `renderer.info.autoReset=false`로 모든 후처리 패스를 합산한다. 프레임 시작 시 한 번만 초기화한다.
- `renderer.info.memory`는 Three.js의 자원 개수이며 VRAM 바이트 사용량이 아니다. 시야 변화에 따른 최초 업로드 때문에 geometry 수가 증가할 수 있다.
- CPU update는 이동/충돌/고도/태양/정보 UI 갱신을 포함한다. 미니맵과 WebGL 명령 제출은 별도다. 제출 시간은 GPU 실행 시간이 아니다.
- 직접 참조된 재질 텍스처 목록은 셰이더 주입 텍스처 전체를 포함하지 않을 수 있다. 정상 표면은 color/normal/roughness 3종 × forest/path/rock 3표면을 사용하며 별도의 건물 조명 맵과 후처리 타깃이 있다.
- 현재 그림자 맵은 비활성화되어 있다. 주광원 DirectionalLight와 환경광 HemisphereLight를 유지한다.
## 진행 기록
원본 변경 파일은 `.tmp/mobile-performance/`에 보존했다. 원본 렌더 설정의 시나리오별 수치는 `baseline-*.json`에 저장한다. 최종 비교와 미검증 항목은 작업 종료 시 아래에 추가한다.
## 현재 결과 — 계측 및 실험 준비 단계
사용자 요청에 따라 5분 테스트와 추가 연속 렌더링 부하를 중단했다. 측정 탭은 닫혔고 별도 측정 서버도 중지했다. **성능 최적화 완료 또는 모바일 30 FPS 달성을 주장하지 않는다.**
동시에 진행된 다른 작업에서 `summitRelief` 등 장면 소스가 변경된 사실을 발견했다. 아래 JSON은 각 실행에서 실제 관측된 수치지만, 실행 간 동일 소스 버전을 보장하지 못한다. 특히 texture/geometry 개수 변화에는 최초 GPU 업로드 외에 장면 변경 영향이 섞일 수 있다. 파일명 `baseline-*`은 초기 수집 파일명이며, 최종 전후 비교의 확정 기준값으로 재사용하면 안 된다. 고정 소스에서 기준값을 다시 수집해야 한다.
| 수집 시나리오 | FPS | 평균 ms | p95 ms | 평균 Draw Call | 평균 삼각형 | 텍스처(종료) | geometry(종료) | 50ms 초과 |
|---|---:|---:|---:|---:|---:|---:|---:|---:|
| 정지·강제 연속 렌더 | 119.85 | 8.34 | 8.40 | 49.00 | 1,802,718 | 28 | 117 | 0 |
| 360° 회전 | 119.95 | 8.34 | 8.40 | 32.35 | 1,748,428 | 28 | 117 | 0 |
| 왕복 이동 | 99.30 | 10.07 | 16.70 | 47.35 | 1,800,092 | 25 | 45 | 0 |
| 과천 방향 왕복 | 112.35 | 8.90 | 16.60 | 22.00 | 1,744,875 | 28 | 117 | 0 |
| 변경 후 동일 조건 | 미측정 | 미측정 | 미측정 | 미측정 | 미측정 | 미측정 | 미측정 | 미측정 |
| 5분 지속 | 중단 | — | — | — | — | — | — | — |
모든 표본은 CSS 412×915, 강제 DPR 2(내부 824×1830, 1,507,920픽셀), PC Chromium이다. 실기기 검증이 아니다. 단일 실행 결과이며 반복 측정 신뢰구간이 없다. 일반 장면의 원래 렌더링/재질/그림자/이동 설정은 이 작업에서 변경하지 않았다.
## 구현 파일과 실험 방법
- `src/dev/renderProfile.ts`: DEV 전용 패널·시나리오·원시 JSON. `stop` 버튼으로 중단 가능하며 탭이 숨겨지면 실행을 취소한다.
- `src/scene/world.ts`, `src/main.ts`: DEV 계측 연결, 비교용 날짜·날씨 고정, 전체 후처리 카운트 합산. 일반 사용자의 시각·날씨 동작은 유지한다. 다른 작업의 지형 변경을 보존했다.
- `src/scene/frameSummary.ts`: 평균/FPS/p95/지연 프레임 계산.
- `src/scene/adaptiveResolution.ts`, `src/constants/renderQuality.ts`: 개발 실험용 자동 해상도. `/?profile&quality=adaptive`로 명시적으로 켠다. DPR 상한 1.5, 실제 픽셀 예산 150만, 하한 단계 0.75. 기기 native DPR도 넘지 않는다.
- 고정 `dpr`를 지정하면 자동 조절보다 우선한다. 자동 조절은 5초 관측창, p95 34ms 초과 하향, p95 22ms 미만·평균 19ms 미만이 4개 창 동안 유지될 때 상향, 초기/변경/복귀/텍스처 로딩 후 10초 안정화 시간을 사용한다. 정지 렌더 생략 구간은 연속 프레임 근거로 사용하지 않는다.
- 자동 조절은 렌더 해상도만 바꾸고 시뮬레이션 delta나 이동·회전·태양 계산을 변경하지 않는다. 실제 성능 효과와 화질 검증 전이므로 **production에서 활성화하지 않는다**.
- `src/vite-env.d.ts`: Vite DEV 플래그 타입.
- `tests/render-performance.test.ts`, `tests/adaptive-resolution.test.ts`: 통계와 조절 임계값/복귀/픽셀 상한 검증.
## 검증 및 남은 일
- `npm test`: 최종 69개 통과. 처음 발생한 로컬 HTTP EACCES는 권한이 허용된 실행에서 재검증하여 통과했다.
- `npm run build`: 입력 자산 freshness 검사, TypeScript, production 빌드 통과. 번들 크기 경고는 남는다. production 번들에서 DEV 패널/결과 로그 문자열이 제외됨을 확인했다.
- `npm run verify:solar`: 기존 SunCalc/NOAA 허용 오차 이내. 물리적 실측이 아닌 계산 대조다.
- Android 중급 실기기, Safari, 터치 입력, 일반 브라우저 Pointer Lock, 전후 시각 비교 스크린샷: 미검증.
- 5분 연속 테스트: 사용자 요청으로 중단, 통과 처리하지 않음.
- 현재 과천 방향은 능선 때문에 실제 건물 밀집 부하를 대표하지 않을 수 있다. 재측정 때 구조물 밀집 시점이나 별도 도시 조감 시나리오를 추가 선정해야 한다.
- 동일 소스 스냅샷에서 DPR 2/1.5/1.25와 후처리 분리 실험 → 화질 비교 → 효과 있는 설정만 production에 적용 → 실제 기기 검증 순서로 이어간다. 이 작업에서 LOD/Instancing/KTX2/그림자 변경은 도입하지 않았다.
- 독립 코드 리뷰의 3건을 수정했다: 새 자동 화질 실험마다 초기 상한 복원, inventory 수집을 준비 시간으로 이동, 화면 resize 시 실행 취소. 이전 수집 JSON에는 첫 측정 프레임 inventory 비용도 일부 포함될 수 있으므로 최종 비교용이 아닌 임시 관찰 자료로만 보존한다. 수정 후 브라우저 재측정은 사용자 부하 제한에 따라 미실시했다.