みかづきブログ・カスタム

基本的にはちょちょいのほいです。

Blenderで作ったglbファイルをThree.jsで読み込んだあと、複製してたくさん表示する 📦

こちらの記事で、Blenderで作ったglbファイルを読み込んで表示しました。

blog.kimizuka.org

読み込んだモデルを一度しか使わないのであれば、これで問題ないのですが、同じモデルを何個も配置するときはどうしたものかと考えた結果、cloneをつかって複製することにしてみました。

DEMO

f:id:kimizuka:20210324123847p:plain

develop.kimizuka.org

こちらのDEMOのカラフルなキューブは、わざわざBlenderで作っているのですが、

・loaderで1回読み込む
・cloneで複製

という形を取って4つに増やしています。

JavaScript

import * as THREE from './build/three.module.js';
import { OrbitControls } from './lib/jsm/controls/OrbitControls.js';
import { GLTFLoader } from './lib/jsm/loaders/GLTFLoader.js';

init();

async function init() {
  const canvas = document.createElement('canvas');

  document.body.appendChild(canvas);

  const renderer = new THREE.WebGLRenderer({
    canvas,
    antialias: true
  });
  const scene = new THREE.Scene();
  const width = window.innerWidth;
  const height = window.innerHeight;

  renderer.setPixelRatio(1);
  renderer.setSize(width, height);

  const camera = new THREE.PerspectiveCamera(45, width / height, 1, 100);

  camera.position.set(0, 1, 10);

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

  const light = new THREE.AmbientLight(0xFFFFFF, 1.0);

  scene.add(light);

  const loader = new GLTFLoader();
  const url = './cube.glb';
  const colors = [{
    r: 1,
    g: 1,
    b: 1
  },{
    r: 1,
    g: 0,
    b: 0
  },{
    r: 0,
    g: 1,
    b: 0
  },{
    r: 0,
    g: 0,
    b: 1
  },];
  const models = [];

  const model = await (() => {
    return new Promise((resolve) => {
      loader.load(
        url,
        (gltf) => {
          resolve(gltf.scene);
        },
        (err) => {
          console.error(err);
        }
      );
    });
  })();

  for (let i = 0; i < colors.length; ++i) {
    models.push(model.clone()); // モデルを複製

    models[i].traverse((object) => {
      if (object.isMesh) {
        object.material = object.material.clone(); // 同一のマテリアルを参照しているようなので複製したものを代入
        object.material.color.r = colors[i].r;
        object.material.color.g = colors[i].g;
        object.material.color.b = colors[i].b;
      }
    });

    models[i].position.set(
      i * 2 % colors.length,
      0,
      (0 | i / colors.length * 2) * 2
    );
    scene.add(models[i]);
  }

  renderer.setAnimationLoop(tick);

  function tick() {
    controls.update();

    if (model) {
      scene.rotation.y += .01;
    }

    renderer.render(scene, camera);
  }
}