threejs打造3d跑车竞赛动画效果

代码语言:html

所属分类:三维

下面为部分代码预览,完整代码请点击下载或在bfwstudio webide中打开

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">

<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<style>
  body {
	margin: 0;
	overflow: hidden;
}
canvas {
	cursor: move;
}
</style>

</head>
<body translate="no">

<script type="text/javascript" src="http://repo.bfw.wiki/bfwrepo/js/three.js"></script>
<script src='http://repo.bfw.wiki/bfwrepo/js/OrbitControls.js'></script>
<script src='http://repo.bfw.wiki/bfwrepo/js/dat.gui.min.js'></script>
<script >
      window.addEventListener("DOMContentLoaded", app);

function app() {
  var scene,
  camera,
  renderer,
  textureLoader = new THREE.TextureLoader(),
  controls,
  GUI,
  road,
  cybertruck,
  ambientLight,
  daylight,
  fogColor;

  var adjustWindow = () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
  },
  init = () => {
    // setup
    let licensePlate = textureLoader.load("http://repo.bfw.wiki/bfwrepo/image/5df5d982ef313.png"),
    grassTile = textureLoader.load("http://repo.bfw.wiki/bfwrepo/image/5df5d982ef313.png"),
    roadTile = textureLoader.load("http://repo.bfw.wiki/bfwrepo/image/5df5d96d46d8e.png");

    scene = new THREE.Scene();
    fogColor = {
      h: 215,
      s: 80,
      l: 80 };

    scene.fog = new THREE.Fog(`hsl(${fogColor.h},${fogColor.s}%,${fogColor.l}%)`, 0.01, 272);

    camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.1, 1000);
    camera.position.set(20, 10, 20);
    camera.lookAt(scene.position);

    renderer = new THREE.WebGLRenderer({
      logarithmicDepthBuffer: false });

    renderer.setClearColor(scene.fog.color.getStyle());
    renderer.setSize(window.innerWidth, window.innerHeight);
    renderer.shadowMap.enabled = true;

    let camControls = new THREE.OrbitControls(camera, renderer.domElement);
    camControls.enablePan = false;

    // road
    road = new Road(grassTile, roadTile);

    // cybertruck
    cybertruck = new Cybertruck(licensePlate);
    cybertruck.mesh.name = "Cybertruck";
    cybertruck.mesh.position.y = cybertruck.height / 2;

    // ambient light
    ambientLight = new THREE.AmbientLight(0xffffff);
    ambientLight.intensity = 1;
    scene.add(ambientLight);

    // daylight
    daylight = new THREE.PointLight(0xffffff, ambientLight.intensity * 2);
    daylight.position.set(0, 64, 0);
    daylight.castShadow = true;
    scene.add(daylight);

    // config
    controls = {
      daylight: ambientLight.intensity,
      speed: cybertruck.speed,
      resetCam: () => {
        camControls.reset();
      } };

    GUI = new dat.GUI();
    GUI.add(controls, "daylight", 0.1, 1, 0.01).name("Daylight").onChange(e => {
      let newVal = controls.daylight;
      cybertruck.headlight.intensity = (1 - newVal) * 2;
      cybertruck.rearlight.intensity = (1 - newVal) * 2;
      ambientLight.intensity = newVal;
      daylight.intensity = newVal * 2;

      let h = fogColor.h,
      s = fogColor.s,
      l = newVal * 100;
      fogColor.l = l * 0.8;

      let daylightColorStr = `hsl(${h},${s}%,${l.toFixed(0)}%)`,
      fogColorStr = `hsl(${h},${s}%,${fogColor.l.toFixed(0)}%)`;

      daylight.color = new THREE.Color(daylightColorStr);
      renderer.setClearColor(fogColorStr);
      scene.fog.color.set(fogColorStr);
    });
    GUI.add(controls, "speed", 0, 60, 1).name("Speed (MPH)").onChange(e => {
      cybertruck.speed = controls.speed;
    });
    GUI.add(controls, "resetCam").name("Reset Camera");

    // first render
    document.body.appendChild(renderer.domElement);
    renderScene();
  },
  renderScene = () => {
    updateObjects();
    renderer.render(scene, camera);
    requestAnimationFrame(renderScene);
  },
  spawnObjects = () => {
    scene.add(road.mesh);
    scene.add(cybertruck.mesh);
  },
  updateObjects = () => {
    if (scene.getObjectByName(cybertruck.mesh.name)) {
      cybertruck.move();

      if (cybertruck.mesh.position.z > road.tileSize)
      cybertruck.mesh.position.z -= road.tileSize;

      let cybertruckZ = cybertruck.mesh.position.z;
      daylight.position.z = cybertruckZ;
      scene.position.z = -cybertruckZ;
    }
  };

  init();
  window.addEventListener("load", spawnObjects);
  window.addEventListener("resize", adjustWindow);
}

class Cybertruck {
  constructor(licensePlateImg) {
    this.speed = 5;
    this.wireframes = false;
    this.width = 8;
    this.height = 7.5;
    this.depth = 23;
    this.mesh = new THREE.Object3D();

    let W = this.width,
    H = this.height,
    D = this.depth,
    flipXVertices = a => [-a[0], a[1], a[2]],
    toVectors = a => new THREE.Vector3(W * a[0], H * a[1], D * a[2]),
    reverseFaceDraws = a => a.reverse(),
    toFaces = a => new THREE.Face3(a[0], a[1], a[2]);

    // I. Body
    // A. Main
    let bodyVerticesArr = [
    // back (0–3)
    [-0.45, 0.26, -0.5],
    [0.45, 0.26, -0.5],
    [-0.45, -0.1, -0.48],
    [0.45, -0.1, -0.48],
    // top (4–5)
    [-0.326, 0.5, 0.08],
    [0.326, 0.5, 0.08],
    // middle (6–19)
    [-0.45, -0.1, -0.38],
    [0.45, -0.1, -0.38],
    [-0.45, 0.06, -0.36],
    [0.45, 0.06, -0.36],
    [-0.45, 0.06, -0.24],
    [0.45, 0.06, -0.24],
    [-0.45, -0.15, -0.18],
    [0.45, -0.15, -0.18],
    [-0.45, -0.17, 0.255],
    [0.45, -0.17, 0.255],
    [-0.45, 0.06, 0.303],
    [0.45, 0.06, 0.303],
    [-0.45, 0.06, 0.42],
    [0.45, 0.06, 0.42],
    // upper front (20–23)
    [-0.45, 0.08, 0.47],
    [0.45, 0.08, 0.47],
    [-0.33, 0.045, 0.5],
    [0.33, 0.045, 0.5],
    // lower front (24–27)
    [-0.45, -0.13, 0.46],
    [0.45, -0.13, 0.46],
    [-0.343, -0.13, 0.488],
    [0.343, -0.13, 0.488],
    // bottom flaps (28–31)
    [-0.41, -0.21, -0.173],
    [0.41, -0.21, -0.173],
    [-0.41, -0.23, 0.25],
    [0.41, -0.23, 0.25],
    // windows (32–39)
    [-0.4225, 0.27, -0.14],
    [0.4225, 0.27, -0.14],
    [-0.379, 0.39, -0.13],
    [0.379, 0.39, -0.13],
    [-0.337, 0.47, 0.08],
    [0.337, 0.47, 0.08],
    [-0.425, 0.17, 0.36],
    [0.425, 0.17, 0.36]],

    bodyVertices = bodyVerticesArr.map(toVectors),
    bodyFacesArr = [
    [0, 1, 3],
    [3, 2, 0],
    [0, 4, 5],
    [5, 1, 0],
    [5, 37, 35],
    [1, 5, 35],
    [1, 35, 33],
    [33, 21, 1],
    [39, 21, 33],
    [5, 21, 37],
    [21, 39, 37],
    [4, 34, 36],
    [0, 34, 4],
    [0, 32, 34],
    [32, 0, 20],
    [38, 32, 20],
    [4, 36, 20],
    [20, 36, 38],
    [20, 18, 24],
    [20, 0, 18],
    [18, 0, 16],
    [16, 0, 10],
    [10, 0, 8],
    [8, 0, 2],
    [2, 6, 8],
    [16, 10, 14],
    [12, 14, 10],
    [14, 12, 28],
    [28, 30, 14],
    [21, 25, 19],
    [21, 19, 1],
    [19, 17, 1],
    [17, 11, 1],
    [11, 9, 1],
    [1, 9, 7],
    [7, 3, 1],
    [11, 17, 15],
    [15, 13, 11],
    [15, 31, 29],
    [29, 13, 15],
    [5, 4, 20],
    [20, 21, 5],
    [21, 20, 22],
    [22, 23, 21],
    [22, 20, 24],
    [24, 26, 22],
    [23, 22, 26],
    [26, 27, 23],
    [23, 27, 25],
    [25, 21, 23],
    [2, 3, 7],
    [7, 6, 2],
    [6, 7, 9],
    [9, 8, 6],
    [8, 9, 11],
    [11, 10, 8],
    [10, 11, 13],
    [13, 12, 10],
    [12, 13, 29],
    [29, 28, 12],
    [28, 29, 31],
    [31, 30, 28],
    [30, 31, 15],
    [15, 14, 30],
    [14, 15, 17],
    [17, 16, 14],
    [16, 17, 19],
    [19, 18, 16],
    [18, 19, 25],
    [25, 24, 18],
    [24, 25, 26],
    [25, 27, 26],
    [34, 32, 33],
    [33, 35, 34],
    [34, 35, 37],
    [37, 36, 34],
    [36, 37, 39],
    [39, 38, 36],
    [33, 32, 38],
    [38, 39, 33]],

    bodyFaces = bodyFacesArr.map(toFaces),
    bodyGeo = new THREE.Geometry(),
    bodyMat = new THREE.MeshStandardMaterial({
      color: 0xbac3c8,
      wireframe: this.wireframes });


    bodyGeo.vertices = bodyVertices;
    bodyGeo.faces = bodyFaces;
    bodyGeo.computeFaceNormals();

    let body = new THREE.Mesh(bodyGeo, bodyMat);
    this.mesh.add(body);

    // B. Door Handles
    let doorHandleGeo = new THREE.BoxGeometry(W * 0.01, W * 0.024, D * 0.0375),
    doorHandleFR = new THREE.Mesh(doorHandleGeo, bodyMat);

    // front right
    doorHandleFR.position.set(W * -0.45, H * 0.13, D * 0.0844);
    doorHandleFR.rotation.x = 4 * Math.PI / 180;
    body.add(doorHandleFR);

    // front left
    let doorHandleFL = doorHandleFR.clone();
    doorHandleFL.position.x *= -1;
    body.add(doorHandleFL);

    // back right
    let doorHandleBR = doorHandleFR.clone();
    doorHandleBR.position.y = H * 0.165;
    doorHandleBR.position.z = D * -0.1094;
    body.add(doorHandleBR);

    // back left
    let doorHandleBL = doorHandleBR.clone();
    doorHandleBL.position.x *= -1;
    body.add(doorHandleBL);

    // C. Door Outlines
    let doorOutlineMat = new THREE.LineBasicMaterial({
      color: 0x000000,
      transparent: true,
      opacity: 0.25 }),

    doorOutlineFLVerticesArr = [
    [0.451, -0.17, 0.255],
    [0.451, 0.12, 0.255],
    [0.425, 0.192, 0.255],
    [0.424, 0.192, 0.255]],

    doorOutlineFLVertices = doorOutlineFLVerticesArr.map(toVectors),
    doorOutlineFLGeo = new THREE.Geometry();

    // front left
    doorOutlineFLGeo.vertices = doorOutlineFLVertices;

    let doorOutlineFL = new THREE.Line(doorOutlineFLGeo, doorOutlineMat);
    this.mesh.add(doorOutlineFL);

    // front right
    let doorOutlineFRVerticesArr = doorOutlineFLVerticesArr.map(flipXVertices),
    doorOutlineFRVertices = doorOutlineFRVerticesArr.map(toVectors),
    doorOutlineFRGeo = new THREE.Geometry();

    doorOutlineFRGeo.vertices = doorOutlineFRVertices;

    let doorOutlineFR = new THREE.Line(doorOutlineFRGeo, doorOutlineMat);
    this.mesh.add(doorOutlineFR);

    // middle left
    let doorOutlineMLVerticesArr = [
    [0.41, -0.23, 0.0594],
    [0.4505, -0.16, 0.0594],
    [0.4505, 0.156, 0.0531],
    [0.424, 0.233, 0.05],
    [0.41, 0.233, 0.048]],

    doorOutlineMLVertices = doorOutlineMLVerticesArr.map(toVectors),
    doorOutlineMLGeo = new THREE.Geometry();

    doorOutlineMLGeo.vertices = doorOutlineMLVertices;

    let doorOutlineML = new THREE.Line(doorOutlineMLGeo, doorOutlineMat);
    this.mesh.add(doorOutlineML);

    // middle right
    let doorOutlineMRVerticesArr = doorOutlineMLVerticesArr.map(flipXVertices),
    doorOutlineMRVertices = doorOutlineMRVerticesArr.map(toVectors),
    doorOutlineMRGeo = new THREE.Geometry();

    doorOutlineMRGeo.vertices = doorOutlineMRVertices;

    let doorOutlineMR = new THREE.Line(doorOutlineMRGeo, doorOutlineMat);
    this.mesh.add(doorOutlineMR);

    // back left
    let doorOutlineBLVerticesArr = [
    [0.399, -0.23, -0.1313],
    [0.45, -0.152, -0.1359],
    [0.4505, 0.195, -0.1406],
    [0.424, 0.2705, -0.1396],
    [0.4, 0.2705, -0.1396]],

    doorOutlineBLVertices = doorOutlineBLVerticesArr.map(toVectors),
    doorOutlineBLGeo = new THREE.Geometry();

    doorOutlineBLGeo.vertices = doorOutlineBLVertices;

    let doorOutlineBL = new THREE.Line(doorOutlineBLGeo, doorOutlineMat);
    this.mesh.add(doorOutlineBL);

    // back right
    let doorOutlineBRVerticesArr = doorOutlineBLVerticesArr.map(flipXVertices),
    doorOutlineBRVertices = doorOutlineBRVerticesArr.map(toVectors),
    doorOutlineBRGeo = new THREE.Geometry();

    doorOutlineBRGeo.vertices = doorOutlineBRVertices;

    let doorOutlineBR = new THREE.Line(doorOutlineBRGeo, doorOutlineMat);
    this.mesh.add(doorOutlineBR);

    // D. Fuel Cap
    let fuelCapVerticesArr = [
    [0.4502, -0.014, -0.378],
    [0.4502, -0.014, -0.4],
    [0.4502, 0.06, -0.4],
    [0.4502, 0.06, -0.36]],

    fuelCapVertices = fuelCapVerticesArr.map(toVectors),
    fuelCapGeo = new THREE.Geometry();

    fuelCapGeo.vertices = fuelCapVertices;

    let fuelCap = new THREE.Line(fuelCapGeo, doorOutlineMat);
    this.mesh.add(fuelCap);

    // II. Top Parts
    // A. Window
    let windowMat = new THREE.MeshStandardMaterial({
      color: 0x101010,
      wireframe: this.wireframes }),

    lightMat = new THREE.MeshBasicMaterial({
      color: 0xffffff,
      wireframe: this.wireframes }),

    topWindowVerticesArr = [
    [-0.371, 0.415, -0.13],
    [0.371, 0.415, -0.13],
    [-0.326, 0.5, 0.08],
    [0.326, 0.5, 0.08],
    [-0.4145, 0.2, 0.36],
    [0.4145, 0.2, 0.36]],

    topWindowVertices = topWindowVerticesArr.map(toVectors),
    topWindowFacesArr = [
    [1, 0, 2],
    [2, 3, 1],
    [3, 2, 4],
    [4, 5, 3]],

    topWindowFaces = topWindowFacesArr.map(toFaces),
    topWindowGeo = new THREE.Geometry();

    topWindowGeo.vertices = topWindowVertices;
    topWindowGeo.faces = topWindowFaces;
    topWindowGeo.computeVertexNormals();
    topWindowGeo.computeFaceNormals();

    let topWindow = new THREE.Mesh(topWindowGeo, windowMat);
    this.mesh.add(topWindow);

    // B. Light
    let topLightVerticesArr = [
    [-0.26, 0.49, 0.09],
    [0.26, 0.49, 0.09],
    [-0.26, 0.48, 0.1],
    [0.26, 0.48, 0.1]],

    topLightVertices = topLightVerticesArr.map(toVectors),
    topLightFacesArr = [
    [1, 0, 2],
    [2, 3, 1]],

    topLightFaces = topLightFacesArr.map(toFaces),
    topLightGeo = new THREE.Geometry();

    topLightGeo.vertices = topLightVertices;
    topLightGeo.faces = topLightFaces;
    topLightGeo.computeFaceNormals();

    let topLight = new THREE.Mesh(topLightGeo, lightMat);
    this.mesh.add(topLight);

    // C. Sliding Door
    let slidingDoorMat = new THREE.MeshStandardMaterial({
      color: 0x767c7f,
      wireframe: this.wireframes }),

    slidingDoorVerticesArr = [
    [-0.35, 0.274, -0.472],
    [0.35, 0.274, -0.472],
    [-0.35, 0.407, -0.145],
    [0.35, 0.407, -0.145]],

    slidingDoorVertices = slidingDoorVerticesArr.map(toVectors),
    slidingDoorFacesArr = [
    [1, 0, 2],
    [2, 3, 1]],

    slidingDoorFaces = slidingDoorFacesArr.map(toFaces),
    slidingDoorGeo = new THREE.Geometry();

    slidingDoorGeo.vertices = slidingDoorVertices;
    slidingDoorGeo.faces = slidingDoorFaces;
    slidingDoorGeo.computeFaceNormals();

    let slidingDoor = new THREE.Mesh(slidingDoorGeo, slidingDoorMat);
    this.mesh.add(slidingDoor);

    // III. Side Windows
    let sideWindowsVerticesArr = [
    [-0.4, 0.27, -0.14],
    [0.4, 0.27, -0.14],
    [-0.351, 0.39, -.........完整代码请登录后点击上方下载按钮下载查看

网友评论0