33 * 使用 THREE.Points + AdditiveBlending 实现高性能粒子渲染
44 *
55 * @ai -context: 3D 场景对象:ParticleSystem。
6+ * @ai -context: P3-15 降更新频率——按 tier 跳帧更新(high 每帧/medium 隔 1/low 隔 2),
7+ * 水平漂移基于绝对时钟相位(跳帧仍平滑),增量位移乘以 step 补偿以保持运动速度一致。
68 */
79import { useRef , useMemo } from 'react' ;
810import { useFrame } from '@react-three/fiber' ;
@@ -25,10 +27,14 @@ export function ParticleSystem({
2527 speed = 1 ,
2628} : ParticleSystemProps ) {
2729 const pointsRef = useRef < THREE . Points > ( null ) ;
30+ // P3-15 跳帧计数器
31+ const frameRef = useRef ( 0 ) ;
2832 // 有效 tier(自动 tier 受用户性能模式上限约束)
2933 const tier = useEffectiveTier ( ) ;
3034
3135 const particleCount = tier === 'low' ? 500 : tier === 'medium' ? 1200 : count ;
36+ // 更新频率分档:high 每帧、medium 隔 1 帧、low 隔 2 帧(粒子运动缓慢,跳帧视觉无感)
37+ const frameSkip = tier === 'low' ? 3 : tier === 'medium' ? 2 : 1 ;
3238
3339 const { positions, velocities, colors, sizes } = useMemo ( ( ) => {
3440 const pos = new Float32Array ( particleCount * 3 ) ;
@@ -67,19 +73,24 @@ export function ParticleSystem({
6773
6874 useFrame ( ( { clock } ) => {
6975 if ( ! pointsRef . current ) return ;
76+ // P3-15 跳帧:非更新帧直接返回,减少 sin/cos 逐粒子计算开销
77+ frameRef . current += 1 ;
78+ if ( frameRef . current % frameSkip !== 0 ) return ;
79+ const step = frameSkip ; // 补偿跳过帧,保持运动速度一致
80+
7081 const posAttr = pointsRef . current . geometry . attributes . position as THREE . BufferAttribute ;
7182 const posArray = posAttr . array as Float32Array ;
7283 const time = clock . getElapsedTime ( ) ;
7384
7485 for ( let i = 0 ; i < particleCount ; i ++ ) {
7586 const i3 = i * 3 ;
7687
77- // Horizontal drift using sin/cos
78- posArray [ i3 ] += Math . sin ( time * 0.5 + i * 0.1 ) * velocities [ i3 ] * speed * 0.001 ;
79- posArray [ i3 + 2 ] += Math . cos ( time * 0.4 + i * 0.1 ) * velocities [ i3 + 2 ] * speed * 0.001 ;
88+ // Horizontal drift using sin/cos(基于绝对时钟相位,跳帧仍平滑)
89+ posArray [ i3 ] += Math . sin ( time * 0.5 + i * 0.1 ) * velocities [ i3 ] * speed * 0.001 * step ;
90+ posArray [ i3 + 2 ] += Math . cos ( time * 0.4 + i * 0.1 ) * velocities [ i3 + 2 ] * speed * 0.001 * step ;
8091
8192 // Float upward
82- posArray [ i3 + 1 ] += velocities [ i3 + 1 ] * speed ;
93+ posArray [ i3 + 1 ] += velocities [ i3 + 1 ] * speed * step ;
8394
8495 // Reset particle to bottom when reaching top
8596 if ( posArray [ i3 + 1 ] > bounds . y [ 1 ] ) {
0 commit comments