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

Three.js中如何定时或点击触发替换立方体为球体几何体

Three.js 几何体切换失效解决方案

失效核心原因

  • 你自定义的movingObject对象单独存了一份初始立方体几何体的引用,替换Mesh上的geometry属性后,没有同步更新这个引用,后续动画逻辑仍然关联旧几何体
  • 注释里遍历geometry.vertices修改顶点的写法只适配r125之前的旧版Three.js,当前版本用的是BufferGeometry,没有直接暴露的vertices数组,这套写法本身就跑不起来
  • 部分Three.js版本下替换几何体后需要手动标记更新,否则渲染层会沿用旧的缓存资源,看起来就像修改没生效

具体实现步骤

  • 提前实例化需要切换的球体几何体,避免每次触发切换都重复创建几何体占用内存
  • 封装统一的几何体切换方法,替换Mesh的geometry属性后,同步更新movingObject内的几何体引用,标记几何体需要更新
  • 分别绑定定时器、画布点击事件,触发时调用切换方法即可

修改后可直接运行的代码

export class ThreeJSService {
  // 新增球体几何体属性、切换状态标记
  boxGeometry: THREE.BoxGeometry;
  sphereGeometry: THREE.SphereGeometry;
  isSphere: boolean = false;
  camera: THREE.PerspectiveCamera;
  cube: THREE.Mesh;
  movingObject;
  renderer: THREE.WebGLRenderer;
  scene: THREE.Scene;
  texture: THREE.Texture;
  /**
   * Setups scene for 3d objects
   */
  constructor() {
    this.scene = new THREE.Scene();
    this.texture = new THREE.TextureLoader().load('assets/apartment_background.png');
    this.scene.background = this.texture;

    this.camera = new THREE.PerspectiveCamera( 75, window.innerWidth / window.innerHeight, 0.1, 1000 );
    this.renderer = new THREE.WebGLRenderer();

    // 分别创建立方体、球体几何体
    this.boxGeometry = new THREE.BoxGeometry(0.5, 0.5, 0.5);
    this.sphereGeometry = new THREE.SphereGeometry(0.3, 32, 32);
    const material = new THREE.MeshBasicMaterial( {color: 0x348713} );
    // 默认使用立方体几何体初始化
    this.cube = new THREE.Mesh( this.boxGeometry, material );

    this.movingObject = {
      object: this.cube,
      geometry: this.boxGeometry,
      direction: {
        x: 0.03,
        y: 0,
      },
    };

    // 绑定点击触发切换
    this.renderer.domElement.addEventListener('click', () => {
      this.switchGeometry();
    })

    // 绑定定时触发切换,示例为每3秒切换一次,可自行修改间隔
    setInterval(() => {
      this.switchGeometry();
    }, 3000)
  }

  // 新增几何体切换方法
  switchGeometry() {
    this.isSphere = !this.isSphere;
    const targetGeometry = this.isSphere ? this.sphereGeometry : this.boxGeometry;
    // 替换mesh的几何体
    this.cube.geometry = targetGeometry;
    // 同步更新movingObject中存储的几何体引用
    this.movingObject.geometry = targetGeometry;
    // 标记几何体更新,触发渲染缓存刷新
    this.cube.geometry.needsUpdate = true;
  }

  /**
   * Sets all the requirements needed for the scene
   * @param {HTMLElement} parent The element to attach to
   */
  setup(parent: HTMLElement) {
    const canvas = this.renderer.domElement;
    this.scene.add( this.cube );

    this.camera.position.z = 5;
    parent.appendChild(canvas);
  }

  /**
   * Provides animation to the rendered object. Makes the cube move and sends it to another direction when getting to the border
   * @param {number | undefined} headerHeight The height of the header
   */
  animate() {
    const header = document.getElementById('header')?.clientHeight;
    this.renderer.setSize( window.innerWidth, window.innerHeight - (header ? header : 0));

    this.movingObject.object.rotateX(0.01);
    this.movingObject.object.rotateY(0.01);
    requestAnimationFrame( this.animate.bind(this) );
    this.renderer.render( this.scene, this.camera );

    this.movingObject.object.position.x += this.movingObject.direction.x;

    // Check if the position of the cube is on the border
    if (this.cube.position.x > 7.3 || this.cube.position.x < -7.3) {
      this.movingObject.direction.x = -this.movingObject.direction.x;
    }
  }
}

注意点

  • 示例里球体半径设为0.3,是为了和原边长0.5的立方体视觉尺寸接近,你可以根据实际需求调整SphereGeometry的半径、分段数参数
  • 如果只需要做一次立方体到球体的切换,不需要来回切,可以在切换完成后调用this.boxGeometry.dispose()回收旧几何体占用的显存,避免内存泄漏
  • 上述方案是瞬时切换效果,如果需要立方体平滑变形为球体的动画效果,可以使用Morph Target做顶点插值实现

内容的提问来源于stack exchange,提问作者iyanai m'pfunya

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 20:19:01