2,2 k tris1,94 × 1,21 × 4,58 m
Utiliser dans le code
Remixer dans l’éditeursports-car.js · 395 lignes
Module ES autonome — ne dépend que de three. Appelez la fonction factory et ajoutez le groupe à votre scène.
/**
* Sports Car — Codels 3D model library
* License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
* Triangles: 2,212 · Size (W × H × D): 1.94 × 1.21 × 4.58 m
*
* Usage:
* import { createSportsCar } from './sports-car.js';
*
* const model = createSportsCar();
* model.position.set(0, 0, 0);
* scene.add(model);
*/
import * as THREE from 'three';
const deg = THREE.MathUtils.degToRad;
// Revolve a 2D profile [[radius, y], ...] around the Y axis.
function lathe(points, segments, phiStart = 0, phiLength = Math.PI * 2) {
return new THREE.LatheGeometry(points.map(([x, y]) => new THREE.Vector2(x, y)), segments, phiStart, phiLength);
}
// Extrude a 2D outline along Z (centered). bevel = [thickness, size, segments].
function extrude(outline, depth, holes = [], bevel = null) {
const shape = new THREE.Shape(outline.map(([x, y]) => new THREE.Vector2(x, y)));
for (const hole of holes) shape.holes.push(new THREE.Path(hole.map(([x, y]) => new THREE.Vector2(x, y))));
const options = bevel
? { depth, bevelEnabled: true, bevelThickness: bevel[0], bevelSize: bevel[1], bevelSegments: bevel[2] }
: { depth, bevelEnabled: false };
return new THREE.ExtrudeGeometry(shape, options).translate(0, 0, -depth / 2);
}
export function createSportsCar() {
const root = new THREE.Group();
root.name = 'SportsCar';
// Materials
const paintMat = new THREE.MeshStandardMaterial({ name: 'paint', color: 0xd63a2f, roughness: 0.35, metalness: 0.2, flatShading: true });
const stripeMat = new THREE.MeshStandardMaterial({ name: 'stripe', color: 0xf4f1ea, roughness: 0.4, metalness: 0.1, flatShading: true });
const glassMat = new THREE.MeshStandardMaterial({ name: 'glass', color: 0x26313d, roughness: 0.2, metalness: 0.3, flatShading: true });
const trimMat = new THREE.MeshStandardMaterial({ name: 'trim', color: 0x24262a, roughness: 0.75, flatShading: true });
const alloyMat = new THREE.MeshStandardMaterial({ name: 'alloy', color: 0xc3c7ce, roughness: 0.3, metalness: 0.7, flatShading: true });
const headlightMat = new THREE.MeshStandardMaterial({ name: 'headlight', color: 0xf4f7ff, roughness: 0.3, emissive: 0xdfe9ff, emissiveIntensity: 0.9, flatShading: true });
const taillightMat = new THREE.MeshStandardMaterial({ name: 'taillight', color: 0xe0202a, roughness: 0.3, emissive: 0xff1f2a, emissiveIntensity: 0.8, flatShading: true });
// Shared geometries
const extrudeGeo = extrude([[0.4989, 0.93], [0.0467, 1.1], [-0.68, 1.1], [-1.01, 0.93]], 0.02);
const boxGeo = new THREE.BoxGeometry(0.16, 0.01, 0.3413);
const boxGeo2 = new THREE.BoxGeometry(0.16, 0.01, 0.9892);
const boxGeo3 = new THREE.BoxGeometry(0.16, 0.01, 0.6);
const boxGeo4 = new THREE.BoxGeometry(0.16, 0.01, 0.5025);
const boxGeo5 = new THREE.BoxGeometry(0.42, 0.03, 0.1877);
const boxGeo6 = new THREE.BoxGeometry(0.012, 0.16, 0.36);
const boxGeo7 = new THREE.BoxGeometry(0.006, 0.42, 0.014);
const boxGeo8 = new THREE.BoxGeometry(0.12, 0.08, 0.14);
const cylinderGeo = new THREE.CylinderGeometry(0.055, 0.055, 0.2, 8);
const boxGeo9 = new THREE.BoxGeometry(0.05, 0.22, 0.12);
const boxGeo10 = new THREE.BoxGeometry(0.02, 0.14, 0.5);
const latheGeo = lathe([[0.231, -0.1], [0.231, -0.125], [0.295, -0.125], [0.33, -0.085], [0.33, 0.085], [0.295, 0.125], [0.231, 0.125], [0.231, 0.1]], 14);
const cylinderGeo2 = new THREE.CylinderGeometry(0.231, 0.231, 0.2, 14);
const boxGeo11 = new THREE.BoxGeometry(0.028, 0.06, 0.2171);
const cylinderGeo3 = new THREE.CylinderGeometry(0.0508, 0.0647, 0.05, 10);
const latheGeo2 = lathe([[0.2485, -0.12], [0.2485, -0.145], [0.32, -0.145], [0.355, -0.105], [0.355, 0.105], [0.32, 0.145], [0.2485, 0.145], [0.2485, 0.12]], 14);
const cylinderGeo4 = new THREE.CylinderGeometry(0.2485, 0.2485, 0.24, 14);
const boxGeo12 = new THREE.BoxGeometry(0.028, 0.06, 0.2336);
const cylinderGeo5 = new THREE.CylinderGeometry(0.0547, 0.0696, 0.05, 10);
// Parts
const body = new THREE.Group();
body.name = 'body';
root.add(body);
const lowerBody = new THREE.Mesh(extrude([[2.1, 0.2], [2.22, 0.3], [2.24, 0.46], [1.95, 0.64], [0.95, 0.84], [-1.52, 0.88], [-2.02, 0.93], [-2.2, 0.9], [-2.23, 0.45], [-2.1, 0.2], [-1.7611, 0.2], [-1.7871, 0.4048], [-1.7146, 0.5982], [-1.5604, 0.7354], [-1.36, 0.785], [-1.1596, 0.7354], [-1.0054, 0.5982], [-0.9329, 0.4048], [-0.9589, 0.2], [1.0217, 0.2], [1.0042, 0.3876], [1.0744, 0.5624], [1.2169, 0.6856], [1.4, 0.73], [1.5831, 0.6856], [1.7256, 0.5624], [1.7958, 0.3876], [1.7783, 0.2]], 1.84, [], [0.04, 0.04, 2]), paintMat);
lowerBody.name = 'lowerBody';
lowerBody.rotation.set(0, deg(-90), 0);
body.add(lowerBody);
const chassis = new THREE.Mesh(extrude([[1.85, 0.28], [1.85, 0.6], [0.95, 0.78], [-1.85, 0.82], [-1.85, 0.28]], 1.22), trimMat);
chassis.name = 'chassis';
chassis.rotation.set(0, deg(-90), 0);
body.add(chassis);
const cabin = new THREE.Mesh(extrude([[0.98, 0.8], [-0.02, 1.16], [-0.62, 1.16], [-1.58, 0.84]], 1.3, [], [0.05, 0.05, 2]), paintMat);
cabin.name = 'cabin';
cabin.rotation.set(0, deg(-90), 0);
body.add(cabin);
const windowL = new THREE.Mesh(extrudeGeo, glassMat);
windowL.name = 'windowL';
windowL.position.set(0.705, 0, 0);
windowL.rotation.set(0, deg(-90), 0);
body.add(windowL);
const windowR = new THREE.Mesh(extrudeGeo, glassMat);
windowR.name = 'windowR';
windowR.position.set(-0.705, 0, 0);
windowR.rotation.set(0, deg(-90), 0);
body.add(windowR);
const windshield = new THREE.Mesh(new THREE.BoxGeometry(1.2, 0.02, 0.6495), glassMat);
windshield.name = 'windshield';
windshield.position.set(0, 1.0702, 0.4183);
windshield.rotation.set(deg(-160.2011), 0, 0);
body.add(windshield);
const rearWindow = new THREE.Mesh(new THREE.BoxGeometry(1.16, 0.02, 0.6325), glassMat);
rearWindow.name = 'rearWindow';
rearWindow.position.set(0, 1.0807, -1.0602);
rearWindow.rotation.set(deg(161.5651), 0, 0);
body.add(rearWindow);
const box9 = new THREE.Mesh(boxGeo, stripeMat);
box9.position.set(0.15, 0.5899, 2.1198);
box9.rotation.set(deg(-148.1726), 0, 0);
body.add(box9);
const box10 = new THREE.Mesh(boxGeo2, stripeMat);
box10.position.set(0.15, 0.7831, 1.4742);
box10.rotation.set(deg(-168.6901), 0, 0);
body.add(box10);
const box11 = new THREE.Mesh(boxGeo3, stripeMat);
box11.position.set(0.15, 1.217, -0.32);
box11.rotation.set(deg(-180), 0, 0);
body.add(box11);
const box12 = new THREE.Mesh(boxGeo4, stripeMat);
box12.position.set(0.15, 0.9518, -1.7653);
box12.rotation.set(deg(-174.2894), 0, 0);
body.add(box12);
const box13 = new THREE.Mesh(boxGeo, stripeMat);
box13.position.set(-0.15, 0.5899, 2.1198);
box13.rotation.set(deg(-148.1726), 0, 0);
body.add(box13);
const box14 = new THREE.Mesh(boxGeo2, stripeMat);
box14.position.set(-0.15, 0.7831, 1.4742);
box14.rotation.set(deg(-168.6901), 0, 0);
body.add(box14);
const box15 = new THREE.Mesh(boxGeo3, stripeMat);
box15.position.set(-0.15, 1.217, -0.32);
box15.rotation.set(deg(-180), 0, 0);
body.add(box15);
const box16 = new THREE.Mesh(boxGeo4, stripeMat);
box16.position.set(-0.15, 0.9518, -1.7653);
box16.rotation.set(deg(-174.2894), 0, 0);
body.add(box16);
const headlightL = new THREE.Mesh(boxGeo5, headlightMat);
headlightL.name = 'headlightL';
headlightL.position.set(0.62, 0.5837, 2.126);
headlightL.rotation.set(deg(-148.1726), 0, 0);
body.add(headlightL);
const sideIntakeL = new THREE.Mesh(boxGeo6, trimMat);
sideIntakeL.name = 'sideIntakeL';
sideIntakeL.position.set(0.964, 0.62, -0.7);
body.add(sideIntakeL);
const box19 = new THREE.Mesh(boxGeo7, trimMat);
box19.position.set(0.963, 0.58, 0.7);
body.add(box19);
const mirrorL = new THREE.Mesh(boxGeo8, paintMat);
mirrorL.name = 'mirrorL';
mirrorL.position.set(0.77, 0.92, 0.64);
body.add(mirrorL);
const exhaustL = new THREE.Mesh(cylinderGeo, alloyMat);
exhaustL.name = 'exhaustL';
exhaustL.position.set(0.38, 0.3, -2.2);
exhaustL.rotation.set(deg(90), 0, 0);
body.add(exhaustL);
const headlightR = new THREE.Mesh(boxGeo5, headlightMat);
headlightR.name = 'headlightR';
headlightR.position.set(-0.62, 0.5837, 2.126);
headlightR.rotation.set(deg(-148.1726), 0, 0);
body.add(headlightR);
const sideIntakeR = new THREE.Mesh(boxGeo6, trimMat);
sideIntakeR.name = 'sideIntakeR';
sideIntakeR.position.set(-0.964, 0.62, -0.7);
body.add(sideIntakeR);
const box24 = new THREE.Mesh(boxGeo7, trimMat);
box24.position.set(-0.963, 0.58, 0.7);
body.add(box24);
const mirrorR = new THREE.Mesh(boxGeo8, paintMat);
mirrorR.name = 'mirrorR';
mirrorR.position.set(-0.77, 0.92, 0.64);
body.add(mirrorR);
const exhaustR = new THREE.Mesh(cylinderGeo, alloyMat);
exhaustR.name = 'exhaustR';
exhaustR.position.set(-0.38, 0.3, -2.2);
exhaustR.rotation.set(deg(90), 0, 0);
body.add(exhaustR);
const taillightBar = new THREE.Mesh(new THREE.BoxGeometry(1.62, 0.07, 0.04), taillightMat);
taillightBar.name = 'taillightBar';
taillightBar.position.set(0, 0.8, -2.248);
body.add(taillightBar);
const frontIntake = new THREE.Mesh(new THREE.BoxGeometry(0.9, 0.09, 0.04), trimMat);
frontIntake.name = 'frontIntake';
frontIntake.position.set(0, 0.34, 2.26);
body.add(frontIntake);
const splitter = new THREE.Mesh(new THREE.BoxGeometry(1.94, 0.04, 0.3), trimMat);
splitter.name = 'splitter';
splitter.position.set(0, 0.2, 2.12);
body.add(splitter);
const diffuser = new THREE.Mesh(new THREE.BoxGeometry(1.5, 0.14, 0.3), trimMat);
diffuser.name = 'diffuser';
diffuser.position.set(0, 0.27, -2.08);
body.add(diffuser);
const spoiler = new THREE.Group();
spoiler.name = 'spoiler';
body.add(spoiler);
const box32 = new THREE.Mesh(boxGeo9, trimMat);
box32.position.set(-0.62, 1.04, -1.9);
spoiler.add(box32);
const box33 = new THREE.Mesh(boxGeo9, trimMat);
box33.position.set(0.62, 1.04, -1.9);
spoiler.add(box33);
const wing = new THREE.Mesh(extrude([[0.2, 0], [0.16, 0.05], [-0.2, 0.06], [-0.24, 0.02]], 1.8), paintMat);
wing.name = 'wing';
wing.position.set(0, 1.14, -1.92);
wing.rotation.set(0, deg(-90), 0);
spoiler.add(wing);
const box35 = new THREE.Mesh(boxGeo10, trimMat);
box35.position.set(-0.92, 1.15, -1.94);
spoiler.add(box35);
const box36 = new THREE.Mesh(boxGeo10, trimMat);
box36.position.set(0.92, 1.15, -1.94);
spoiler.add(box36);
const wheels = new THREE.Group();
wheels.name = 'wheels';
root.add(wheels);
const wheelFL = new THREE.Group();
wheelFL.name = 'wheelFL';
wheelFL.position.set(0.79, 0.33, 1.4);
wheels.add(wheelFL);
const tire = new THREE.Mesh(latheGeo, trimMat);
tire.name = 'tire';
tire.rotation.set(0, 0, deg(90));
wheelFL.add(tire);
const rim = new THREE.Mesh(cylinderGeo2, trimMat);
rim.name = 'rim';
rim.rotation.set(0, 0, deg(90));
wheelFL.add(rim);
const spoke1 = new THREE.Mesh(boxGeo11, alloyMat);
spoke1.name = 'spoke1';
spoke1.position.set(0.112, -0.0335, 0.1033);
spoke1.rotation.set(deg(18), 0, 0);
wheelFL.add(spoke1);
const spoke2 = new THREE.Mesh(boxGeo11, alloyMat);
spoke2.name = 'spoke2';
spoke2.position.set(0.112, -0.1086, 0);
spoke2.rotation.set(deg(90), 0, 0);
wheelFL.add(spoke2);
const spoke3 = new THREE.Mesh(boxGeo11, alloyMat);
spoke3.name = 'spoke3';
spoke3.position.set(0.112, -0.0335, -0.1033);
spoke3.rotation.set(deg(162), 0, 0);
wheelFL.add(spoke3);
const spoke4 = new THREE.Mesh(boxGeo11, alloyMat);
spoke4.name = 'spoke4';
spoke4.position.set(0.112, 0.0878, -0.0638);
spoke4.rotation.set(deg(234), 0, 0);
wheelFL.add(spoke4);
const spoke5 = new THREE.Mesh(boxGeo11, alloyMat);
spoke5.name = 'spoke5';
spoke5.position.set(0.112, 0.0878, 0.0638);
spoke5.rotation.set(deg(306), 0, 0);
wheelFL.add(spoke5);
const centerCap = new THREE.Mesh(cylinderGeo3, alloyMat);
centerCap.name = 'centerCap';
centerCap.position.set(0.12, 0, 0);
centerCap.rotation.set(0, 0, deg(-90));
wheelFL.add(centerCap);
const wheelFR = new THREE.Group();
wheelFR.name = 'wheelFR';
wheelFR.position.set(-0.79, 0.33, 1.4);
wheels.add(wheelFR);
const tire2 = new THREE.Mesh(latheGeo, trimMat);
tire2.name = 'tire';
tire2.rotation.set(0, 0, deg(90));
wheelFR.add(tire2);
const rim2 = new THREE.Mesh(cylinderGeo2, trimMat);
rim2.name = 'rim';
rim2.rotation.set(0, 0, deg(90));
wheelFR.add(rim2);
const spoke12 = new THREE.Mesh(boxGeo11, alloyMat);
spoke12.name = 'spoke1';
spoke12.position.set(-0.112, -0.0335, 0.1033);
spoke12.rotation.set(deg(18), 0, 0);
wheelFR.add(spoke12);
const spoke22 = new THREE.Mesh(boxGeo11, alloyMat);
spoke22.name = 'spoke2';
spoke22.position.set(-0.112, -0.1086, 0);
spoke22.rotation.set(deg(90), 0, 0);
wheelFR.add(spoke22);
const spoke32 = new THREE.Mesh(boxGeo11, alloyMat);
spoke32.name = 'spoke3';
spoke32.position.set(-0.112, -0.0335, -0.1033);
spoke32.rotation.set(deg(162), 0, 0);
wheelFR.add(spoke32);
const spoke42 = new THREE.Mesh(boxGeo11, alloyMat);
spoke42.name = 'spoke4';
spoke42.position.set(-0.112, 0.0878, -0.0638);
spoke42.rotation.set(deg(234), 0, 0);
wheelFR.add(spoke42);
const spoke52 = new THREE.Mesh(boxGeo11, alloyMat);
spoke52.name = 'spoke5';
spoke52.position.set(-0.112, 0.0878, 0.0638);
spoke52.rotation.set(deg(306), 0, 0);
wheelFR.add(spoke52);
const centerCap2 = new THREE.Mesh(cylinderGeo3, alloyMat);
centerCap2.name = 'centerCap';
centerCap2.position.set(-0.12, 0, 0);
centerCap2.rotation.set(0, 0, deg(90));
wheelFR.add(centerCap2);
const wheelRL = new THREE.Group();
wheelRL.name = 'wheelRL';
wheelRL.position.set(0.8, 0.355, -1.36);
wheels.add(wheelRL);
const tire3 = new THREE.Mesh(latheGeo2, trimMat);
tire3.name = 'tire';
tire3.rotation.set(0, 0, deg(90));
wheelRL.add(tire3);
const rim3 = new THREE.Mesh(cylinderGeo4, trimMat);
rim3.name = 'rim';
rim3.rotation.set(0, 0, deg(90));
wheelRL.add(rim3);
const spoke13 = new THREE.Mesh(boxGeo12, alloyMat);
spoke13.name = 'spoke1';
spoke13.position.set(0.132, -0.0361, 0.1111);
spoke13.rotation.set(deg(18), 0, 0);
wheelRL.add(spoke13);
const spoke23 = new THREE.Mesh(boxGeo12, alloyMat);
spoke23.name = 'spoke2';
spoke23.position.set(0.132, -0.1168, 0);
spoke23.rotation.set(deg(90), 0, 0);
wheelRL.add(spoke23);
const spoke33 = new THREE.Mesh(boxGeo12, alloyMat);
spoke33.name = 'spoke3';
spoke33.position.set(0.132, -0.0361, -0.1111);
spoke33.rotation.set(deg(162), 0, 0);
wheelRL.add(spoke33);
const spoke43 = new THREE.Mesh(boxGeo12, alloyMat);
spoke43.name = 'spoke4';
spoke43.position.set(0.132, 0.0945, -0.0687);
spoke43.rotation.set(deg(234), 0, 0);
wheelRL.add(spoke43);
const spoke53 = new THREE.Mesh(boxGeo12, alloyMat);
spoke53.name = 'spoke5';
spoke53.position.set(0.132, 0.0945, 0.0687);
spoke53.rotation.set(deg(306), 0, 0);
wheelRL.add(spoke53);
const centerCap3 = new THREE.Mesh(cylinderGeo5, alloyMat);
centerCap3.name = 'centerCap';
centerCap3.position.set(0.14, 0, 0);
centerCap3.rotation.set(0, 0, deg(-90));
wheelRL.add(centerCap3);
const wheelRR = new THREE.Group();
wheelRR.name = 'wheelRR';
wheelRR.position.set(-0.8, 0.355, -1.36);
wheels.add(wheelRR);
const tire4 = new THREE.Mesh(latheGeo2, trimMat);
tire4.name = 'tire';
tire4.rotation.set(0, 0, deg(90));
wheelRR.add(tire4);
const rim4 = new THREE.Mesh(cylinderGeo4, trimMat);
rim4.name = 'rim';
rim4.rotation.set(0, 0, deg(90));
wheelRR.add(rim4);
const spoke14 = new THREE.Mesh(boxGeo12, alloyMat);
spoke14.name = 'spoke1';
spoke14.position.set(-0.132, -0.0361, 0.1111);
spoke14.rotation.set(deg(18), 0, 0);
wheelRR.add(spoke14);
const spoke24 = new THREE.Mesh(boxGeo12, alloyMat);
spoke24.name = 'spoke2';
spoke24.position.set(-0.132, -0.1168, 0);
spoke24.rotation.set(deg(90), 0, 0);
wheelRR.add(spoke24);
const spoke34 = new THREE.Mesh(boxGeo12, alloyMat);
spoke34.name = 'spoke3';
spoke34.position.set(-0.132, -0.0361, -0.1111);
spoke34.rotation.set(deg(162), 0, 0);
wheelRR.add(spoke34);
const spoke44 = new THREE.Mesh(boxGeo12, alloyMat);
spoke44.name = 'spoke4';
spoke44.position.set(-0.132, 0.0945, -0.0687);
spoke44.rotation.set(deg(234), 0, 0);
wheelRR.add(spoke44);
const spoke54 = new THREE.Mesh(boxGeo12, alloyMat);
spoke54.name = 'spoke5';
spoke54.position.set(-0.132, 0.0945, 0.0687);
spoke54.rotation.set(deg(306), 0, 0);
wheelRR.add(spoke54);
const centerCap4 = new THREE.Mesh(cylinderGeo5, alloyMat);
centerCap4.name = 'centerCap';
centerCap4.position.set(-0.14, 0, 0);
centerCap4.rotation.set(0, 0, deg(90));
wheelRR.add(centerCap4);
root.traverse((o) => {
if (o.isMesh) {
o.castShadow = true;
o.receiveShadow = true;
}
});
return root;
}
export default createSportsCar;
Notes et commentaires
0 commentaire
Aucun commentaire pour l’instant. Dites comment vous avez utilisé ce modèle ou ce qui pourrait être amélioré.
Modèles similaires
Même catégorie ou étiquettes proches









