cannon+three打造一个三维小球重力下滑滑滑梯效果代码

cannon+three打造一个三维小球重力下滑滑滑梯效果代码
<!DOCTYPE html>
<html lang="en" >

<head>

  <meta charset="UTF-8">


 
  <style>
    :root {
      --tp-base-background-color: hsla(0, 0%, 40%, 1.00);
      --tp-base-shadow-color: hsla(0, 0%, 0%, 0.2);
      --tp-button-background-color: hsla(0, 0%, 100%, 1.00);
      --tp-button-background-color-active: hsla(0, 0%, 85%, 1.00);
      --tp-button-background-color-focus: hsla(0, 0%, 90%, 1.00);
      --tp-button-background-color-hover: hsla(0, 0%, 95%, 1.00);
      --tp-button-foreground-color: hsla(230, 20%, 11%, 1.00);
      --tp-container-background-color: hsla(0, 0%, 0%, 0.20);
      --tp-container-background-color-active: hsla(0, 0%, 0%, 0.35);
      --tp-container-background-color-focus: hsla(0, 0%, 0%, 0.30);
      --tp-container-background-color-hover: hsla(0, 0%, 0%, 0.25);
      --tp-container-foreground-color: hsla(0, 0%, 100%, 0.90);
      --tp-groove-foreground-color: hsla(0, 0%, 0%, 0.50);
      --tp-input-background-color: hsla(0, 0%, 0%, 0.50);
      --tp-input-background-color-active: hsla(0, 0%, 0%, 0.65);
      --tp-input-background-color-focus: hsla(0, 0%, 0%, 0.60);
      --tp-input-background-color-hover: hsla(0, 0%, 0%, 0.55);
      --tp-input-foreground-color: hsla(0, 0%, 100%, 0.90);
      --tp-label-foreground-color: hsla(0, 0%, 100%, 0.90);
      --tp-monitor-background-color: hsla(0, 0%, 0%, 0.50);
      --tp-monitor-foreground-color: hsla(0, 0%, 100%, 0.50);
    }

    html {
      font-family: 'Dosis', Arial, sans-serif;
      -ms-text-size-adjust: 100%;
      -webkit-text-size-adjust: 100%;
    }

    *,
    *::after,
    *::before {
      box-sizing: border-box;
    }

    body {
      padding: 0;
      margin: 0;
      background-color: #1c7dff;
      overflow: hidden;
      -webkit-font-smoothing: antialiased;
      -moz-osx-font-smoothing: grayscale;
      cursor: -moz-grabg;
      cursor: -webkit-grab;
    }

    .credits {
      position: absolute;
      z-index: 1;
      bottom: 0;
      width: auto;
      background-color: #07326b;
      padding: 10px;
      cursor: pointer;
      font-size: 8pt;
      font-weight: lighter;
    }

    .credits a {
      color: #ffffff;
      text-decoration: none;
    }

    .credits h1 {
      margin: inherit;
    }

    .credits:hover {
      background-color: #ff1111;
      color: #ffffff;
    }
  </style>

  
  
<style>
html {
  font-family: "Dosis", Arial, sans-serif;
  -ms-text-size-adjust: 100%;
  -webkit-text-size-adjust: 100%;
}

.stats {
  position: absolute;
  z-index: 1;
  top: 0;
  left: 0;
}
</style>


</head>

<body>
  <div class="stats">
</div>

 
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/Stats-16.js"></script>
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/cannon.js"></script>

<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/three.126.js"></script>
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/OrbitControls.126.js"></script>
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/TransformControls.js"></script>
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/gsap.3.5.2.js"></script>
<script type="text/javascript" src="//repo.bfw.wiki/bfwrepo/js/tweakpane.3.02.js"></script>

      <script >

class App {
  init() {
    this.setup();
    this.createScene();
    this.createCamera();
    this.addCameraControls();
    this.addAmbientLight();
    this.addDirectionalLight();
    this.addPhysicsWorld();
    this.addBackWall();
    this.addFloor();
    this.addWoodColumns();
    this.addRows();
    this.addEdges();
    this.addSphere();
    this.addFloorBox();
    this.addStatsMonitor();
    this.addWindowListeners();
    this.addGuiControls();
    this.addDummyCameraTarget();
    this.animateDummyCameraTarget();
    this.animate();
  }

  setup() {
    this.debug = false;
    this.width = window.innerWidth;
    this.height = window.innerHeight;
    this.cameraAutoAnimate = false;
    this.spheres = [];

    Sphere.loadTextures();
    Sphere.buildMaterial();
    Column.buildMaterial();
    Row.buildMaterial();
  }

  createScene() {
    this.scene = new THREE.Scene();
    this.scene.background = new THREE.Color(
    window.getComputedStyle(document.body).backgroundColor);

    this.renderer = new THREE.WebGLRenderer({ antialias: true });

    this.renderer.setSize(this.width, this.height);
    this.scene.position.set(0, -5, 0);
    this.renderer.shadowMap.enabled = true;
    this.renderer.shadowMap.type = THREE.PCFSoftShadowMap;

    document.body.appendChild(this.renderer.domElement);
  }

  createCamera() {
    this.camera = new THREE.PerspectiveCamera(
    20,
    this.width / this.height,
    1,
    1000);

    this.camera.position.set(20, 20, 80);

    this.scene.add(this.camera);
  }

  addCameraControls() {
    this.orbitControl = new THREE.OrbitControls(
    this.camera,
    this.renderer.domElement);

    this.orbitControl.minPolarAngle = THREE.MathUtils.degToRad(0);
    this.orbitControl.maxPolarAngle = THREE.MathUtils.degToRad(90);
    this.orbitControl.minAzimuthAngle = THREE.MathUtils.degToRad(-50);
    this.orbitControl.maxAzimuthAngle = THREE.MathUtils.degToRad(50);
    this.orbitControl.maxDistance = 90;
    this.orbitControl.minDistance = 40;
    this.orbitControl.enableDamping = true;
    this.orbitControl.dampingFactor = 0.02;
    this.orbitControl.enablePan = !this.cameraAutoAnimate;
    this.orbitControl.enableRotate = !this.cameraAutoAnimate;
    this.orbitControl.enableZoom = !this.cameraAutoAnimate;
    this.orbitControl.saveState();

    this.orbitControl.addEventListener("start", () => {
      requestAnimationFrame(() => {
        document.body.style.cursor = "-moz-grabbing";
        document.body.style.cursor = "-webkit-grabbing";
      });
    });

    this.orbitControl.addEventListener("end", () => {
      requestAnimationFrame(() => {
        document.body.style.cursor = "-moz-grab";
        document.body.style.cursor = "-webkit-grab";
      });
    });
  }

  addPhysicsWorld() {
    this.physics = {
      fixedTimeStep: 1 / 60,
      maxSubSteps: 10,
      damping: 0.09,
      time: 0.01,
      lastTime: 0.01 };


    this.world = new CANNON.World();
    this.world.gravity.set(0, -120, 0);
    this.world.broadphase = new CANNON.NaiveBroadphase();
    this.world.solver.iterations = 10;
    this.world.defaultContactMaterial.contactEquationStiffness = 1e6;
    this.world.defaultContactMaterial.contactEquationRelaxation = 3;
    this.world.allowSleep = true;

    this.cannonDebugRenderer =
    this.debug &&
    new CannonDebugRenderer(this.scene, this.world, { THREE, CANNON });
  }

  addAmbientLight() {
    this.scene.add(new THREE.AmbientLight({ color: "#ffffff" }, 0.5));
  }

  addDirectionalLight() {
    this.directionalLight = new THREE.DirectionalLight("#ffffff", 0.8);
    this.directionalLight.castShadow = true;
    this.directionalLight.position.set(10, 15, 15);

    this.directionalLight.shadow.camera.needsUpdate = true;
    this.directionalLight.shadow.mapSize.width = 2048;
    this.directionalLight.shadow.mapSize.height = 2048;
    this.directionalLight.shadow.camera.left = -20;
    this.directionalLight.shadow.camera.right = 20;
    this.directionalLight.shadow.camera.top = 15;
    this.directionalLight.shadow.camera.bottom = -15;

    this.scene.add(this.directionalLight);
  }

  addFloor() {
    const geometry = new THREE.PlaneBufferGeometry(400, 150);
    const material = new THREE.MeshStandardMaterial({
      color: "#ffffff",
      side: THREE.DoubleSide });


    this.floor = new THREE.Mesh(geometry, material);
    this.floor.position.y = -5;
    this.floor.position.z = 0;
    this.floor.rotateX(Math.PI / 2);
    this.floor.receiveShadow = true;
    this.floor.body = new CANNON.Body({
      mass: 0,
      position: new CANNON.Vec3(0, this.floor.position.y, 0),
      material: new CANNON.Material(),
      shape: new CANNON.Plane(40, 40, 40) });


    this.floor.body.material.name = "floor";
    this.floor.body.quaternion.setFromAxisAngle(
    new CANNON.Vec3(1, 0, 0),
    THREE.MathUtils.degToRad(-90));

    this.world.addBody(this.floor.body);

    this.scene.add(this.floor);

    this.addFloorGrid();
  }

  addFloorGrid() {
    const size = 400;
    const divisions = size;
    const grid = new THREE.GridHelper(size, divisions, "#888888");

    grid.position.set(0, this.floor.position.y, 0);

    this.scene.add(grid);
  }

  addWoodColumns() {
    this.columnFront = new Column();
    this.columnFront.build();
    this.columnFront.mesh.position.y = 7;
    this.columnFront.mesh.position.z = 0.7;
    this.scene.add(this.columnFront.mesh);

    this.columnFront.cylinder.position.set(0, 0.2, 8.7);
    this.columnFront.mesh.add(this.columnFront.cylinder);

    const cylinder2 = this.columnFront.cylinder.clone();
    cylinder2.position.set(0, 0.2, 4);
    this.columnFront.mesh.add(cylinder2);

    const cylinder3 = this.columnFront.cylinder.clone();
    cylinder3.position.set(0, 0.2, -0.7);
    this.columnFront.mesh.add(cylinder3);

    const cylinder4 = this.columnFront.cylinder.clone();
    cylinder4.position.set(0, 0.2, -5.5);
    this.columnFront.mesh.add(cylinder4);

    const cylinder5 = this.columnFront.cylinder.clone();
    cylinder5.position.set(0, 0.2, -10.5);
    this.columnFront.mesh.add(cylinder5);

    this.columnBack = this.columnFront.mesh.clone();
    this.columnBack.position.y = this.columnFront.mesh.position.y;
    this.columnBack.position.z = -this.columnFront.mesh.position.z;

    this.scene.add(this.columnBack);
  }

  addRows() {
    this.row1 = new Row(this.world);
    this.row1.build({ size: 6 });
    this.row1.rotateZ(THREE.MathUtils.degToRad(-20));
    this.row1.position({ x: 2.2, y: 14, z: 0, gutter: -0.18 });
    this.scene.add(this.row1.mesh);

    this.row2 = new Row(this.world);
    this.row2.build({ size: 12 });
    this.row2.rotateZ(THREE.MathUtils.degToRad(10));
    this.row2.position({ x: 0.25, y: 10, z: 0, gutter: 0.1 });
    this.scene.add(this.row2.mesh);

    this.row3 = new Row(this.world);
    this.row3.build({ size: 12 });
    this.row3.rotateZ(THREE.MathUtils.degToRad(-15));
    this.row3.position({ x: -1, y: 5.5, z: 0, gutter: -0.1 });
    this.scene.add(this.row3.mesh);

    this.row4 = new Row(this.world);
    this.row4.build({ size: 12 });
    this.row4.rotateZ(THREE.MathUtils.degToRad(10));
    this.row4.position({ x: 0, y: 0.5, z: 0, gutter: 0.1 });
    this.scene.add(this.row4.mesh);

    this.row5 = new Row(this.world);
    this.row5.build({ size: 12 });
    this.row5.rotateZ(THREE.MathUtils.degToRad(-15));
    this.row5.position({ x: -1, y: -4, z: 0, gutter: -0.1 });
    this.scene.add(this.row5.mesh);
  }

  addEdges() {
    this.edge1 = new Edge();
    this.edge1.build(this.world, "#fbff0e");
    this.edge1.rotate({ x: 0, y: 0, z: THREE.MathUtils.degToRad(90) });
    this.edge1.position({ x: 2, y: 14, z: 0 });
    this.edge1.bottom.body.position = new CANNON.Vec3(
    6.4,
    14.5,
    this.edge1.bottom.position.z);

    this.edge1.bottomInside.position = new CANNON.Vec3(
    6,
    14.2,
    this.edge1.bottom.position.z);

    this.edge1.bottomInside.quaternion.setFromAxisAngle(
    new CANNON.Vec3(0, 0, -1),
    THREE.MathUtils.degToRad(-40));

    this.scene.add(this.edge1.mesh);
    this.edge1.cylinder.rotateX(THREE.MathUtils.degToRad(90));
    this.edge1.cylinder.position.set(2, -1, 0.75);
    this.edge1.mesh.add(this.edge1.cylinder);
    const cylinder2 = this.edge1.cylinder.clone();
    cylinder2.position.set(2, 1.8, 0.75);
    this.edge1.mesh.add(cylinder2);

    this.edge2 = new Edge();
    this.edge2.build(this.world, "#ff0e0e");
    this.edge2.rotate({ x: 0, y: 0, z: THREE.MathUtils.degToRad(90) });
    this.edge2.position({ x: -9, y: 9.8, z: 0 });
    this.edge2.bottom.position.x = 1.55;
    this.edge2.bottom.body.position = new CANNON.Vec3(
    -7.5,
    10,
    this.edge2.bottom.position.z);

    this.edge2.bottomInside.position = new CANNON.Vec3(
    -7,
    10.5,
    this.edge2.bottom.position.z);

    this.edge2.bottomInside.quaternion.setFromAxisAngle(
    new CANNON.Vec3(0, 0, -1),
    THREE.MathUtils.degToRad(35));

    this.scene.add(this.edge2.mesh);
    const cylinder3 = this.edge1.cylinder.clone();
    cylinder3.material = this.edge1.cylinder.material.clone();
    cylinder3.material.color = new THREE.Color("#ff0e0e");
    cylinder3.position.set(4, -1, 0.75);
    this.edge2.mesh.add(cylinder3);
    const cylinder4 = cylinder3.clone();
    cylinder4.position.set(4, 1.8, 0.75);
    this.edge2.mesh.add(cylinder4);

    this.edge3 = new Edge();
    this.edge3.build(this.world, "#15ff47");
    this.edge3.rotate({ x: 0, y: 0, z: THREE.MathUtils.degToRad(90) });
    this.edge3.position({ x: 2, y: 4.8, z: 0 });
    this.edge3.bottom.position.x = 4.45;
    this.edge3.bottom.body.position = new CANNON.Vec3(
    6.5,
    5.5,
    this.edge3.bottom.position.z);

    this.edge3.bottomInside.position = new CANNON.Vec3(
    6,
    5.2,
    this.edge3.bottom.position.z);

    this.edge3.bottomInside.quaternion.setFromAxisAngle(
    new CANNON.Vec3(0, 0, -1),
    THREE.MathUtils.degToRad(-40));

    this.scene.add(this.edge3.mesh);
    const cylinder5 = this.edge1.cylinder.clone();
    cylinder5.material = this.edge1.cylinder.material.clone();
    cylinder5.material.color = new THREE.Color("#15ff47");
    cylinder5.position.set(2, -1, 0.75);
    this.edge3.mesh.add(cylinder5);
    const cylinder6 = cylinder5.clone();
    cylinder6.position.set(2, 1.8, 0.75);
    this.edge3.mesh.add(cylinder6);

    this.edge4 = new Edge();
    this.edge4.build(this.world, "#1c57ff");
    this.edge4.rotate({ x: 0, y: 0, z: THREE.MathUtils.degToRad(90) });
    this.edge4.position({ x: -9, y: 0.3, z: 0 });
    this.edge4.bottom.position.x = 1.55;
    this.edge4.bottom.body.position = new CANNON.Vec3(
    -7.4,
    0.8,
    this.edge4.bottom.position.z);

    this.edge4.bottomInside.position = new CANNON.Vec3(
    -7,
    1,
    this.edge4.bottom.position.z);

    this.edge4.bottomInside.quaternion.setFromAxisAngle(
    new CANNON.Vec3(0, 0, -1),
    THREE.MathUtils.degToRad(40));

    this.scene.add(this.edge4.mesh);
    const cylinder7 = this.edge1.cylinder.clone();
    cylinder7.material = this.edge1.cylinder.material.clone();
    cylinder7.material.color = new THREE.Color("#1c57ff");
    cylinder7.position.set(4, -0.7, 0.75);
    this.edge4.mesh.add(cylinder7);
    const cylinder8 = cylinder7.clone();
    cylinder8.position.set(4, 1.8, 0.75);
    this.edge4.mesh.add(cylinder8);
  }

  addFloorBox() {
    this.floorBox = new FloorBox();
    this.floorBox.build(this.world);
    this.scene.add(this.floorBox.mesh);
  }

  addBackWall() {
    const materialParams = { color: "#1c7dff", side: THREE.DoubleSide };
    const geometry = new THREE.PlaneBufferGeometry(400, 140);
    const material = new THREE.MeshStandardMaterial(materialParams);

    const backwall = new THREE.Mesh(geometry, material);
    backwall.position.z = -10;
    backwall.receiveShadow = true;

    this.scene.add(backwall);
  }

  addSphere() {
    const sphere = new Sphere();
    sphere.build();

    const collideEvent = e => {
      if (
      e.body.material.name === "floor" ||
      e.body.material.name === "sphere")
      {
        sphere.mesh.body.removeEventListener("collide", collideEvent);

        this.moveCameraUp();
      }
    };

    sphere.mesh.body.addEventListener("collide", collideEvent);

    this.world.addBody(sphere.mesh.body);
    const mat = new CANNON.ContactMaterial(
    this.floor.body.material,
    sphere.mesh.body.material,
    { friction: 0.3, restitution: 0.5 });

    this.world.addContactMaterial(mat);

    this.spheres.push(sphere);
    this.scene.add(sphere.mesh);
  }

  addDummyCameraTarget() {
    this.dummyCameraTarget = new THREE.Mesh(
    new THREE.SphereBufferGeometry(0.5, 8, 8),
    new THREE.MeshStandardMaterial());

    this.dummyCameraTarget.material.needsUpdate = true;
    this.dummyCameraTarget.material.opacity = 0;
    this.dummyCameraTarget.material.alphaTest = 1;
    this.dummyCameraTarget.position.y = 20;
    this.dummyCameraTarget.position.z = 2;
    this.scene.add(this.dummyCameraTarget);
  }

  animateDummyCameraTarget() {
    const tl = gsap.timeline({
      defaults: { duration: 11, ease: "sine.out", delay: 0.5 },
      onComplete: () => {
        tl.kill();
      } });


    tl.to(this.dummyCameraTarget.position, { y: -4 });
  }

  moveCameraUp() {
    const tl = gsap.timeline({
      defaults: { duration: 3, ease: "linear", delay: 0.5 },
      onComplete: () => {
        tl.kill();
        this.dummyCameraTarget.position.y = 14;
        this.addSphere();
        this.animateDummyCameraTarget();
      } });


    tl.to(this.dummyCameraTarget.position, { y: 14 });
  }

  addGuiControls() {
    this.pane = new Tweakpane.Pane();
    this.guiCamera = this.pane.addFolder({
      title: "Camera",
      expanded: true });


    this.guiCamera.
    addInput({ auto: this.cameraAutoAnimate }, "auto").
    on("change", ({ value }) => {
      this.cameraAutoAnimate = value;
      this.orbitControl.enablePan = !this.cameraAutoAnimate;
      this.orbitControl.enableRotate = !this.cameraAutoAnimate;
      this.orbitControl.enableZoom = !this.cameraAutoAnimate;

      if (this.cameraAutoAnimate) {
        this.orbitControl.reset();
      }
    });
  }

  animate() {
    this.stats.begin();
    this.renderer.render(this.scene, this.camera);

    if (!this.cameraAutoAnimate) {
      this.orbitControl.update();
    }

    // physics loop
    if (this.physics.lastTime !== undefined) {
      this.debug && this.cannonDebugRenderer.update();
      const dt = (this.physics.time - this.physics.lastTime) / 1000;
      this.world.step(this.physics.fixedTimeStep, dt, this.physics.maxSubSteps);

      if (this.cameraAutoAnimate) {
        const { x, y, z } = this.dummyCameraTarget.position;
        this.camera.lookAt(new THREE.Vector3(x, y, z));
        this.camera.position.y = y + 2;
      }

      // map physics position to threejs mesh position
      this.spheres.map(sphere => {
        sphere.mesh.position.copy(sphere.mesh.body.position);
        sphere.mesh.quaternion.copy(sphere.mesh.body.quaternion);
      });
    }

    this.stats.end();
    this.physics.lastTime = this.physics.time;

    requestAnimationFrame(this.animate.bind(this));
  }

  addWindowListeners() {
    window.addEventListener("resize", this.onResize.bind(this), {
      passive: true });

  }

  addStatsMonitor() {
    this.stats = new Stats();
    this.stats.showPanel(0);
    this.stats = new Stats();
    this.stats.showPanel(0);
    document.body.querySelector(".stats").appendChild(this.stats.domElement);
  }

  onResize() {
    this.width = window.innerWidth;
    this.height = window.innerHeight;
    this.camera.aspect = this.width / this.height;

    this.camera.updateProjectionMatrix();
    this.renderer.setSize(this.width, this.height);
  }}


class Sphere {
  constructor() {
    this.mesh = null;
  }

  static loadTextures() {
    const urls = [
    ];


    Sphere.texture = new THREE.CubeTextureLoader().load(urls);
  }

  static buildMaterial() {
    const material = new THREE.MeshPhysicalMaterial({
      color: "#ffffff",
      roughness: 0,
      metalness: 0.8,
      emissive: "#000000",
      envMap: Sphere.texture });


    material.clearcoatRoughness = 0;
    material.clearcoat = 0;
    material.reflectivity = 1;

    Sphere.material = material;
  }

  build() {
    const sphere = new THREE.Mesh(
    new THREE.SphereBufferGeometry(0.5, 16, 16),
    new THREE.MeshStandardMaterial({ color: "#ff00ff" }));

    this.mesh = sphere;
    this.mesh.material.name = "sphere";
    this.mesh.material.needsUpdate = true;
    this.mesh.material.opacity = 0;
    this.mesh.material.alphaTest = 1;
    this.mesh.position.y = 22;
    this.mesh.position.z = 0;

    const leftSide = new THREE.Mesh(
    new THREE.SphereBufferGeometry(0.5, 16, 16, 0, 3.15),
    new THREE.MeshPhysicalMaterial({
      color: "#ffffff",
      roughness: 0.1,
      metalness: 0.2,
      emissive: "#000000" }));


    leftSide.rotation.y = THREE.MathUtils.degToRad(-90);
    leftSide.castShadow = true;
    leftSide.receiveShadow = true;
    this.mesh.add(leftSide);

    const rightSide = new THREE.Mesh(
    new THREE.SphereBufferGeometry(0.5, 16, 16, 0, 3.15),
    Sphere.material);

    rightSide.rotation.y = THREE.MathUtils.degToRad(90);
    rightSide.castShadow = true;
    rightSide.receiveShadow = true;
    this.mesh.add(rightSide);

    this.mesh.body = new CANNON.Body({
      mass: 2,
      material: new CANNON.Material(),
      shape: new CANNON.Sphere(0.5),
      position: new CANNON.Vec3(0, sphere.position.y, 0) });


    this.mesh.body.material.name = "sphere";
    this.mesh.body.fixedRotation = true;
    this.mesh.body.sleepSpeedLimit = 0.1;
    this.mesh.body.sleepTimeLimit = 0.5;
  }}


class Row {
  constructor(world) {
    this.mesh = null;
    this.world = world;
  }

  static buildMaterial() {
    const material = new THREE.MeshPhysicalMaterial({
      color: "#ffffff",
      roughness: 0,
      metalness: 0,
      emissive: "#000000" });


    material.clearcoatRoughness = 0;
    material.clearcoat = 0;
    material.reflectivity = 1;
    material.aoMapIntensity = 0.5;
    material.displacementScale = 0;
    material.displacementBias = 0;
    material.aoMap = new THREE.TextureLoader().load(
    "//repo.bfw.wiki/bfwrepo/image/5f14d32694ad3.png");

    material.displacementMap = new THREE.TextureLoader().load(
    "//repo.bfw.wiki/bfwrepo/image/5f14d32694ad3.png");

    material.roughnessMap = new THREE.TextureLoader().load(
    "//repo.bfw.wiki/bfwrepo/image/5f14d32694ad3.png");

    material.normalMap = new THREE.TextureLoader().load(
    "//repo.bfw.wiki/bfwrepo/image/6085fa955c872.png");

    material.map = new THREE.TextureLoader().load(
    "//repo.bfw.wiki/bfwrepo/image/5e4350528640e.png");


    material.normalScale = new THREE.Vector2(1.5, 0);
    material.map.wrapS = THREE.RepeatWrapping;
    material.map.wrapT = THREE.RepeatWrapping;
    material.map.repeat.x = 1;
    material.map.repeat.y = 0.1;

    Row.material = material;
  }

  build({ size }) {
    this.mesh = new THREE.Object3D();
    const geometry = new THREE.BoxBufferGeometry(size, 1, 0.1, 16, 16);
    const cannonSize = size * 0.5; // half size

    this.front = new THREE.Mesh(geometry, Row.material);
    this.front.receiveShadow = true;
    this.front.castShadow = true;
    this.front.position.y = 2.5;
    this.front.position.z = 0.5;
    this.front.body = new CANNON.Body({
      mass: 0,
      inertia: 1,
      force: 10,
      material: new CANNON.Material(),
      shape: new CANNON.Box(new CANNON.Vec3(cannonSize, 0.5, 0.05)) });


    this.mesh.add(this.front);
    this.world.addBody(this.front.body);

    this.back = new THREE.Mesh(geometry, Row.material);
    this.back.receiveShadow = true;
    this.back.castShadow = true;
    this.back.position.y = 2.5;
    this.back.position.z = -0.5;
    this.back.body = new CANNON.Body({
      mass: 0,
      inertia: 1,
      force: 10,
      material: new CANNON.Material(),
      shape: new CANNON.Box(new CANNON.Vec3(cannonSize, 0.5, 0.05)) });

    this.mesh.add(this.back);
    this.world.addBody(this.back.body);

    this.bottom = new THREE.Mesh(
    new THREE.BoxBufferGeometry(size, 0.9, 0.1, 16, 16),
    Row.material);

    this.bottom.receiveShadow = true;
    this.bottom.castShadow = true;
    this.bottom.body = new CANNON.Body({
      mass: 0,
      material: new CANNON.Material(),
      shape: new CANNON.Box(new CANNON.Vec3(cannonSize, 0.05, 0.5)) });


    this.mesh.add(this.bottom);
    this.world.addBody(this.bottom.body);
  }

  position({ x, y, z, gutter }) {
    this.mesh.position.set(x, y, z);
    this.bottom.position.y = 2.05;
    this.bottom.position.z = z;

    this.bottom.position.x = gutter;
    this.front.body.position = new CANNON.Vec3(
    this.front.position.x + x,
    this.front.position.y + y,
    this.front.position.z + z);

    this.back.body.position = new CANNON.Vec3(
    this.back.position.x + x,
    this.back.position.y + y,
    this.back.position.z - z);

    this.bottom.body.position = new CANNON.Vec3(
    this.mesh.position.x + this.bottom.position.x,
    this.bottom.position.y + y,
    this.bottom.position.z + z);

  }

  rotateZ(z) {
    this.front.rotateZ(z);
    this.back.rotateZ(z);
    this.bottom.rotateZ(z);
    this.bottom.rotateX(Math.PI / 2);

    this.front.body.quaternion.setFromAxisAngle(new CANNON.Vec3(0, 0, -1), -z);
    this.back.body.quaternion.setFromAxisAngle(new CANNON.Vec3(0, 0, -1), -z);
    this.bottom.body.quaternion.setFromAxisAngle(new CANNON.Vec3(0, 0, -1), -z);
  }}


class FloorBox {
  constructor() {
    this.mesh = null;
  }

  getMaterial() {
    const material = new THREE.MeshPhysicalMaterial({
      color: "#ff5403",
      roughness: 0,
      metalness: 0,
      emissive: "#000000" });


    material.clearcoatRoughness = 0;
    material.clearcoat = 0;
    material.reflectivity = 1;
    material.aoMapIntensity = 0.5;
    material.displacementScale = 0;
    material.displacementBias = 0;
    material.normalScale = new THREE.Vector2(6, 6);

    return material;
  }

  build(world) {
    this.mesh = new THREE.Object3D();
    this.world = world;
    const geometry = new THREE.BoxBufferGeometry(7, 2, 0.2, 16, 16);
    const material = this.getMaterial();

    this.left = new THREE.Mesh(geometry, material);
    this.left.receiveShadow = true;
    this.left.castShadow = true;
    this.left.position.y = -4.5;
    this.left.position.x = 8.2;
    this.left.position.z = 4;
    this.left.body = new CANNON.Body({
      mass: 0,
      inertia: 1,
      force: 10,
      material: new CANNON.Material(),
      shape: new CANNON.Box(new CANNON.Vec3(3.5, 1, 0.3)),
      position: new CANNON.Vec3(
      this.left.position.x,
      this.left.position.y,
      this.left.position.z) });



    this.world.addBody(this.left.body);
    this.mesh.add(this.left);

    this.right = new THREE.Mesh(geometry, material);
    this.right.receiveShadow = true;
    this.right.castShadow = true;
    this.right.position.y = -4.5;
    this.right.position.x = 8.2;
    this.right.position.z = -4;
    this.right.body = new CANNON.Body({
      mass: 0,
      inertia: 1,
      force: 10,
      material: new CANNON.Material(),
      shape: new CANNON.Box(new CANNON.Vec3(3.5, 1, 0.3)),
      position: new CANNON.Vec3(
      this.right.position.x,
      this.right.position.y,
      this.right.position.z) });



    this.world.addBody(this.right.body);
    this.mesh.add(this.right);

    this.back = new THREE.Mesh(
    new THREE.BoxBufferGeometry(7.8, 2, 0.2, 16, 16),
    material);

    this.back.receiveShadow = true;
    this.back.castShadow = true;
    this.back.position.y = -4.5;
    this.back.position.x = 11.6;
    this.back.position.z = 0;
    this.back.rotateY(Math.PI / 2);
    this.back.body = new CANNON.Body({
      mass: 0,
      inertia: 1,
      force: 10,
      material: new CANNON.Material(),
      shape: new CANNON.Box(new CANNON.Vec3(4, 1, 0.3)),
      position: new CANNON.Vec3(
      this.back.position.x - 0.1,
      this.back.position.y,
      this.back.position.z) });



    this.back.body.quaternion.setFromAxisAngle(
    new CANNON.Vec3(0, -1, 0),
    -THREE.MathUtils.degToRad(90));

    this.world.addBody(this.back.body);
    this.mesh.add(this.back);

    this.leftFront = new THREE.Mesh(
    new THREE.BoxBufferGeometry(7.8, 2, 0.2, 16, 16),
    material);

    this.leftFront.receiveShadow = true;
    this.leftFront.castShadow = true;
    this.leftFront.position.y = -4.5;
    this.leftFront.position.x = 4.8;
    this.leftFront.position.z = 0;
    this.leftFront.rotateY(Math.PI / 2);
    this.leftFront.body = new CANNON.Body({
      mass: 0,
      inertia: 1,
      force: 10,
      material: new CANNON.Material(),
      shape: new CANNON.Box(new CANNON.Vec3(4, 1, 0.3)),
      position: new CANNON.Vec3(
      this.leftFront.position.x - 0.2,
      this.leftFront.position.y,
      this.leftFront.position.z) });



    this.leftFront.body.quaternion.setFromAxisAngle(
    new CANNON.Vec3(0, -1, 0),
    -THREE.MathUtils.degToRad(90));

    this.world.addBody(this.leftFront.body);
    this.mesh.add(this.leftFront);
  }}


class Edge {
  constructor() {
    this.mesh = null;
    this.size = 3;
  }

  getMaterial(color = "#ff440c") {
    const material = new THREE.MeshPhysicalMaterial({
      color,
      roughness: 1,
      metalness: 0,
      emissive: "#000000" });


    return material;
  }

  build(world, color, textures) {
    this.mesh = new THREE.Object3D();
    this.world = world;
    const material = this.getMaterial(color, textures);

    this.front = new THREE.Mesh(
    new THREE.BoxBufferGeometry(this.size, 4, 0.1, 16, 16),
    material);

    this.front.receiveShadow = true;
    this.front.castShadow = true;
    this.front.position.y = 0.5;
    this.front.position.z = 0.6;
    this.front.position.x = 3;
    this.front.body = new CANNON.Body({
      mass: 0,
      material: new CANNON.Material(),
      shape: new CANNON.Box(new CANNON.Vec3(this.size / 2, 2, 0.05)) });


    this.mesh.add(this.front);
    this.world.addBody(this.front.body);

    this.back = this.front.clone();
    this.back.position.y = 0.5;
    this.back.position.z = -0.6;
    this.back.position.x = 3;
    this.back.body = new CANNON.Body({
      mass: 0,
      material: new CANNON.Material(),
      shape: new CANNON.Box(new CANNON.Vec3(this.size / 2, 2, 0.05)) });

    this.mesh.add(this.back);
    this.world.addBody(this.back.body);

    this.bottom = new THREE.Mesh(
    new THREE.BoxBufferGeometry(1.2, 4, 0.1, 16, 16),
    material);

    this.bottom.receiveShadow = true;
    this.bottom.castShadow = true;
    this.bottom.position.y = 0.5;
    this.bottom.position.z = 0;
    this.bottom.position.x = 4.45;
    this.bottom.rotateY(Math.PI / 2);
    this.bottom.body = new CANNON.Body({
      mass: 0,
      material: new CANNON.Material(),
      shape: new CANNON.Box(new CANNON.Vec3(2, 0.1, 0.5)) });

    this.bottomInside = new CANNON.Body({
      mass: 0,
      material: new CANNON.Material(),
      shape: new CANNON.Box(new CANNON.Vec3(0.5, 0.05, 0.5)) });


    this.mesh.add(this.bottom);
    this.world.addBody(this.bottom.body);
    this.world.addBody(this.bottomInside);

    this.cylinder = new THREE.Mesh(
    new THREE.CylinderGeometry(0.25, 0.25, 0.2, 32),
    new THREE.MeshPhysicalMaterial({
      color: "#fbff0e",
      roughness: 0.5,
      metalness: 0.2,
      emissive: "#000000" }));



    this.cylinder.receiveShadow = true;
    this.cylinder.castShadow = true;
  }

  position({ x, y, z }) {
    this.mesh.position.set(x, y, z);

    this.front.body.position = new CANNON.Vec3(
    this.front.position.x + x,
    this.front.position.y + y,
    this.front.position.z + z);

    this.back.body.position = new CANNON.Vec3(
    this.back.position.x + x,
    this.back.position.y + y,
    this.back.position.z - z);

    this.bottom.body.position = new CANNON.Vec3(
    this.bottom.position.x + x,
    this.bottom.position.y + y,
    this.bottom.position.z + z);

    this.bottomInside.position = new CANNON.Vec3(
    this.bottom.position.x + x,
    this.bottom.position.y + y,
    this.bottom.position.z + z);

  }

  rotate({ z }) {
    this.bottom.body.quaternion.setFromAxisAngle(new CANNON.Vec3(0, 0, -1), -z);
    this.bottomInside.quaternion.setFromAxisAngle(
    new CANNON.Vec3(0, 0, -1),
    -z);

  }}


class Column {
  constructor() {
    this.mesh = null;
  }

  static buildMaterial() {
    const material = new THREE.MeshPhysicalMaterial({
      color: "#ffffff",
      roughness: 0.1,
      metalness: 0.4,
      emissive: "#000000" });


    material.clearcoatRoughness = 0;
    material.clearcoat = 0;
    material.reflectivity = 1;
    material.aoMapIntensity = 0.5;
    material.displacementScale = 0;
    material.displacementBias = 0;
      material.aoMap = new THREE.TextureLoader().load(
    "//repo.bfw.wiki/bfwrepo/image/5f14d32694ad3.png");

    material.displacementMap = new THREE.TextureLoader().load(
    "//repo.bfw.wiki/bfwrepo/image/5f14d32694ad3.png");

    material.roughnessMap = new THREE.TextureLoader().load(
    "//repo.bfw.wiki/bfwrepo/image/5f14d32694ad3.png");

    material.normalMap = new THREE.TextureLoader().load(
    "//repo.bfw.wiki/bfwrepo/image/6085fa955c872.png");

    material.map = new THREE.TextureLoader().load(
    "//repo.bfw.wiki/bfwrepo/image/5e4350528640e.png");

    material.normalScale = new THREE.Vector2(6, 2);

    material.map.wrapS = THREE.RepeatWrapping;
    material.map.wrapT = THREE.RepeatWrapping;
    material.map.repeat.x = 0.1;
    material.map.repeat.y = 2;

    Column.material = material;
  }

  build() {
    const geometry = new THREE.BoxBufferGeometry(1.5, 0.2, 24, 16, 16);
    const column = new THREE.Mesh(geometry, Column.material);
    this.mesh = column;
    this.mesh.rotateX(Math.PI / 2);
    this.mesh.receiveShadow = true;
    this.mesh.castShadow = true;
    this.cylinder = new THREE.Mesh(
    new THREE.CylinderGeometry(0.25, 0.25, 0.2, 32),
    new THREE.MeshPhysicalMaterial({
      color: "#ffffff",
      roughness: 1,
      metalness: 0,
      emissive: "#000000" }));



    this.cylinder.receiveShadow = true;
    this.cylinder.castShadow = true;
  }}


new App().init();

    </script>

  

</body>

</html>
 

网友评论0