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

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

Three.jsをつかってGETパラメータをキューブとして描画するウェブサイトをつくる 📦

cube

ひょんなことからGETパラメータを基にキューブを生成してくれるサイトをつくってみました。

develop.kimizuka.org


使い方

https://develop.kimizuka.org/cube/?1,1,1,1,1,1,1,1という形でGETパラメータにカンマ区切りで1を渡すと、1x1のcubeを8個並べてcubeをつくる

cube

https://develop.kimizuka.org/cube/?1,0,1,1,1,1,1,1という感じで0を渡すと、その部分はcubeが並ばない

cube

https://develop.kimizuka.org/cube/?1,1 という感じでパラメータの数がnの3乗でない場合は3乗になるまで0で埋める
(例の場合は1,1,0,0,0,0,0,0として扱われる)

cube

試してないですが、URLの文字数の限界までcubeを並べることができると思います。
が。カメラの設定が割と適当なので、途中で画角から外れてしまうかもしれません。


JavaScript

    const boxes = location.search.replace('?', ' ').split(',').map((i) => {
      return Number(i);
    });

    const length = Math.pow(Math.ceil(Math.cbrt(boxes.length)), 3);
    const diff = length - boxes.length;

    for (let i = 0; i < diff; ++i) {
      boxes.push(0);
    }

    const size = 1;
    const scene = new THREE.Scene();
    const renderer = new THREE.WebGLRenderer({
      antialias: true
    });
    const camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 1, 100);
    const light = new THREE.DirectionalLight(0xFFFFFF);
    const geometry = new THREE.BoxGeometry(size, size, size);
    const material = new THREE.MeshLambertMaterial({
      color: 0xFFFFFF
    });
    const interval = 100;
    const group = new THREE.Group();

    camera.position.set(size / 2, 0, Math.cbrt(boxes.length) * 8);
    light.position.set(0, 100, 100);
    scene.add(light);

    for (let i = 0; i < boxes.length; ++i) {
      ((i) => {
        if (!boxes[i]) {
          return;
        }

        const cube = new THREE.Mesh(geometry, material);
        const pos = getPosition(i);
        
        cube.position.set(
          pos.x * size,
          pos.y * size,
          pos.z * size
        );

        setTimeout(() => {
          group.add(cube);
        }, i * interval);
      })(i);
    }

    scene.add(group);
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    render();

    function getPosition(i) {
      const length = boxes.length;

      const x = i % Math.cbrt(length);
      const y = 0 | i / Math.pow(Math.cbrt(length), 2);
      const z = 0 | i / Math.cbrt(length) % Math.cbrt(length);
      
      return { x, y, z };
    }

    function render() {
      group.rotation.x += .01;
      group.rotation.y += .01;
      group.rotation.z += .01;
      renderer.render(scene, camera);
      requestAnimationFrame(render);
    }