109 lines
4.3 KiB
TypeScript
109 lines
4.3 KiB
TypeScript
import * as THREE from 'three';
|
|
import type { SceneResourceBag } from '@/scene/resources';
|
|
|
|
export function createCar(resources: SceneResourceBag) {
|
|
const group = new THREE.Group();
|
|
group.position.set(0, 0.69, 0.5);
|
|
group.scale.set(0.9, 0.65, 0.78);
|
|
|
|
const bodyMaterial = resources.own('material', new THREE.MeshStandardMaterial({
|
|
color: 0x202938,
|
|
roughness: 0.28,
|
|
metalness: 0.78,
|
|
}));
|
|
const glassMaterial = resources.own('material', new THREE.MeshStandardMaterial({
|
|
color: 0x10273a,
|
|
roughness: 0.12,
|
|
metalness: 0.35,
|
|
}));
|
|
const tailMaterial = resources.own('material', new THREE.MeshBasicMaterial({ color: 0xff315f }));
|
|
const silhouetteMaterial = resources.own('material', new THREE.MeshBasicMaterial({ color: 0x405875 }));
|
|
const fasciaMaterial = resources.own('material', new THREE.MeshStandardMaterial({
|
|
color: 0x151c28,
|
|
roughness: 0.42,
|
|
metalness: 0.62,
|
|
}));
|
|
const underglowMaterial = resources.own('material', new THREE.MeshBasicMaterial({
|
|
color: 0x28d8ef,
|
|
transparent: true,
|
|
opacity: 0.42,
|
|
}));
|
|
|
|
const lowerGeometry = resources.own('geometry', new THREE.BoxGeometry(4.6, 0.55, 6.6));
|
|
const lower = new THREE.Mesh(lowerGeometry, bodyMaterial);
|
|
lower.scale.set(1, 1, 0.92);
|
|
group.add(lower);
|
|
|
|
const cabinGeometry = resources.own('geometry', new THREE.CylinderGeometry(1.25, 1.72, 2.9, 4));
|
|
const cabin = new THREE.Mesh(cabinGeometry, glassMaterial);
|
|
cabin.rotation.set(Math.PI / 2, Math.PI / 4, 0);
|
|
cabin.scale.set(1, 1, 0.62);
|
|
cabin.position.set(0, 0.64, -0.35);
|
|
group.add(cabin);
|
|
|
|
const lightGeometry = resources.own('geometry', new THREE.BoxGeometry(3.9, 0.12, 0.08));
|
|
const rearLight = new THREE.Mesh(lightGeometry, tailMaterial);
|
|
rearLight.position.set(0, 0.04, 3.08);
|
|
group.add(rearLight);
|
|
|
|
const rearProfile = new THREE.Shape();
|
|
rearProfile.moveTo(-2.5, -0.32);
|
|
rearProfile.lineTo(-2.32, 0.28);
|
|
rearProfile.lineTo(-1.42, 0.72);
|
|
rearProfile.lineTo(1.42, 0.72);
|
|
rearProfile.lineTo(2.32, 0.28);
|
|
rearProfile.lineTo(2.5, -0.32);
|
|
rearProfile.closePath();
|
|
const silhouetteGeometry = resources.own('geometry', new THREE.ShapeGeometry(rearProfile));
|
|
const silhouette = new THREE.Mesh(silhouetteGeometry, silhouetteMaterial);
|
|
silhouette.name = 'rear-silhouette';
|
|
silhouette.position.z = 2.98;
|
|
group.add(silhouette);
|
|
|
|
const fasciaGeometry = resources.own('geometry', new THREE.BoxGeometry(4.3, 0.38, 0.22));
|
|
const fascia = new THREE.Mesh(fasciaGeometry, fasciaMaterial);
|
|
fascia.position.set(0, -0.12, 2.94);
|
|
group.add(fascia);
|
|
|
|
const shoulderGeometry = resources.own('geometry', new THREE.BoxGeometry(5.05, 0.18, 1.1));
|
|
const shoulders = new THREE.Mesh(shoulderGeometry, bodyMaterial);
|
|
shoulders.position.set(0, 0.18, 2.48);
|
|
group.add(shoulders);
|
|
|
|
const accentMaterial = resources.own('material', new THREE.MeshBasicMaterial({ color: 0x28d8ef }));
|
|
const accentGeometry = resources.own('geometry', new THREE.BoxGeometry(0.36, 0.1, 0.08));
|
|
for (const x of [-2.02, 2.02]) {
|
|
const accent = new THREE.Mesh(accentGeometry, accentMaterial);
|
|
accent.position.set(x, -0.15, 3.11);
|
|
group.add(accent);
|
|
}
|
|
|
|
const glowGeometry = resources.own('geometry', new THREE.PlaneGeometry(4.2, 6.2));
|
|
const underglow = new THREE.Mesh(glowGeometry, underglowMaterial);
|
|
underglow.rotation.x = -Math.PI / 2;
|
|
underglow.position.y = -0.31;
|
|
group.add(underglow);
|
|
|
|
const wheelGeometry = resources.own('geometry', new THREE.CylinderGeometry(0.62, 0.62, 0.42, 18));
|
|
const wheelMaterial = resources.own('material', new THREE.MeshStandardMaterial({ color: 0x030407, roughness: 0.92 }));
|
|
for (const x of [-2.05, 2.05]) {
|
|
for (const z of [-2.15, 2.15]) {
|
|
const wheel = new THREE.Mesh(wheelGeometry, wheelMaterial);
|
|
wheel.rotation.z = Math.PI / 2;
|
|
wheel.position.set(x, -0.18, z);
|
|
group.add(wheel);
|
|
}
|
|
}
|
|
|
|
return {
|
|
group,
|
|
update(speed: number, acceleration: number, elapsedSeconds: number) {
|
|
const response = Math.min(1, Math.max(0, acceleration));
|
|
group.position.y = 0.69 + Math.sin(elapsedSeconds * (2.2 + speed)) * (0.012 + response * 0.018);
|
|
group.rotation.z = Math.sin(elapsedSeconds * 1.4) * 0.003 * response;
|
|
tailMaterial.color.setRGB(1, 0.12 + response * 0.08, 0.28 + response * 0.08);
|
|
underglowMaterial.opacity = 0.32 + Math.min(0.3, speed * 0.2);
|
|
},
|
|
};
|
|
}
|