three.js之Group

carol2014發表於2024-05-23

Group

<canvas id="mainCanvas"></canvas>
<script type="importmap">
  {
    "imports": {
      "three": "./js/build/three.module.js",
      "three/addons/": "./js/jsm/"
    }
  }
</script>
<script type="module">
  import * as THREE from "three";
  import { TrackballControls } from "three/addons/controls/TrackballControls.js";
  import { GUI } from "three/addons/libs/lil-gui.module.min.js";
  import { initRenderer, initPerspectiveCamera, initAmbientLight, initSpotLight, addPlane } from "./init.js";

  function init() {
    const gui = new GUI();

    const renderer = initRenderer("mainCanvas");

    const scene = new THREE.Scene();

    const camera = initPerspectiveCamera();
    scene.add(camera);

    const spotLight = initSpotLight();
    scene.add(spotLight);

    const ambientLight = initAmbientLight();
    scene.add(ambientLight);

    const plane = addPlane({ width: 1000, height: 100 });
    scene.add(plane);

    let sphere;
    let cube;
    let group;
    let box;
    let arrow;
    const step = 0.03;
    const controls = setupControls();
    controls.redraw();

    render();

    function render() {
      if (controls.grouping && controls.rotate) {
        group.rotation.y += step;
      }

      if (controls.rotate && !controls.grouping) {
        sphere.rotation.y += step;
        cube.rotation.y += step;
      }

      requestAnimationFrame(render);
      renderer.render(scene, camera);
    }

    function setupControls() {
      const controls = new (function () {
        this.cubePosX = 0;
        this.cubePosY = 3;
        this.cubePosZ = 10;

        this.spherePosX = 10;
        this.spherePosY = 5;
        this.spherePosZ = 0;

        this.groupPosX = 10;
        this.groupPosY = 5;
        this.groupPosZ = 0;

        this.grouping = false;
        this.rotate = false;

        this.groupScale = 1;
        this.cubeScale = 1;
        this.sphereScale = 1;

        this.redraw = function () {
          scene.remove(group);

          sphere = createMesh(new THREE.SphereGeometry(5, 10, 10));
          cube = createMesh(new THREE.BoxGeometry(6, 6, 6));

          sphere.position.set(controls.spherePosX, controls.spherePosY, controls.spherePosZ);
          sphere.scale.set(controls.sphereScale, controls.sphereScale, controls.sphereScale);
          cube.position.set(controls.cubePosX, controls.cubePosY, controls.cubePosZ);
          cube.scale.set(controls.cubeScale, controls.cubeScale, controls.cubeScale);

          group = new THREE.Group();
          group.position.set(controls.groupPosX, controls.groupPosY, controls.groupPosZ);
          group.scale.set(controls.groupScale, controls.groupScale, controls.groupScale);
          group.add(sphere);
          group.add(cube);

          scene.add(group);
          controls.positionBoundingBox();

          if (arrow) scene.remove(arrow);
          arrow = new THREE.ArrowHelper(new THREE.Vector3(0, 1, 0), group.position, 10, 0x0000ff);
          scene.add(arrow);
        };

        this.positionBoundingBox = function () {
          scene.remove(box);
          const cbox = new THREE.Box3().setFromObject(group);
          const size = cbox.getSize(new THREE.Vector3());
          const pos = cbox.getCenter(new THREE.Vector3());

          box = new THREE.Mesh(
            new THREE.BoxGeometry(size.x, size.y, size.z),
            new THREE.MeshBasicMaterial({
              color: 0x000000,
              vertexColors: false,
              wireframeLinewidth: 2,
              wireframe: true,
            })
          );
          box.position.copy(pos);
          scene.add(box);
        };
      })();

      const sphereFolder = gui.addFolder("sphere");
      sphereFolder.add(controls, "spherePosX", -20, 20).onChange(function (e) {
        sphere.position.x = e;
        controls.positionBoundingBox();
        controls.redraw();
      });
      sphereFolder.add(controls, "spherePosZ", -20, 20).onChange(function (e) {
        sphere.position.z = e;
        controls.positionBoundingBox();
        controls.redraw();
      });
      sphereFolder.add(controls, "spherePosY", -20, 20).onChange(function (e) {
        sphere.position.y = e;
        controls.positionBoundingBox();
        controls.redraw();
      });
      sphereFolder.add(controls, "sphereScale", 0, 3).onChange(function (e) {
        sphere.scale.set(e, e, e);
        controls.positionBoundingBox();
        controls.redraw();
      });

      const cubeFolder = gui.addFolder("cube");
      cubeFolder.add(controls, "cubePosX", -20, 20).onChange(function (e) {
        cube.position.x = e;
        controls.positionBoundingBox();
        controls.redraw();
      });
      cubeFolder.add(controls, "cubePosZ", -20, 20).onChange(function (e) {
        cube.position.z = e;
        controls.positionBoundingBox();
        controls.redraw();
      });
      cubeFolder.add(controls, "cubePosY", -20, 20).onChange(function (e) {
        cube.position.y = e;
        controls.positionBoundingBox();
        controls.redraw();
      });
      cubeFolder.add(controls, "cubeScale", 0, 3).onChange(function (e) {
        cube.scale.set(e, e, e);
        controls.positionBoundingBox();
        controls.redraw();
      });

      const groupFolder = gui.addFolder("group");
      groupFolder.add(controls, "groupPosX", -20, 20).onChange(function (e) {
        group.position.x = e;
        controls.positionBoundingBox();
        controls.redraw();
      });
      groupFolder.add(controls, "groupPosZ", -20, 20).onChange(function (e) {
        group.position.z = e;
        controls.positionBoundingBox();
        controls.redraw();
      });
      groupFolder.add(controls, "groupPosY", -20, 20).onChange(function (e) {
        group.position.y = e;
        controls.positionBoundingBox();
        controls.redraw();
      });
      groupFolder.add(controls, "groupScale", 0, 3).onChange(function (e) {
        group.scale.set(e, e, e);
        controls.positionBoundingBox();
        controls.redraw();
      });

      gui.add(controls, "grouping");
      gui.add(controls, "rotate");

      return controls;
    }
  }

  init();

  function createMesh(geom) {
    const meshMaterial = new THREE.MeshNormalMaterial();
    meshMaterial.side = THREE.DoubleSide;

    const plane = new THREE.Mesh(geom, meshMaterial);
    return plane;
  }
</script>

three.js之Group

相關文章