特斯拉(Tesla)

特斯拉(Tesla)

示例

在這裏插入圖片描述

CSS

body {
	margin: 0;
	overflow: hidden;
}
canvas {
	cursor: move;
}

JS

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("https://i.ibb.co/R9tkkV0/license-plate.png"),
				grassTile = textureLoader.load("https://i.ibb.co/KrgXYY5/grass.jpg"),
				roadTile = textureLoader.load("https://i.ibb.co/khVnGNv/road.jpg");


			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.13],
				[0.351, 0.39,-0.13],
				[-0.315,0.47,0.08],
				[0.315, 0.47,0.08],
				[-0.43, 0.17,0.36],
				[0.43,  0.17,0.36]
			],
			sideWindowsVertices = sideWindowsVerticesArr.map(toVectors),
			sideWindowsFacesArr = [
				[2,3,1],
				[1,0,2],
				[2,4,5],
				[5,3,2],
				[4,6,7],
				[7,5,4],
				[4,2,0],
				[0,6,4],
				[5,7,1],
				[1,3,5],
				[0,1,7],
				[7,6,0]
			],
			sideWindowsFaces = sideWindowsFacesArr.map(toFaces),
			sideWindowsGeo = new THREE.Geometry();


		sideWindowsGeo.vertices = sideWindowsVertices;
		sideWindowsGeo.faces = sideWindowsFaces;
		sideWindowsGeo.computeVertexNormals();
		sideWindowsGeo.computeFaceNormals();


		let sideWindows = new THREE.Mesh(sideWindowsGeo,windowMat);
		this.mesh.add(sideWindows);


		// IV. Front Lights
		// A. Upper
		let frontLightVerticesArr = [
				[-0.45,  0.075,0.4701],
				[-0.33,  0.04, 0.4999],
				[0.33,   0.04, 0.4999],
				[0.45,   0.075,0.4701],


				[-0.45,  0.043,0.4685],
				[-0.3315,0.02, 0.4985],
				[0.3315, 0.02, 0.4985],
				[0.45,   0.043,0.4685]
			],
			frontLightVertices = frontLightVerticesArr.map(toVectors),
			frontLightFacesArr = [
				[1,0,4],
				[4,5,1],
				[2,1,5],
				[5,6,2],
				[3,2,6],
				[6,7,3]
			],
			frontLightFaces = frontLightFacesArr.map(toFaces),
			frontLightGeo = new THREE.Geometry();


		frontLightGeo.vertices = frontLightVertices;
		frontLightGeo.faces = frontLightFaces;
		frontLightGeo.computeFaceNormals();


		let frontLight = new THREE.Mesh(frontLightGeo,lightMat);
		this.mesh.add(frontLight);


		// B. Lower
		let lowerLightMat = new THREE.MeshBasicMaterial({
				color: 0xff9e59,
				wireframe: this.wireframes
			}),
			lowerLFrontLightVerticesArr = [
				[0.343,-0.13,0.4881],
				[0.45, -0.13,0.4601],
				[0.343,-0.12,0.4885],
				[0.45, -0.12,0.4605]
			],
			lowerLFrontLightVertices = lowerLFrontLightVerticesArr.map(toVectors),
			lowerLFrontLightFacesArr = [
				[0,1,3],
				[3,2,0]
			],
			lowerLFrontLightFaces = lowerLFrontLightFacesArr.map(toFaces),
			lowerLFrontLightGeo = new THREE.Geometry();


		// left
		lowerLFrontLightGeo.vertices = lowerLFrontLightVertices;
		lowerLFrontLightGeo.faces = lowerLFrontLightFaces;
		lowerLFrontLightGeo.computeFaceNormals();


		let lowerLFrontLight = new THREE.Mesh(lowerLFrontLightGeo,lowerLightMat);
		this.mesh.add(lowerLFrontLight);


		// right
		let lowerRFrontLightVerticesArr = lowerLFrontLightVerticesArr.map(flipXVertices),
			lowerRFrontLightVertices = lowerRFrontLightVerticesArr.map(toVectors),
			lowerRFrontLightFacesArr = lowerLFrontLightFacesArr.map(reverseFaceDraws),
			lowerRFrontLightFaces = lowerRFrontLightFacesArr.map(toFaces),
			lowerRFrontLightGeo = new THREE.Geometry();


		lowerRFrontLightGeo.vertices = lowerRFrontLightVertices;
		lowerRFrontLightGeo.faces = lowerRFrontLightFaces;
		lowerRFrontLightGeo.computeFaceNormals();


		let lowerRFrontLight = new THREE.Mesh(lowerRFrontLightGeo,lowerLightMat);
		this.mesh.add(lowerRFrontLight);


		// V. Back Light
		let backLightGeo = new THREE.PlaneGeometry(W*0.9,H*0.06),
			backLightMat = new THREE.MeshStandardMaterial({
				color: 0x101010,
				wireframe: this.wireframes
			}),
			backLight = new THREE.Mesh(backLightGeo,backLightMat);


		backLightGeo.translate(0,H*0.03,0);
		backLight.position.set(0,H*0.26,D*-0.5);
		backLight.rotation.set(171 * Math.PI/180,0,0);


		// red part
		let backLightInnerGeo = new THREE.PlaneGeometry(W*0.9 - H*0.04, H*0.02),
			backLightInnerMat = new THREE.MeshBasicMaterial({
				color: 0xd65a65,
				wireframe: this.wireframes
			}),
			backLightInner = new THREE.Mesh(backLightInnerGeo,backLightInnerMat);


		backLightInnerGeo.translate(0,H*0.03,0);
		backLightInner.position.set(0,0,0.01);
		backLight.add(backLightInner);


		let backLightAreaGeo = new THREE.PlaneGeometry(W*0.18, H*0.02),
			backLightAreaMat = new THREE.MeshBasicMaterial({
				color: 0xfdffb8,
				wireframe: this.wireframes
			}),
			backLightArea2 = new THREE.Mesh(backLightAreaGeo,backLightAreaMat);


		// middle light
		backLightAreaGeo.translate(0,H*0.03,0);
		backLightArea2.position.set(0,0,0.01);
		backLightInner.add(backLightArea2);


		// left light
		let backLightArea1 = backLightArea2.clone();
		backLightArea1.position.set(W*-0.33,0,0.01);
		backLightInner.add(backLightArea1);


		// right light
		let backLightArea3 = backLightArea2.clone();
		backLightArea3.position.set(W*0.33,0,0.01);
		backLightInner.add(backLightArea3);


		this.mesh.add(backLight);


		// VI. Left Side Part Above Wheels
		let sideMat = new THREE.MeshStandardMaterial({
				color: 0x2b2b2b,
				wireframe: this.wireframes
			}),
			leftSideVerticesArr = [
				// top (0–19)
				[0.45, -0.1,  -0.4],
				[0.5,  -0.1,  -0.3825],
				[0.45, 0.06,  -0.36],
				[0.5,  0.03,  -0.35],
				[0.45, 0.06,  -0.236],
				[0.5,  0.03,  -0.24],
				[0.45, -0.15, -0.18],
				[0.5,  -0.15, -0.192],
				[0.41, -0.21, -0.173],
				[0.48, -0.21, -0.19],
				[0.41, -0.23, 0.2498],
				[0.48, -0.23, 0.261],
				[0.45, -0.17, 0.255],
				[0.5,  -0.17, 0.263],
				[0.45, 0.06,  0.3015],
				[0.5,  0.03,  0.3035],
				[0.45, 0.06,  0.42],
				[0.5,  0.03,  0.4165],
				[0.45, -0.13, 0.46],
				[0.5,  -0.13, 0.45],
				// bottom (20–41)
				[0.45, -0.074,-0.379],
				[0.5,  -0.1,  -0.3775],
				[0.45, 0.04,  -0.35],
				[0.5,  0.015, -0.348],
				[0.45, 0.04,  -0.2505],
				[0.5,  0.015, -0.2435],
				[0.45, -0.15, -0.197],
				[0.5,  -0.15, -0.197],
				[0.355,-0.29, -0.19],
				[0.4,  -0.29, -0.19],
				[0.355,-0.31, 0.2582],
				[0.4,  -0.31, 0.26],
				[0.45, -0.17, 0.265],
				[0.5,  -0.17, 0.267],
				[0.45, 0.04,  0.3099],
				[0.5,  0.015, 0.3065],
				[0.45, 0.04,  0.418],
				[0.5,  0.015, 0.4135],
				[0.45, -0.13, 0.455],
				[0.5,  -0.13, 0.445],
				[0.48, -0.21, -0.194],
				[0.48, -0.23, 0.265]
			],
			leftSideVertices = leftSideVerticesArr.map(toVectors),
			leftSideFacesArr = [
				[0,2,3],
				[3,1,0],
				[2,4,5],
				[5,3,2],
				[4,6,7],
				[7,5,4],
				[6,8,9],
				[9,7,6],
				[8,10,11],
				[11,9,8],
				[10,12,13],
				[13,11,10],
				[12,14,15],
				[15,13,12],
				[14,16,17],
				[17,15,14],
				[16,18,19],
				[19,17,16],
				[23,22,20],
				[20,21,23],
				[25,24,22],
				[22,23,25],
				[27,26,24],
				[24,25,27],
				[31,30,28],
				[28,29,31],
				[35,34,32],
				[32,33,35],
				[37,36,34],
				[34,35,37],
				[39,38,36],
				[36,37,39],
				[0,1,21],
				[21,20,0],
				[20,22,2],
				[2,0,20],
				[22,24,4],
				[4,2,22],
				[24,26,6],
				[6,4,24],
				[26,28,8],
				[8,6,26],
				[28,30,10],
				[10,8,28],
				[30,32,12],
				[12,10,30],
				[32,34,14],
				[14,12,32],
				[34,36,16],
				[16,14,34],
				[36,38,18],
				[18,16,36],
				[3,23,21],
				[21,1,3],
				[5,25,23],
				[23,3,5],
				[7,27,25],
				[25,5,7],
				[27,7,9],
				[9,40,27],
				[40,9,29],
				[26,27,40],
				[40,29,26],
				[26,29,28],
				[11,31,29],
				[29,9,11],
				[11,41,31],
				[13,33,41],
				[41,11,13],
				[33,32,30],
				[30,41,33],
				[41,10,30],
				[30,31,41],
				[15,35,33],
				[33,13,15],
				[17,37,35],
				[35,15,17],
				[19,39,37],
				[37,17,19],
				[38,39,19],
				[19,18,38]
			],
			leftSideFaces = leftSideFacesArr.map(toFaces),
			leftSideGeo = new THREE.Geometry();


		leftSideGeo.vertices = leftSideVertices;
		leftSideGeo.faces = leftSideFaces;
		leftSideGeo.computeFaceNormals();


		let leftSide = new THREE.Mesh(leftSideGeo,sideMat);
		leftSide.castShadow = true;
		this.mesh.add(leftSide);


		// VII. Right Side Part Above Wheels
		let rightSideVerticesArr = leftSideVerticesArr.map(flipXVertices),
			rightSideVertices = rightSideVerticesArr.map(toVectors),
			rightSideFacesArr = leftSideFacesArr.map(reverseFaceDraws),
			rightSideFaces = rightSideFacesArr.map(toFaces),
			rightSideGeo = new THREE.Geometry();


		rightSideGeo.vertices = rightSideVertices;
		rightSideGeo.faces = rightSideFaces;
		rightSideGeo.computeFaceNormals();


		let rightSide = new THREE.Mesh(rightSideGeo,sideMat);
		rightSide.castShadow = true;
		this.mesh.add(rightSide);


		// VIII. Back
		// A. Connecting Bumper
		let backVerticesArr = [
				[-0.423,-0.1,  -0.47],
				[0.423, -0.1,  -0.47],
				[-0.423,-0.222,-0.47],
				[0.423, -0.222,-0.47],
				[-0.423,-0.1,  -0.38],
				[0.423, -0.1,  -0.38],
				[-0.423,-0.285,-0.4],
				[0.423, -0.285,-0.4]
			],
			backVertices = backVerticesArr.map(toVectors),
			backFacesArr = [
				[0,1,3],
				[3,2,0],
				[4,0,2],
				[2,6,4],
				[1,5,7],
				[7,3,1],
				[1,0,4],
				[4,5,1],
				[5,4,6],
				[6,7,5],
				[2,3,7],
				[7,6,2]
			],
			backFaces = backFacesArr.map(toFaces),
			backGeo = new THREE.Geometry(),
			backMat = new THREE.MeshStandardMaterial({
				color: 0x101010,
				wireframe: this.wireframes
			});


		backGeo.vertices = backVertices;
		backGeo.faces = backFaces;
		backGeo.computeFaceNormals();


		let back = new THREE.Mesh(backGeo,backMat);
		this.mesh.add(back);


		// B. Red Lines
		let redLinesMat = new THREE.MeshStandardMaterial({
				color: 0xd81937,
				wireframe: this.wireframes
			}),
			leftRedLinesVerticesArr = [
				[0.356, -0.115,-0.4701],
				[0.4231,-0.115,-0.4701],
				[0.4231,-0.115,-0.385],
				[0.356, -0.135,-0.4701],
				[0.4231,-0.135,-0.4701],
				[0.4231,-0.135,-0.387]
			],
			leftRedLinesVertices = leftRedLinesVerticesArr.map(toVectors),
			leftRedLinesFacesArr = [
				[0,1,4],
				[4,3,0],
				[1,2,5],
				[5,4,1]
			],
			leftRedLinesFaces = leftRedLinesFacesArr.map(toFaces),
			leftRedLinesGeo = new THREE.Geometry();


		// left
		leftRedLinesGeo.vertices = leftRedLinesVertices;
		leftRedLinesGeo.faces = leftRedLinesFaces;
		leftRedLinesGeo.computeFaceNormals();


		let leftRedLines = new THREE.Mesh(leftRedLinesGeo,redLinesMat);
		this.mesh.add(leftRedLines);


		let leftSmallBackLightVerticesArr = [
				[0.4,   -0.135,-0.4702],
				[0.4231,-0.135,-0.4702],
				[0.4,   -0.115,-0.4702],
				[0.4231,-0.115,-0.4702]
			],
			leftSmallBackLightVertices = leftSmallBackLightVerticesArr.map(toVectors),
			leftSmallBackLightFacesArr = [
				[2,3,1],
				[1,0,2]
			],
			leftSmallBackLightFaces = leftSmallBackLightFacesArr.map(toFaces),
			leftSmallBackLightGeo = new THREE.Geometry();


		leftSmallBackLightGeo.vertices = leftSmallBackLightVertices;
		leftSmallBackLightGeo.faces = leftSmallBackLightFaces;
		leftSmallBackLightGeo.computeFaceNormals();


		let leftSmallBackLight = new THREE.Mesh(leftSmallBackLightGeo,backLightInnerMat);
		this.mesh.add(leftSmallBackLight);


		// right
		let rightRedLinesVerticesArr = leftRedLinesVerticesArr.map(flipXVertices),
			rightRedLinesVertices = rightRedLinesVerticesArr.map(toVectors),
			rightRedLinesFacesArr = [
				[1,0,3],
				[3,4,1],
				[2,1,4],
				[4,5,2]
			],
			rightRedLinesFaces = rightRedLinesFacesArr.map(toFaces),
			rightRedLinesGeo = new THREE.Geometry();


		rightRedLinesGeo.vertices = rightRedLinesVertices;
		rightRedLinesGeo.faces = rightRedLinesFaces;
		rightRedLinesGeo.computeFaceNormals();


		let rightRedLines = new THREE.Mesh(rightRedLinesGeo,redLinesMat);
		this.mesh.add(rightRedLines);


		let rightSmallBackLightVerticesArr = leftSmallBackLightVerticesArr.map(flipXVertices),
			rightSmallBackLightVertices = rightSmallBackLightVerticesArr.map(toVectors),
			rightSmallBackLightFacesArr = leftSmallBackLightFacesArr.map(reverseFaceDraws),
			rightSmallBackLightFaces = rightSmallBackLightFacesArr.map(toFaces),
			rightSmallBackLightGeo = new THREE.Geometry();


		rightSmallBackLightGeo.vertices = rightSmallBackLightVertices;
		rightSmallBackLightGeo.faces = rightSmallBackLightFaces;
		rightSmallBackLightGeo.computeFaceNormals();


		let rightSmallBackLight = new THREE.Mesh(rightSmallBackLightGeo,backLightInnerMat);
		this.mesh.add(rightSmallBackLight);


		// C. Bumper
		let backBumperVerticesArr = [
				[-0.452,-0.15, -0.49],
				[-0.143,-0.15, -0.49],
				[-0.415,-0.223,-0.49],
				[-0.128,-0.223,-0.49],
				[0.143, -0.15, -0.49],
				[0.452, -0.15, -0.49],
				[0.128, -0.223,-0.49],
				[0.415, -0.223,-0.49],
				[-0.208,-0.25, -0.49],
				[0.208, -0.25, -0.49],
				[-0.423,-0.286,-0.4],
				[-0.226,-0.311,-0.4],
				[0.226, -0.311,-0.4],
				[0.423, -0.286,-0.4],
				[-0.424,-0.15, -0.47],
				[-0.143,-0.15, -0.47],
				[0.143, -0.15, -0.47],
				[0.424, -0.15, -0.47],
				[-0.128,-0.223,-0.47],
				[0.128, -0.223,-0.47],
				[-0.5,  -0.15, -0.385],
				[-0.424,-0.15, -0.385],
				[0.424, -0.15, -0.385],
				[0.5,   -0.15, -0.385],
				[-0.424,-0.223,-0.47],
				[0.424, -0.223,-0.47],
				[-0.226,-0.286,-0.4],
				[0.226, -0.286,-0.4]
			],
			backBumperVertices = backBumperVerticesArr.map(toVectors),
			backBumperFacesArr = [
				[0,1,3],
				[3,2,0],
				[4,5,7],
				[7,6,4],
				[2,3,8],
				[6,7,9],
				[6,9,8],
				[3,6,8],
				[2,8,11],
				[11,10,2],
				[8,9,12],
				[12,11,8],
				[9,7,13],
				[13,12,9],
				[14,15,1],
				[1,0,14],
				[16,17,5],
				[5,4,16],
				[1,15,18],
				[18,3,1],
				[16,4,6],
				[6,19,16],
				[18,19,6],
				[6,3,18],
				[20,21,14],
				[20,14,0],
				[22,23,17],
				[23,5,17],
				[20,0,2],
				[2,10,20],
				[7,5,23],
				[23,13,7],
				[21,20,10],
				[23,22,13],
				[14,21,10],
				[10,24,14],
				[15,14,24],
				[24,18,15],
				[16,19,25],
				[25,17,16],
				[17,25,13],
				[13,22,17],
				[18,24,10],
				[10,26,18],
				[19,18,26],
				[26,27,19],
				[25,19,27],
				[27,13,25],
				[26,10,11],
				[27,26,11],
				[11,12,27],
				[13,27,12]
			],
			backBumperFaces = backBumperFacesArr.map(toFaces),
			backBumperGeo = new THREE.Geometry();


		backBumperGeo.vertices = backBumperVertices;
		backBumperGeo.faces = backBumperFaces;
		backBumperGeo.computeFaceNormals();


		let backBumper = new THREE.Mesh(backBumperGeo,sideMat);
		backBumper.castShadow = true;
		this.mesh.add(backBumper);


		// IX. Front Bumper
		let frontBumperVerticesArr = [
				[-0.5,  -0.13, 0.4501],
				[0.5,   -0.13, 0.4501],
				[-0.346,-0.13, 0.495],
				[0.346, -0.13, 0.495],
				[-0.5,  -0.194,0.4501],
				[0.5,   -0.194,0.4501],
				[-0.346,-0.194,0.495],
				[0.346, -0.194,0.495],
				[-0.466,-0.242,0.4501],
				[0.466, -0.242,0.4501],
				[-0.346,-0.242,0.485],
				[0.346, -0.242,0.485],
				[-0.346,-0.31, 0.4501],
				[0.346, -0.31, 0.4501],
				[-0.346,-0.194,0.47],
				[0.346, -0.194,0.47],
				[-0.346,-0.242,0.47],
				[0.346, -0.242,0.47]
			],
			frontBumperVertices = frontBumperVerticesArr.map(toVectors),
			frontBumperFacesArr = [
				[0,1,5],
				[5,4,0],
				[1,0,2],
				[2,3,1],
				[2,0,4],
				[4,6,2],
				[3,2,6],
				[6,7,3],
				[1,3,7],
				[7,5,1],
				[4,5,9],
				[9,8,4],
				[6,4,8],
				[8,10,6],
				[5,7,11],
				[11,9,5],
				[8,9,13],
				[13,12,8],
				[10,8,12],
				[11,10,12],
				[12,13,11],
				[9,11,13],
				[14,15,7],
				[7,6,14],
				[15,14,16],
				[16,17,15],
				[17,16,10],
				[10,11,17],
				[14,6,10],
				[10,16,14],
				[7,15,17],
				[17,11,7]
			],
			frontBumperFaces = frontBumperFacesArr.map(toFaces),
			frontBumperGeo = new THREE.Geometry();


		frontBumperGeo.vertices = frontBumperVertices;
		frontBumperGeo.faces = frontBumperFaces;
		frontBumperGeo.computeFaceNormals();


		let frontBumper = new THREE.Mesh(frontBumperGeo,sideMat);
		frontBumper.castShadow = true;
		this.mesh.add(frontBumper);


		// X. Front Cylinders
		let cylinderGeo = new THREE.CylinderBufferGeometry(W*0.025,W*0.025,H*0.32,32),
			cylinderMat = new THREE.MeshStandardMaterial({
				color: 0x969696,
				wireframe: this.wireframes
			}),
			leftCylinder = new THREE.Mesh(cylinderGeo,cylinderMat);
		
		// left
		leftCylinder.position.set(W*0.33,H*-0.09,D*0.355);
		leftCylinder.rotation.x = -5 *Math.PI/180;
		this.mesh.add(leftCylinder);


		// right
		let rightCylinder = leftCylinder.clone();
		rightCylinder.position.x *= -1;
		this.mesh.add(rightCylinder);


		// XI. Axles
		// A. Axels Themselves
		let axleGeo = new THREE.CylinderBufferGeometry(W*0.02,W*0.02,W*0.72,32),
			axleMat = new THREE.MeshStandardMaterial({
				color: 0x7f7f7f,
				wireframe: this.wireframes
			}),
			frontAxle = new THREE.Mesh(axleGeo,axleMat);


		// front
		frontAxle.position.set(0,H*-0.27,D*0.36);
		frontAxle.rotation.z = -Math.PI/2;
		this.mesh.add(frontAxle);


		// back
		let backAxle = frontAxle.clone();
		backAxle.position.z = D*-0.3;
		this.mesh.add(backAxle);


		// B. Support Parts
		let supportMat = new THREE.MeshStandardMaterial({
				color: 0x595959,
				wireframe: this.wireframes
			}),
			frontAxleSupportVerticesArr = [
				// back (0–7)
				[-0.3,  -0.31, 0.2582],
				[0.3,   -0.31, 0.2582],
				[-0.3,  -0.17, 0.265],
				[0.3,   -0.17, 0.265],
				[-0.3,  -0.31, 0.31],
				[0.3,   -0.31, 0.31],
				[-0.3,  0.04,  0.31],
				[0.3,   0.04,  0.31],
				// front (8–15)
				[-0.3,  -0.31, 0.42],
				[0.3,   -0.31, 0.42],
				[-0.3,  0.04,  0.42],
				[0.3,   0.04,  0.42],
				[-0.3,  -0.31, 0.45],
				[0.3,   -0.31, 0.45],
				[-0.3,  -0.13, 0.45],
				[0.3,   -0.13, 0.45],
				// right side (16–22)
				[-0.355,-0.31, 0.2582],
				[-0.45, -0.17, 0.265],
				[-0.45, 0.04,  0.3099],
				[-0.45, 0.04,  0.42],
				[-0.45, -0.13, 0.45],
				[-0.45, -0.13, 0.455],
				[-0.346,-0.31, 0.45],
				// left side (23-29)
				[0.355, -0.31, 0.2582],
				[0.45,  -0.17, 0.265],
				[0.45,  0.04,  0.3099],
				[0.45,  0.04,  0.42],
				[0.45,  -0.13, 0.45],
				[0.45,  -0.13, 0.455],
				[0.346, -0.31, 0.45]
			],
			frontAxleSupportVertices = frontAxleSupportVerticesArr.map(toVectors),
			frontAxleSupportFacesArr = [
				[2,3,1],
				[1,0,2],
				[6,7,3],
				[3,2,6],
				[7,6,10],
				[10,11,7],
				[11,10,14],
				[14,15,11],
				[15,14,12],
				[12,13,15],
				[6,2,0],
				[0,4,6],
				[10,6,4],
				[4,8,10],
				[14,10,8],
				[8,12,14],
				[3,7,5],
				[5,1,3],
				[7,11,9],
				[9,5,7],
				[11,15,13],
				[13,9,11],
				[0,1,5],
				[5,4,0],
				[4,5,9],
				[9,8,4],
				[8,9,13],
				[13,12,8],
				[0,2,17],
				[17,16,0],
				[6,18,2],
				[2,18,17],
				[18,6,10],
				[10,19,18],
				[19,10,14],
				[14,20,19],
				[19,20,21],
				[20,14,12],
				[12,22,20],
				[3,1,23],
				[23,24,3],
				[7,3,24],
				[24,25,7],
				[7,25,26],
				[26,11,7],
				[11,26,27],
				[27,15,11],
				[28,27,26],
				[15,27,29],
				[29,13,15]
			],
			frontAxleSupportFaces = frontAxleSupportFacesArr.map(toFaces),
			frontAxleSupportGeo = new THREE.Geometry();


		frontAxleSupportGeo.vertices = frontAxleSupportVertices;
		frontAxleSupportGeo.faces = frontAxleSupportFaces;
		frontAxleSupportGeo.computeFaceNormals();


		let frontAxleSupport = new THREE.Mesh(frontAxleSupportGeo,supportMat);
		frontAxleSupport.castShadow = true;
		this.mesh.add(frontAxleSupport);


		let backAxleSupportVerticesArr = [
				// back (0–7)
				[-0.3,  -0.29, -0.3999],
				[0.3,   -0.29, -0.3999],
				[-0.3,  -0.1,  -0.38],
				[0.3,   -0.1,  -0.38],
				[-0.3,  -0.31, -0.35],
				[0.3,   -0.31, -0.35],
				[-0.3,  0.04,  -0.35],
				[0.3,   0.04,  -0.35],
				// front (8–15)
				[-0.3,  -0.31, -0.24],
				[0.3,   -0.31, -0.24],
				[-0.3,  0.04,  -0.24],
				[0.3,   0.04,  -0.24],
				[-0.3,  -0.29, -0.19],
				[0.3,   -0.29, -0.19],
				[-0.3,  -0.15, -0.19],
				[0.3,   -0.15, -0.19],
				// right side (16–22)
				[-0.423,-0.285,-0.3999],
				[-0.423,-0.1,  -0.3799],
				[-0.45, 0.04,  -0.3501],
				[-0.45, 0.04,  -0.24],
				[-0.45, -0.15, -0.19],
				[-0.45, -0.15, -0.197],
				[-0.355,-0.29, -0.19],
				// left side (23-29)
				[0.423, -0.285,-0.3999],
				[0.423, -0.1,  -0.3799],
				[0.45,  0.04,  -0.3501],
				[0.45,  0.04,  -0.24],
				[0.45,  -0.15, -0.19],
				[0.45,  -0.15, -0.197],
				[0.355, -0.29, -0.19]
			],
			backAxleSupportVertices = backAxleSupportVerticesArr.map(toVectors),
			backAxleSupportFacesArr = [
				[2,3,1],
				[1,0,2],
				[6,7,3],
				[3,2,6],
				[7,6,10],
				[10,11,7],
				[11,10,14],
				[14,15,11],
				[15,14,12],
				[12,13,15],
				[6,2,0],
				[0,4,6],
				[10,6,4],
				[4,8,10],
				[14,10,8],
				[8,12,14],
				[3,7,5],
				[5,1,3],
				[7,11,9],
				[9,5,7],
				[11,15,13],
				[13,9,11],
				[0,1,5],
				[5,4,0],
				[4,5,9],
				[9,8,4],
				[8,9,13],
				[13,12,8],
				[0,2,17],
				[17,16,0],
				[6,18,2],
				[2,18,17],
				[18,6,10],
				[10,19,18],
				[19,10,14],
				[14,20,19],
				[20,14,12],
				[12,22,20],
				[3,1,23],
				[23,24,3],
				[7,3,24],
				[24,25,7],
				[7,25,26],
				[26,11,7],
				[11,26,27],
				[27,15,11],
				[15,27,29],
				[29,13,15]
			],
			backAxleSupportFaces = backAxleSupportFacesArr.map(toFaces),
			backAxleSupportGeo = new THREE.Geometry();


		backAxleSupportGeo.vertices = backAxleSupportVertices;
		backAxleSupportGeo.faces = backAxleSupportFaces;
		backAxleSupportGeo.computeFaceNormals();


		let backAxleSupport = new THREE.Mesh(backAxleSupportGeo,supportMat);
		backAxleSupport.castShadow = true;
		this.mesh.add(backAxleSupport);


		// C. Bottom Plane Between
		let bottomVerticesArr = [
				[-0.355,-0.29,-0.19],
				[-0.3,  -0.29,-0.19],
				[0.3,   -0.29,-0.19],
				[0.355, -0.29,-0.19],
				[-0.355,-0.31,0.2582],
				[-0.3,  -0.31,0.2582],
				[0.3,   -0.31,0.2582],
				[0.355, -0.31,0.2582]
			],
			bottomVertices = bottomVerticesArr.map(toVectors),
			bottomFacesArr = [
				[0,1,5],
				[5,4,0],
				[1,2,6],
				[6,5,1],
				[2,3,7],
				[7,6,2]
			],
			bottomFaces = bottomFacesArr.map(toFaces),
			bottomGeo = new THREE.Geometry();


		bottomGeo.vertices = bottomVertices;
		bottomGeo.faces = bottomFaces;
		bottomGeo.computeFaceNormals();


		let bottom = new THREE.Mesh(bottomGeo,supportMat);
		bottom.castShadow = true;
		this.mesh.add(bottom);


		// XII. License Plate
		let licensePlateGeo = new THREE.PlaneBufferGeometry(W*0.18,W*0.09),
			licensePlateMat = new THREE.MeshStandardMaterial({
				color: 0xffffff,
				wireframe: this.wireframes,
				map: licensePlateImg,
				transparent: true
			});
		
		licensePlateMat.map.wrapS = THREE.RepeatWrapping;
		licensePlateMat.map.wrapT = THREE.RepeatWrapping;
		licensePlateMat.map.repeat.set(1,1);


		let licensePlate = new THREE.Mesh(licensePlateGeo,licensePlateMat);
		licensePlate.position.set(0,H*-0.16,D*-0.4701);
		licensePlate.rotation.y = Math.PI;
		this.mesh.add(licensePlate);


		// XIII. Wheels
		// A. Tire
		let wheelGeo = new THREE.CylinderBufferGeometry(H*0.23,H*0.23,W*0.14,32),
			wheelMat = new THREE.MeshLambertMaterial({
				color: 0x1c1c1c,
				wireframe: this.wireframes
			});


		this.wheels = [
			new THREE.Mesh(wheelGeo,wheelMat)
		];


		// B. Hub
		let wheelHub = new THREE.Object3D();
		wheelHub.position.y = W*0.075;
		this.wheels[0].add(wheelHub);


		let hubBaseGeo = new THREE.CylinderBufferGeometry(H*0.16,H*0.17,W*0.01,7),
			hubBaseMat = new THREE.MeshStandardMaterial({
				color: 0x1a1a1a,
				wireframe: this.wireframes
			}),
			hubBase = new THREE.Mesh(hubBaseGeo,hubBaseMat);
		wheelHub.add(hubBase);


		let hubCenterGeo = new THREE.TorusBufferGeometry(H*0.03,H*0.03,4,7),
			hubCenter = new THREE.Mesh(hubCenterGeo,hubBaseMat);
		hubCenter.position.y = W*0.005;
		hubCenter.rotation.x = -Math.PI/2;
		hubCenter.rotation.z = 3/28 * Math.PI*2;
		hubBase.add(hubCenter);


		let hubCenterPlateGeo = new THREE.CircleBufferGeometry(H*0.03,7),
			hubCenterPlate = new THREE.Mesh(hubCenterPlateGeo,hubBaseMat);
		hubCenterPlate.position.z = W*0.025;
		hubCenter.add(hubCenterPlate);


		let spokeVerticesArr = [
				// back (0–5)
				[-0.02,-0.063,-0.003],
				[0.02, -0.063,-0.003],
				[-0.02,0.03,  -0.003],
				[0.02, 0.03,  -0.003],
				[-0.02,0.063,-0.003],
				[0.02, 0.063,-0.003],
				// front (6–9)
				[-0.015,-0.063,0.003],
				[0.015, -0.063,0.003],
				[-0.015,0.03,0.003],
				[0.015, 0.03,0.003]
			],
			spokeVertices = spokeVerticesArr.map(toVectors),
			spokeFacesArr = [
				[5,4,8],
				[8,9,5],
				[9,8,6],
				[6,7,9],
				[4,2,8],
				[5,9,3],
				[3,9,7],
				[7,1,3],
				[8,2,0],
				[0,6,8]
			],
			spokeFaces = spokeFacesArr.map(toFaces),
			spokeGeo = new THREE.Geometry();


		spokeGeo.vertices = spokeVertices;
		spokeGeo.faces = spokeFaces;
		spokeGeo.computeFaceNormals();
		spokeGeo.translate(0,H*0.1135,0);


		let spoke = new THREE.Mesh(spokeGeo,hubBaseMat);
		spoke.rotation.z = 3/28 * Math.PI*2;
		hubCenter.add(spoke);


		for (let s = 1; s < 7; ++s) {
			let spokeClone = spoke.clone();
			spokeClone.rotation.z += ((Math.PI*2)/7) * s;
			hubCenter.add(spokeClone);
		}


		// C. Positioning and Cloning
		this.wheels[0].position.set(W*0.43,H*-0.27,D*0.36);
		this.wheels[0].rotation.z = -Math.PI/2;
		this.wheels[0].castShadow = true;
		this.wheels[0].receiveShadow = true;
		this.mesh.add(this.wheels[0]);


		this.wheels.push(this.wheels[0].clone());
		this.wheels[1].position.set(W*-0.43,H*-0.27,D*0.36);
		this.wheels[1].rotation.z = Math.PI/2;
		this.mesh.add(this.wheels[1]);


		this.wheels.push(this.wheels[0].clone());
		this.wheels[2].position.set(W*0.43,H*-0.27,D*-0.3);
		this.wheels[2].rotation.z = -Math.PI/2;
		this.mesh.add(this.wheels[2]);


		this.wheels.push(this.wheels[0].clone());
		this.wheels[3].position.set(W*-0.43,H*-0.27,D*-0.3);
		this.wheels[3].rotation.z = Math.PI/2;
		this.mesh.add(this.wheels[3]);


		// XIV. Light Effects
		this.headlight = new THREE.SpotLight(0x30d2d5,0);
		this.headlight.position.set(0,0,this.depth * 0.48);
		this.headlight.target.position.set(0,0,this.depth/2 + 0.1);
		this.headlight.angle = 75 * Math.PI/180;
		this.headlight.penumbra = 0.2;
		this.headlight.distance = -10;
		this.headlight.castShadow = true;
		this.headlight.shadow.mapSize = new THREE.Vector2(512,512);
		this.mesh.add(this.headlight);
		this.mesh.add(this.headlight.target);


		this.rearlight = new THREE.SpotLight(0xd65a65,0);
		this.rearlight.position.set(0,0,-this.depth * 0.42);
		this.rearlight.target.position.set(0,0,-this.depth/2 - 0.1);
		this.rearlight.angle = 60 * Math.PI/180;
		this.rearlight.penumbra = 0.2;
		this.rearlight.distance = 10;
		this.rearlight.castShadow = true;
		this.rearlight.shadow.mapSize = new THREE.Vector2(512,512);
		this.mesh.add(this.rearlight);
		this.mesh.add(this.rearlight.target);
		
	}
	move() {
		let fps = 60,
			scaleBy = 10,


			inchesInMile = 5280 * 12,
			incZ1MPH = (inchesInMile / 3600) / fps,
			incZ = incZ1MPH * this.speed,


			tireRadius = this.height * 0.23,
			feetPerMin = (this.speed * 5280) / 60,
			rpm = feetPerMin / (2 * Math.PI * (tireRadius / 12)),
			incRotate = (Math.PI * 2) * (rpm / 6e4) * (1e3 / fps);


		this.wheels.forEach(e => {
			e.rotation.x += incRotate / scaleBy;


			if (e.rotation.x >= Math.PI * 2)
				e.rotation.x = 0;
		});
		this.mesh.position.z += incZ / scaleBy;
	}
}


class Road {
	constructor(grassTexture,roadTexture) {
		this.tileSize = 32;
		this.worldSize = this.tileSize * 16;
		this.mesh = new THREE.Object3D();
		this.mesh.rotation.x = -Math.PI/2;


		// grass
		let grassGeo = new THREE.PlaneBufferGeometry(this.worldSize,this.worldSize),
			grassMat = new THREE.MeshLambertMaterial({
				color: 0xc0ea3b,
				map: grassTexture
			});


		grassMat.map.wrapS = THREE.RepeatWrapping;
		grassMat.map.wrapT = THREE.RepeatWrapping;
		grassMat.map.repeat.set(128,128);


		let grass = new THREE.Mesh(grassGeo,grassMat);
		grass.position.z = -0.02;
		this.mesh.add(grass);


		// road
		let roadGeo = new THREE.PlaneBufferGeometry(this.tileSize,this.worldSize),
			roadMat = new THREE.MeshPhongMaterial({
				color: 0xffffff,
				map: roadTexture
			});


		roadMat.map.wrapS = THREE.RepeatWrapping;
		roadMat.map.wrapT = THREE.RepeatWrapping;
		roadMat.map.repeat.set(1,16);


		let road = new THREE.Mesh(roadGeo,roadMat);
		road.position.x = 7;
		road.receiveShadow = true;
		this.mesh.add(road);
	}
}
發佈了127 篇原創文章 · 獲贊 55 · 訪問量 1萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章