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

Three.js调用同一函数创建2个球体后如何区分并控制指定球体移动

问题根源

  • 你代码里的center、mesh_felii变量没有加let/const声明,默认成为全局变量,第二次调用createSphere函数时会直接覆盖第一次的center值,所以你目前只能操作到最后一次创建的球体。
  • 你传入的sphere_name参数没有被实际使用,没有给不同球体设置唯一标识用来区分。
  • 你当前生成的球体分片网格都是直接添加到场景中,没有挂载到center下,就算你能拿到之前的center实例,移动center时分片也不会跟着移动,这是隐藏的逻辑问题。

解决方法

第一步:修改函数逻辑,存储球体实例

先在全局作用域声明一个用来存储所有球体实例的映射表,同时修改createSphere函数,给变量加声明、把分片挂载到center下、用sphere_name作为唯一标识存储实例:

// 全局作用域声明,用来存储所有球体实例
const spheres = {}
// 注意:你原代码里的全局变量materialeDeAratat如果要多次调用函数,建议按需重置,这里先保留原逻辑

function createSphere(
  sphere_name,
  radius,
  wSegments,
  hSegments,
  surface_map,
  xPos,
  yPos,
  zPos
) {
  let geometry1 = new THREE.SphereGeometry(radius, wSegments, hSegments);
  let material1 = new THREE.MeshLambertMaterial({ map: surface_map });
  // 加let声明,避免成为全局变量
  let center = new THREE.Mesh(geometry1, material1);
  center.position.set(xPos, yPos, zPos);
  // 给实例设置name属性,方便后续查找
  center.name = sphere_name;

  let materialsToMap = 1;

  for (let i = 10; i < 630; i += 62.8) {
    for (let k = 70; k < 215; k += 45) {
      let j = i / 100;
      let l = k / 100;
      let geometry = new THREE.SphereGeometry(radius, 16, 16, j, 0.62, l, 0.44);
      let material = new THREE.MeshLambertMaterial({
        map: materiale[materialsToMap],
        transparent: true,
        opacity: 0.8,
      });
      // 加let声明,避免全局污染
      let mesh_felii = new THREE.Mesh(geometry, material);
      // 子元素相对于父级center定位,直接设为0即可
      mesh_felii.position.set(0,0,0);
      mesh_felii.userData = linkuri[materialeDeAratat];
      mesh_felii.layers.set(1);
      // 挂载到center下,移动center时所有分片会同步移动
      center.add(mesh_felii);
      materialeDeAratat++;
      if (materialeDeAratat >= materiale.length) materialeDeAratat = 1;
    }
  }
  // 把当前球体实例存入全局映射表
  spheres[sphere_name] = center;
  scene.add(center);
  return center;
}

第二步:调用函数时传入唯一名称

创建球体时给每个球体传入唯一的sphere_name:

// 示例:创建两个球体,分别命名为sphere1和sphere2
createSphere('sphere1', 5, 32, 32, surfaceMap1, -10, 0, 0);
createSphere('sphere2', 5, 32, 32, surfaceMap2, 10, 0, 0);

第三步:通过名称指定要移动的球体

滑块触发事件时,直接通过名称从映射表中取对应实例修改位置即可:

// 假设控制第一个球体的滑块id为sphere1Slider
document.querySelector('#sphere1Slider').addEventListener('input', e => {
  // 直接通过名称获取对应球体,修改x坐标
  spheres.sphere1.position.x = Number(e.target.value);
})

// 控制第二个球体就改为spheres.sphere2.position.x

替代方案

如果你不想用全局映射表,也可以直接用Three.js内置的getObjectByName方法从场景中查找对应实例:

const targetSphere = scene.getObjectByName('sphere1');
if (targetSphere) {
  targetSphere.position.x = 滑块值;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.17 11:45:11