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

关于采用Particle Shader Raycast实现粒子鼠标交互效果的技术咨询

嘿,这个需求我太熟了!直接修改几何体顶点确实会有生硬感——毕竟每次鼠标交互都要更新CPU端的顶点数据,不仅卡顿,过渡也不自然。用Shader来实现绝对是正确的方向,全程GPU处理,流畅度和效果都会提升一大截。我给你详细拆解下实现思路和关键步骤:

核心原理

Shader方案的核心是在GPU端为每个顶点/粒子实时计算与鼠标的交互偏移,不需要修改CPU端的几何体数据。通过传递鼠标的世界空间坐标到Shader,让每个顶点根据自身与鼠标的距离,平滑地调整位置(或大小、透明度),实现自然的“推开”效果。

具体实现步骤

1. 把鼠标坐标转换成世界空间坐标

Shader需要的是鼠标在3D场景中的位置,而不是屏幕像素坐标。以Three.js为例,你可以通过射线检测把鼠标的屏幕坐标转成场景中的世界坐标:

  • 先将屏幕坐标转为NDC(归一化设备坐标,范围-1到1)
  • 用射线与场景中的某个平面(比如地面或几何体所在平面)相交,得到鼠标的世界位置
  • 把这个位置通过uniform变量传递给Shader

2. 在顶点着色器中实现平滑偏移逻辑

这是效果自然的关键,我们要用平滑的距离衰减函数代替生硬的射线命中判断:

  • 计算当前顶点到鼠标世界位置的距离
  • 用smoothstep函数生成一个平滑的偏移因子:距离鼠标越近,因子越大;超过设定的作用半径后,因子归零
  • 根据偏移因子计算顶点的偏移方向(推开的话就是从鼠标指向顶点的反方向),并应用到顶点位置上

3. 绑定鼠标交互事件

在鼠标移动(或按下)事件中,实时更新Shader中的鼠标位置uniform,让效果跟随鼠标动态变化。

关键代码示例

顶点着色器(以Three.js的Points材质为例)

// 从JS传递的uniform变量
uniform vec3 mouseWorldPos;
uniform float pushStrength; // 推开的力度
uniform float pushRadius;   // 生效的半径

void main() {
    // 计算顶点与鼠标的距离
    float distToMouse = distance(position, mouseWorldPos);
    
    // 生成平滑的偏移因子:在0到pushRadius之间从1衰减到0
    float pushFactor = smoothstep(pushRadius, 0.0, distToMouse);
    
    // 计算推开方向:从鼠标指向顶点的反方向
    vec3 pushDir = normalize(position - mouseWorldPos);
    // 应用偏移
    vec3 transformedPos = position + pushDir * pushFactor * pushStrength;
    
    // 常规顶点着色器流程
    gl_Position = projectionMatrix * modelViewMatrix * vec4(transformedPos, 1.0);
    // 可选:让粒子大小随距离变化,增强效果
    gl_PointSize = 2.0 + pushFactor * 3.0;
}

JS端鼠标坐标转换与uniform更新

// 初始化变量
const raycaster = new THREE.Raycaster();
const mouse = new THREE.Vector2();
const plane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0); // 假设场景平面是z=0
const intersectionPoint = new THREE.Vector3();

// 鼠标移动事件
function handleMouseMove(event) {
    // 转成NDC坐标
    mouse.x = (event.clientX / window.innerWidth) * 2 - 1;
    mouse.y = -(event.clientY / window.innerHeight) * 2 + 1;
    
    // 计算鼠标在场景中的世界位置
    raycaster.setFromCamera(mouse, camera);
    raycaster.ray.intersectPlane(plane, intersectionPoint);
    
    // 更新Shader的uniform变量
    yourMaterial.uniforms.mouseWorldPos.value.copy(intersectionPoint);
}

// 绑定事件
window.addEventListener('mousemove', handleMouseMove);
效果优化建议
  • 平滑过渡:可以给pushFactor加上幂运算(比如pow(pushFactor, 2.0)),让衰减曲线更平缓,避免边缘突兀
  • 性能提升:如果是大量粒子,优先使用InstancedMesh或Points材质,GPU并行处理的性能远优于CPU修改顶点
  • 动态效果:可以给pushStrength加一个随时间衰减的动画,让推开的效果有“回弹”感,更接近你参考的网站效果
  • 多交互支持:如果需要触摸设备适配,只需把鼠标事件换成触摸事件,坐标转换逻辑一致

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:49:00