44 * 但仍低于所有 UI 浮层(标题栏 z-50 / FunctionalOverlay z-10 / 引导 z-40+)。
55 * 注意:不能用负 z-index,否则会落到根 div 之后被其透明盒拦截点击。
66 *
7+ * 帧循环策略(性能优化核心):
8+ * - 概览态(!isInModule):frameloop=always 全帧渲染(可交互);
9+ * - 模块态(isInModule,3D 被遗罩覆盖):按性能模式降帧/暂停——
10+ * 静谧(low)=never 暂停、从容(medium)=demand 10fps、澎湃(high)=demand 30fps,
11+ * 避免 3D 在不可见时仍全帧渲染(持续开销最大头)。
12+ * - 模块态不渲染 PerformanceMonitor:降帧后的 FPS 是人为限制值,
13+ * 若用于测量会被误判为性能恶化而降级 tier。
14+ *
715 * @ai -context: 3D 场景核心(R3F):SceneProvider。
816 */
9- import { Canvas } from '@react-three/fiber' ;
10- import { Suspense } from 'react' ;
17+ import { Canvas , useThree } from '@react-three/fiber' ;
18+ import { Suspense , useEffect } from 'react' ;
1119import { Preload } from '@react-three/drei' ;
1220import { PerformanceMonitor } from './PerformanceMonitor' ;
1321import { QualityController } from './QualityController' ;
1422import { MemoryManager } from './MemoryManager' ;
1523import { ContextRecovery } from './ContextRecovery' ;
24+ import { useOrbitalStore } from '../navigation/OrbitalStore' ;
25+ import { usePerformanceModeStore } from '@/lib/performance/usePerformanceMode' ;
26+ import { PERFORMANCE_MODE_CONFIG } from '@/lib/performance/performanceMode' ;
1627import * as THREE from 'three' ;
1728
1829interface SceneProviderProps {
@@ -21,10 +32,33 @@ interface SceneProviderProps {
2132 interactive ?: boolean ;
2233}
2334
35+ /** 模块态降帧 ticker:demand 模式下按目标帧率触发渲染(invalidate) */
36+ function ModuleFpsTicker ( { fps } : { fps : number } ) {
37+ const invalidate = useThree ( ( s ) => s . invalidate ) ;
38+ useEffect ( ( ) => {
39+ if ( fps <= 0 ) return ; // 暂停档:不触发渲染
40+ const id = setInterval ( ( ) => invalidate ( ) , 1000 / fps ) ;
41+ return ( ) => clearInterval ( id ) ;
42+ } , [ fps , invalidate ] ) ;
43+ return null ;
44+ }
45+
2446export function SceneProvider ( { children, interactive = false } : SceneProviderProps ) {
47+ const isInModule = useOrbitalStore ( ( s ) => s . isInModule ) ;
48+ const mode = usePerformanceModeStore ( ( s ) => s . mode ) ;
49+ const moduleFps = PERFORMANCE_MODE_CONFIG [ mode ] . moduleFps ;
50+
51+ // 帧循环策略:概览态全帧;模块态按档位降帧/暂停
52+ const frameloop : 'always' | 'demand' | 'never' = ! isInModule
53+ ? 'always'
54+ : moduleFps === 0
55+ ? 'never'
56+ : 'demand' ;
57+
2558 return (
2659 < div className = "fixed inset-0 z-0" style = { { pointerEvents : interactive ? 'auto' : 'none' } } >
2760 < Canvas
61+ frameloop = { frameloop }
2862 gl = { {
2963 antialias : true ,
3064 alpha : true ,
@@ -49,7 +83,10 @@ export function SceneProvider({ children, interactive = false }: SceneProviderPr
4983 console . info ( '[3D] WebGL renderer:' , rendererName ) ;
5084 } }
5185 >
52- < PerformanceMonitor />
86+ { /* 模块态降帧 ticker(仅 demand 模式) */ }
87+ { frameloop === 'demand' && < ModuleFpsTicker fps = { moduleFps } /> }
88+ { /* FPS 自动降档仅在概览态测量(模块态帧率被人为限制,不可作为性能依据) */ }
89+ { ! isInModule && < PerformanceMonitor /> }
5390 < QualityController />
5491 < MemoryManager />
5592 < ContextRecovery />
0 commit comments