【Three.js】物体を複製(クローン)する方法clone()と注意点(デモあり)

WebGL & Three.js

Three.jsで物体を複製する方法を紹介します。
具体的なコードとデモが見たい場合は、【WebGL&Three.js入門】Three.jsの一番シンプルなサンプルコードのチュートリアルの解説でデモもみれる状態にしているので参考にしてみてください。
まずはデモをみてみましょう。

Three.jsで物体を複製しているデモ

ソースコード

import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls";
  const scene = new THREE.Scene();
  const camera = new THREE.PerspectiveCamera(
    75,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  );

  const renderer = new THREE.WebGLRenderer();
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  const geometry1 = new THREE.BoxGeometry(10, 10, 10);
  const geometry2 = new THREE.PlaneGeometry(20, 20);
  const geometry3 = new THREE.TorusGeometry(10, 3, 200, 20);

  const material1 = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
  // cloneせずにプロパティを変更すると、オブジェクトの実体への参照先が変更されるので、material1もmaterial2も同じ色になってしまう。
  const material2 = material1.clone();
  material2.color = new THREE.Color(0xff0000);
  const material3 = material1.clone();
  material3.color = new THREE.Color(0x0000ff);

  const mesh1 = new THREE.Mesh(geometry1, material1);
  const mesh2 = new THREE.Mesh(geometry2, material2);
  const mesh3 = new THREE.Mesh(geometry3, material3);
  mesh1.position.x = -25;
  mesh3.position.x = 25;
  scene.add(mesh1, mesh2, mesh3);

  const axis = new THREE.AxesHelper(20);
  scene.add(axis);

  camera.position.z = 50;

  const control = new OrbitControls(camera, renderer.domElement);

  function animate() {
    requestAnimationFrame(animate);

    // 回転
    mesh1.rotation.x += 0.01;
    mesh2.rotation.x += 0.01;
    mesh2.rotation.y += 0.01;
    mesh3.rotation.z += 0.01;

    control.update();

    renderer.render(scene, camera);
  }

  animate();

今回は、複製なので、特に以下の部分がポイントとなります。

  const material1 = new THREE.MeshBasicMaterial({ color: 0x00ff00 });
  const material2 = material1.clone();
  material2.color = new THREE.Color(0xff0000);
  const material3 = material1.clone();
  material3.color = new THREE.Color(0x0000ff);

meshでもできますが、たとえばマテリアルが大体同じものだったりする場合は、上のようにclone()で複製するのが一般的です。
そして、そのあとで必要なプロパティを変更します。

注意:cloneしたい場合

material2にmaterial1をそのまま格納すると、オブジェクトのため実体への参照先が同じになり、
どちらかのプロパティを変更するともう片方まで変更されてしまいます。
この辺りが理解できない場合は、オブジェクトのコピーの挙動が理解できていない可能性が高いため、JavaScriptにおけるプリミティブ型とオブジェクト型の挙動の差を参考にしてもらえればと思います。
clone()を使うことで、実体への参照先を異なるものにできるので、それぞれを変更することが可能になります。