Three.js导入FBX模型组子网格实现鼠标悬停磁吸跟随效果咨询
Three.js 光标磁吸效果实现方案
1. 正确获取光标对应的世界坐标系位置
你当前的坐标计算逻辑仅适用于相机沿Z轴正对场景、所有物体均处于Z=0平面的特定场景,参数稍有变化就会出现坐标数值异常的问题。推荐使用Three.js内置的Raycaster(射线投射器)实现通用坐标获取,计算更稳定准确:
// 提前声明公用变量 const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); // 如果你所有网格都在Z=0平面,提前定义检测平面,性能更高 const targetPlane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0); const worldMousePos = new THREE.Vector3(); function onMouseMove(event) { // 计算标准化设备坐标 (-1 到 1 区间) mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; // 更新射线 raycaster.setFromCamera(mouse, camera); // 求射线和目标平面的交点 raycaster.ray.intersectPlane(targetPlane, worldMousePos); // 此时worldMousePos就是光标在目标平面上的准确世界坐标 console.log(worldMousePos); }
如果你的模型组不在Z=0平面,修改targetPlane的参数匹配你的模型所在平面即可。
2. 实现网格磁吸平移效果
要实现类似导航项的弹性磁吸效果,需要先存储每个网格的初始位置,再在渲染循环中做插值缓动,避免直接修改位置导致的生硬感:
修改后的完整逻辑:
// 新增:存储所有可动网格的初始位置 const meshes = []; // Load object and play a third-party animation loader.load("Object_001.fbx", (object) => { mixer = new THREE.AnimationMixer(object); const action = mixer.clipAction(object.animations[0]); action.play(); object.traverse((child) => { if (child.isMesh) { child.material.map = texture; child.material.needsUpdate = true; // 存储网格和它的初始位置 meshes.push({ mesh: child, originPos: child.position.clone() }); } }); scene.add(object); }); // 射线相关变量 const raycaster = new THREE.Raycaster(); const mouse = new THREE.Vector2(); const targetPlane = new THREE.Plane(new THREE.Vector3(0, 0, 1), 0); const worldMousePos = new THREE.Vector3(); // 磁吸强度参数,数值越大响应越快、缓动效果越弱 const magnetForce = 0.12; // 最大磁吸偏移距离,避免网格移动过远 const maxOffset = 2; function onMouseMove(event) { mouse.x = (event.clientX / window.innerWidth) * 2 - 1; mouse.y = -(event.clientY / window.innerHeight) * 2 + 1; raycaster.setFromCamera(mouse, camera); raycaster.ray.intersectPlane(targetPlane, worldMousePos); } wrapperElement.addEventListener("mousemove", onMouseMove); // 新增:在你的渲染循环中更新网格位置 function animate() { requestAnimationFrame(animate); // 更新每个网格的位置 meshes.forEach(item => { // 计算目标位置:初始位置 + 指向光标位置的偏移,限制最大偏移量 const targetX = item.originPos.x + THREE.MathUtils.clamp(worldMousePos.x - item.originPos.x, -maxOffset, maxOffset); const targetY = item.originPos.y + THREE.MathUtils.clamp(worldMousePos.y - item.originPos.y, -maxOffset, maxOffset); // 线性插值实现缓动效果 item.mesh.position.x += (targetX - item.mesh.position.x) * magnetForce; item.mesh.position.y += (targetY - item.mesh.position.y) * magnetForce; }); // 原有逻辑:更新动画混合器、渲染场景等 if (mixer) mixer.update(clock.getDelta()); renderer.render(scene, camera); } animate();
你可以根据实际效果调整magnetForce和maxOffset两个参数,匹配你需要的磁吸强度和移动范围。如果需要不同网格有不同的磁吸效果,也可以给每个网格单独配置这两个参数。
内容的提问来源于stack exchange,提问作者Lazouski
相关产品推荐
相关产品推荐

