You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在React Three Fiber中实现粒子气泡物理效果?是否需自定义顶点着色器?

React Three Fiber粒子鼠标交互实现方案

核心结论

是的,要实现这种鼠标靠近粒子时反向移动、远离时回归的气泡效果,必须用到自定义顶点着色器——因为这种基于粒子与鼠标距离的实时位置偏移计算,没法用Three.js内置材质或组件直接实现,需要在GPU层面逐顶点处理交互逻辑。

实现思路拆解

  • 传递鼠标位置到着色器:在React Three Fiber中,通过useFrame钩子实时获取鼠标的归一化坐标(或世界坐标),并将其作为uniform变量传递给着色器。
  • 顶点着色器中计算偏移:
    1. 保存粒子初始位置:在几何体的attributes里添加initialPosition属性,初始化时复制顶点原始位置。
    2. 计算距离与偏移:算出每个粒子到鼠标的距离,距离越近偏移幅度越大,方向与鼠标指向粒子的方向相反。
    3. 加入缓动效果:用mix函数或简单弹簧公式,让粒子回归原位时呈现气泡般的平滑运动。
  • CPU辅助优化(可选):如果粒子数量极大,可在CPU端先筛选鼠标附近的粒子,只对这些粒子传递偏移数据,减少GPU计算压力,基础实现用纯着色器即可。

简化代码示例(核心部分)

自定义着色器材质

import { useRef, useFrame } from '@react-three/fiber'
import { Points, BufferGeometry } from 'three'

function BubbleParticles() {
  const meshRef = useRef()
  const mouse = useRef([0, 0])

  // 实时更新鼠标位置
  useFrame((state) => {
    mouse.current = [state.mouse.x, state.mouse.y]
    if (meshRef.current) {
      meshRef.current.material.uniforms.uMouse.value.set(mouse.current[0], mouse.current[1], 0)
      meshRef.current.material.uniforms.uTime.value = state.clock.getElapsedTime()
    }
  })

  // 创建几何体并添加初始位置属性
  const positions = []
  for (let i = 0; i < 1000; i++) {
    positions.push(Math.random() * 10 - 5, Math.random() * 10 - 5, Math.random() * 10 - 5)
  }
  const geometry = new BufferGeometry()
  geometry.setAttribute('position', new Float32BufferAttribute(positions, 3))
  geometry.setAttribute('initialPosition', geometry.attributes.position.clone())

  return (
    <Points ref={meshRef}>
      <shaderMaterial
        uniforms={{
          uMouse: { value: new THREE.Vector3() },
          uTime: { value: 0 },
          uStrength: { value: 2 }, // 控制偏移强度
          uMaxDistance: { value: 3 } // 鼠标影响的最大距离
        }}
        vertexShader={`
          attribute vec3 initialPosition;
          uniform vec3 uMouse;
          uniform float uTime;
          uniform float uStrength;
          uniform float uMaxDistance;

          void main() {
            // 计算粒子到鼠标的向量与距离
            vec3 toMouse = uMouse - initialPosition;
            float distance = length(toMouse);
            
            // 根据距离计算偏移量,超出最大距离则无偏移
            float influence = smoothstep(uMaxDistance, 0.0, distance);
            vec3 offset = normalize(-toMouse) * uStrength * influence;
            
            // 加入弹性回归效果,模拟气泡回弹
            vec3 finalPosition = mix(initialPosition + offset, initialPosition, pow(influence, 0.3));
            
            gl_Position = projectionMatrix * modelViewMatrix * vec4(finalPosition, 1.0);
            gl_PointSize = 2.0;
          }
        `}
        fragmentShader={`
          void main() {
            gl_FragColor = vec4(0.2, 0.6, 1.0, 0.8);
          }
        `}
      />
    </Points>
  )
}

关键注意点

  • 鼠标坐标要和粒子处于同一空间:示例用归一化坐标,若粒子在世界空间,需将鼠标坐标转换为世界坐标。
  • 调整uStrength和uMaxDistance可控制气泡效果的灵敏度和影响范围。
  • 若要更真实的物理感,可在顶点着色器中加入弹簧公式(如F = -k*x),结合时间变量计算速度和位置。

内容的提问来源于stack exchange,提问作者Felipe Oliveira

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.05 03:37:47