Repository navigation
3D 파이프라인 최적화 - gltf, 렌더 루프·화면 텍스처 정비 - #93
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
641d890 to
460df49
Compare
460df49 to
91fd5ae
Compare
- Draco→Meshopt 전환 + 임베디드 텍스처 WebP화 스크립트(프롭 공격적/캐릭터 보수적 변환 분리) - 주범이던 4K fabric roughness(15.7MB)를 1024 WebP로, character.glb 32MB→4.6MB - ORM PNG는 near-lossless WebP(채널 번짐 방지), 원본은 assets-src/에 백업(inspect 베이스라인 포함) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- 모델 경로 상수화(.v2 버전 규칙) + Draco 디코더 self-host로 gstatic CDN 의존 제거, Preload로 셰이더 선컴파일 - 노트북 화면 CanvasTexture: DPR 슈퍼샘플링, body 실폰트+fonts.ready 재드로우, renderer 이방성 주입 - 비가시(스크롤 밖/백그라운드 탭) 시 frameloop 정지, 그림자 frustum 타이트닝, 아웃라인 composer MSAA 복원 - /models·/textures·/decoders에 immutable 캐시 헤더 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
91fd5ae to
b076843
Compare
초판을 a2cfed7(#93 이전)에서 측정하는 바람에 이미 해결된 문제를 다뤘다. origin/main 기준으로 재측정하고 살아남은 것만 남긴다. #93이 끝낸 것(에셋 48MB→9.6MB, Meshopt 전환, .vN + immutable 캐시, RenderWhenVisible, 디코더 self-host)은 "이미 해결됨" 표로 기록해 다음에 같은 분석을 반복하지 않게 한다. 남은 건 VRAM이다. WebP는 파일만 줄이고 GPU에는 RGBA8로 올라가므로 해상도가 그대로인 한 VRAM은 안 줄어든다 — 파일은 5배 줄었는데 VRAM은 714MB→380MB로 1.9배뿐이다. 그래서 목표를 파일 크기에서 VRAM으로 바꿨다. - 죽은 roughness 텍스처가 아직 임베드돼 있다. #93은 압축만 하고 제거하지 않았다. 파일로는 1.2MB지만 VRAM으로는 90MB다. - KTX2 미도입이 나머지 238MB의 원인. 브랜치를 6개에서 3개로 줄였다. 셋 다 파일이 겹치지 않아 병합 순서도 무관하다. 04(믹서 가드) 지시서에는 #93의 RenderWhenVisible이 재현을 가린다는 점과, delta 클램프를 지우면 안 되는 이유를 추가했다. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
`SceneAssetPreloader`가 루트 레이아웃에 있어 `/articles`, `/resume`, `/project`, `/guest`, admin 등 3D를 전혀 렌더하지 않는 모든 라우트가 씬 GLB를 통째로 받고 있었다. #93·#95가 총량을 크게 줄였지만 안 쓰는 페이지에서는 여전히 100% 낭비다. 3D 진입점은 `HomeHeroScene`과 `ContactScene` 둘뿐이고 둘 다 `views/home`의 `HomePage`가 유일한 부모다. 그래서 후보는 셋이었고, 그중 홈 뷰 안은 함정이다 — `HomePage`는 `getHomePageData`(Supabase storage 조회)를 await 한 뒤에야 렌더되고 `(home)/loading.tsx`가 그 세그먼트에 Suspense 경계를 만든다. 프리페치를 거기 두면 데이터 조회를 통째로 기다린다. 비3D 라우트에서 아끼려다 홈 진입을 느리게 만드는 셈이다. 홈 데이터 조회에 3초 지연을 주입하고 첫 GLB 요청 시각을 측정했다(dev, 배치별로 서버를 새로 띄워 각 3회): | 프리페처 위치 | 첫 GLB 요청 | 데이터 조회를 기다리는가 | | --- | --- | --- | | `app/layout.tsx` (변경 전) | 151 / 192 / 149 ms | 아니오 | | `(home)/layout.tsx` (채택) | 782 / 1115 / 805 ms | 아니오 | | `HomePage` 안 | 3159 / 3783 / 3567 ms | 예 | 레이아웃은 페이지 세그먼트의 대기와 무관하게 먼저 스트리밍되므로 데이터 조회와 GLB를 병렬로 받는다. 루트 레이아웃보다 ≈650ms 늦는 건 데이터 의존이 아니라 해당 세그먼트 청크의 로드·하이드레이트 순서 차이고, dev 세그먼트별 컴파일이 섞인 값이라 프로덕션에서는 더 줄어든다. 라우트 범위를 좁힌 대가로 감수한다. `requestIdleCallback` 지연은 넣지 않았다. 홈의 첫 화면이 히어로 3D 씬 자체라 GLB는 초기 페인트의 경쟁자가 아니라 그 화면을 그리는 자원이다. `layout.tsx`의 `import React`는 계약 테스트가 렌더하기 위해서다. tsconfig가 `jsx: preserve`라 vitest의 esbuild는 classic 런타임으로 변환한다.
`SceneAssetPreloader`가 루트 레이아웃에 있어 `/articles`, `/resume`, `/project`, `/guest`, admin 등 3D를 전혀 렌더하지 않는 모든 라우트가 씬 GLB를 통째로 받고 있었다. #93·#95가 총량을 크게 줄였지만 안 쓰는 페이지에서는 여전히 100% 낭비다. 3D 진입점은 `HomeHeroScene`과 `ContactScene` 둘뿐이고 둘 다 `views/home`의 `HomePage`가 유일한 부모다. 그래서 후보는 셋이었고, 그중 홈 뷰 안은 함정이다 — `HomePage`는 `getHomePageData`(Supabase storage 조회)를 await 한 뒤에야 렌더되고 `(home)/loading.tsx`가 그 세그먼트에 Suspense 경계를 만든다. 프리페치를 거기 두면 데이터 조회를 통째로 기다린다. 비3D 라우트에서 아끼려다 홈 진입을 느리게 만드는 셈이다. 홈 데이터 조회에 3초 지연을 주입하고 첫 GLB 요청 시각을 측정했다(dev, 배치별로 서버를 새로 띄워 각 3회): | 프리페처 위치 | 첫 GLB 요청 | 데이터 조회를 기다리는가 | | --- | --- | --- | | `app/layout.tsx` (변경 전) | 151 / 192 / 149 ms | 아니오 | | `(home)/layout.tsx` (채택) | 782 / 1115 / 805 ms | 아니오 | | `HomePage` 안 | 3159 / 3783 / 3567 ms | 예 | 레이아웃은 페이지 세그먼트의 대기와 무관하게 먼저 스트리밍되므로 데이터 조회와 GLB를 병렬로 받는다. 루트 레이아웃보다 ≈650ms 늦는 건 데이터 의존이 아니라 해당 세그먼트 청크의 로드·하이드레이트 순서 차이고, dev 세그먼트별 컴파일이 섞인 값이라 프로덕션에서는 더 줄어든다. 라우트 범위를 좁힌 대가로 감수한다. `requestIdleCallback` 지연은 넣지 않았다. 홈의 첫 화면이 히어로 3D 씬 자체라 GLB는 초기 페인트의 경쟁자가 아니라 그 화면을 그리는 자원이다. `layout.tsx`의 `import React`는 계약 테스트가 렌더하기 위해서다. tsconfig가 `jsx: preserve`라 vitest의 esbuild는 classic 런타임으로 변환한다.
`SceneAssetPreloader`가 루트 레이아웃에 있어 `/articles`, `/resume`, `/project`, `/guest`, admin 등 3D를 전혀 렌더하지 않는 모든 라우트가 씬 GLB를 통째로 받고 있었다. #93·#95가 총량을 크게 줄였지만 안 쓰는 페이지에서는 여전히 100% 낭비다. 3D 진입점은 `HomeHeroScene`과 `ContactScene` 둘뿐이고 둘 다 `views/home`의 `HomePage`가 유일한 부모다. 그래서 후보는 셋이었고, 그중 홈 뷰 안은 함정이다 — `HomePage`는 `getHomePageData`(Supabase storage 조회)를 await 한 뒤에야 렌더되고 `(home)/loading.tsx`가 그 세그먼트에 Suspense 경계를 만든다. 프리페치를 거기 두면 데이터 조회를 통째로 기다린다. 비3D 라우트에서 아끼려다 홈 진입을 느리게 만드는 셈이다. 홈 데이터 조회에 3초 지연을 주입하고 첫 GLB 요청 시각을 측정했다(dev, 배치별로 서버를 새로 띄워 각 3회): | 프리페처 위치 | 첫 GLB 요청 | 데이터 조회를 기다리는가 | | --- | --- | --- | | `app/layout.tsx` (변경 전) | 151 / 192 / 149 ms | 아니오 | | `(home)/layout.tsx` (채택) | 782 / 1115 / 805 ms | 아니오 | | `HomePage` 안 | 3159 / 3783 / 3567 ms | 예 | 레이아웃은 페이지 세그먼트의 대기와 무관하게 먼저 스트리밍되므로 데이터 조회와 GLB를 병렬로 받는다. 루트 레이아웃보다 ≈650ms 늦는 건 데이터 의존이 아니라 해당 세그먼트 청크의 로드·하이드레이트 순서 차이고, dev 세그먼트별 컴파일이 섞인 값이라 프로덕션에서는 더 줄어든다. 라우트 범위를 좁힌 대가로 감수한다. `requestIdleCallback` 지연은 넣지 않았다. 홈의 첫 화면이 히어로 3D 씬 자체라 GLB는 초기 페인트의 경쟁자가 아니라 그 화면을 그리는 자원이다. `layout.tsx`의 `import React`는 계약 테스트가 렌더하기 위해서다. tsconfig가 `jsx: preserve`라 vitest의 esbuild는 classic 런타임으로 변환한다.
작업 내용
1. 에셋 빌드 파이프라인 (gltf-transform) — 다운로드 47.9MB → 9.6MB
scripts/optimize-models.mjs/optimize-textures.mjs추가 (pnpm optimize:models|textures)assets-src/에 백업 (inspect 베이스라인 포함)2. 로더·캐싱
.v2파일명 버전 규칙,/models·/textures·/decoders에Cache-Control: immutable(재방문 시 재검증 요청 0)<Preload all />— 셰이더 컴파일/텍스처 업로드를 첫 가시화 전 완료3. 렌더 루프
<RenderWhenVisible />신규: IntersectionObserver + visibilitychange로 화면 밖/백그라운드 탭에서 frameloop 정지 (OR로 정지, AND로 재개). 히어로를 보는 동안 하단 연락처 캔버스가 60fps로 돌던 문제 해소4. 노트북 화면 텍스처 (CanvasTexture 유지 + 품질 개선)
document.fonts.ready후 재드로우 (폴백 선렌더로 빈 화면 없음)<video>→ THREE.VideoTexture를 동일 심(applyCharacterScreenTexture)에 무변경 삽입 가능