3,1 k tris5,07 × 6,63 × 19,0 m
Utiliser dans le code
Remixer dans l’éditeursubmarine.js · 361 lignes
Module ES autonome — ne dépend que de three. Appelez la fonction factory et ajoutez le groupe à votre scène.
/**
* Submarine — Codels 3D model library
* License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
* Triangles: 3,132 · Size (W × H × D): 5.07 × 6.63 × 18.95 m
*
* Usage:
* import { createSubmarine } from './submarine.js';
*
* const model = createSubmarine();
* 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 createSubmarine() {
const root = new THREE.Group();
root.name = 'Submarine';
// Materials
const paintMat = new THREE.MeshStandardMaterial({ name: 'paint', color: 0xf2bf2a, roughness: 0.4, metalness: 0.15, flatShading: true });
const lowerMat = new THREE.MeshStandardMaterial({ name: 'lower', color: 0xf2bf2a, roughness: 0.4, metalness: 0.15, flatShading: true });
const accentMat = new THREE.MeshStandardMaterial({ name: 'accent', color: 0xd9562e, roughness: 0.45, metalness: 0.15, flatShading: true });
const glassMat = new THREE.MeshStandardMaterial({ name: 'glass', color: 0x26364a, roughness: 0.2, metalness: 0.35, emissive: 0x2e5d86, emissiveIntensity: 0.3 });
const darkMat = new THREE.MeshStandardMaterial({ name: 'dark', color: 0x24272c, roughness: 0.55, metalness: 0.4, flatShading: true });
const propMat = new THREE.MeshStandardMaterial({ name: 'prop', color: 0xc79a45, roughness: 0.35, metalness: 0.75, flatShading: true });
const lightMat = new THREE.MeshStandardMaterial({ name: 'light', color: 0xfff4c4, roughness: 0.4, emissive: 0xffe48a, emissiveIntensity: 1.4, flatShading: true });
// Shared geometries
const torusGeo = new THREE.TorusGeometry(0.36, 0.08, 5, 12);
const cylinderGeo = new THREE.CylinderGeometry(0.33, 0.33, 0.06, 12);
const cylinderGeo2 = new THREE.CylinderGeometry(0.24, 0.24, 0.12, 10);
const cylinderGeo3 = new THREE.CylinderGeometry(0.18, 0.18, 0.14, 10);
const torusGeo2 = new THREE.TorusGeometry(0.25, 0.06, 4, 10);
const cylinderGeo4 = new THREE.CylinderGeometry(0.22, 0.22, 0.05, 10);
const extrudeGeo = extrude([[-5.9, 0.94], [-7.5, 1.95], [-8.4, 1.95], [-8.6, 0.2]], 0.12, [], [0.03, 0.03, 1]);
const boxGeo = new THREE.BoxGeometry(0.42, 0.95, 0.05);
// Parts
const submarine = new THREE.Group();
submarine.name = 'submarine';
submarine.position.set(0, 1.53, 0);
root.add(submarine);
const hull = new THREE.Group();
hull.name = 'hull';
submarine.add(hull);
const upperHull = new THREE.Mesh(lathe([[0, -9], [0.18, -8.9], [0.45, -8.2], [0.95, -6.6], [1.35, -4.6], [1.5, -2.6], [1.5, 3.5], [1.42, 5.6], [1.18, 7.2], [0.75, 8.3], [0.3, 8.85], [0, 9]], 16, 1.37, 3.5432), paintMat);
upperHull.name = 'upperHull';
upperHull.rotation.set(deg(90), 0, 0);
hull.add(upperHull);
const lowerHull = new THREE.Mesh(lathe([[0, -9], [0.18, -8.9], [0.45, -8.2], [0.95, -6.6], [1.35, -4.6], [1.5, -2.6], [1.5, 3.5], [1.42, 5.6], [1.18, 7.2], [0.75, 8.3], [0.3, 8.85], [0, 9]], 8, -1.37, 2.74), lowerMat);
lowerHull.name = 'lowerHull';
lowerHull.rotation.set(deg(90), 0, 0);
hull.add(lowerHull);
const keel = new THREE.Mesh(new THREE.BoxGeometry(0.18, 0.2, 5.8), accentMat);
keel.name = 'keel';
keel.position.set(0, -1.4, 0.45);
hull.add(keel);
const band = new THREE.Mesh(lathe([[1.4115, -4.18], [1.4385, -3.82]], 16), accentMat);
band.name = 'band';
band.rotation.set(deg(90), 0, 0);
hull.add(band);
const band2 = new THREE.Mesh(lathe([[1.53, -0.78], [1.53, -0.42]], 16), accentMat);
band2.name = 'band';
band2.rotation.set(deg(90), 0, 0);
hull.add(band2);
const band3 = new THREE.Mesh(lathe([[1.5026, 4.22], [1.4889, 4.58]], 16), accentMat);
band3.name = 'band';
band3.rotation.set(deg(90), 0, 0);
hull.add(band3);
const band4 = new THREE.Mesh(lathe([[1.267, 6.82], [1.213, 7.18]], 16), accentMat);
band4.name = 'band';
band4.rotation.set(deg(90), 0, 0);
hull.add(band4);
const portholeRim = new THREE.Mesh(torusGeo, accentMat);
portholeRim.name = 'portholeRim';
portholeRim.position.set(1.52, 0.1, -2.3);
portholeRim.rotation.set(0, deg(90), 0);
hull.add(portholeRim);
const porthole = new THREE.Mesh(cylinderGeo, glassMat);
porthole.name = 'porthole';
porthole.position.set(1.495, 0.1, -2.3);
porthole.rotation.set(0, 0, deg(-90));
hull.add(porthole);
const portholeRim2 = new THREE.Mesh(torusGeo, accentMat);
portholeRim2.name = 'portholeRim';
portholeRim2.position.set(1.52, 0.1, 0.3);
portholeRim2.rotation.set(0, deg(90), 0);
hull.add(portholeRim2);
const porthole2 = new THREE.Mesh(cylinderGeo, glassMat);
porthole2.name = 'porthole';
porthole2.position.set(1.495, 0.1, 0.3);
porthole2.rotation.set(0, 0, deg(-90));
hull.add(porthole2);
const portholeRim3 = new THREE.Mesh(torusGeo, accentMat);
portholeRim3.name = 'portholeRim';
portholeRim3.position.set(1.52, 0.1, 2.9);
portholeRim3.rotation.set(0, deg(90), 0);
hull.add(portholeRim3);
const porthole3 = new THREE.Mesh(cylinderGeo, glassMat);
porthole3.name = 'porthole';
porthole3.position.set(1.495, 0.1, 2.9);
porthole3.rotation.set(0, 0, deg(-90));
hull.add(porthole3);
const portholeRim4 = new THREE.Mesh(torusGeo, accentMat);
portholeRim4.name = 'portholeRim';
portholeRim4.position.set(1.4514, 0.1, 5.3);
portholeRim4.rotation.set(0, deg(90), 0);
hull.add(portholeRim4);
const porthole4 = new THREE.Mesh(cylinderGeo, glassMat);
porthole4.name = 'porthole';
porthole4.position.set(1.4264, 0.1, 5.3);
porthole4.rotation.set(0, 0, deg(-90));
hull.add(porthole4);
const portholeRim5 = new THREE.Mesh(torusGeo, accentMat);
portholeRim5.name = 'portholeRim';
portholeRim5.position.set(-1.52, 0.1, -2.3);
portholeRim5.rotation.set(0, deg(-90), 0);
hull.add(portholeRim5);
const porthole5 = new THREE.Mesh(cylinderGeo, glassMat);
porthole5.name = 'porthole';
porthole5.position.set(-1.495, 0.1, -2.3);
porthole5.rotation.set(0, 0, deg(90));
hull.add(porthole5);
const portholeRim6 = new THREE.Mesh(torusGeo, accentMat);
portholeRim6.name = 'portholeRim';
portholeRim6.position.set(-1.52, 0.1, 0.3);
portholeRim6.rotation.set(0, deg(-90), 0);
hull.add(portholeRim6);
const porthole6 = new THREE.Mesh(cylinderGeo, glassMat);
porthole6.name = 'porthole';
porthole6.position.set(-1.495, 0.1, 0.3);
porthole6.rotation.set(0, 0, deg(90));
hull.add(porthole6);
const portholeRim7 = new THREE.Mesh(torusGeo, accentMat);
portholeRim7.name = 'portholeRim';
portholeRim7.position.set(-1.52, 0.1, 2.9);
portholeRim7.rotation.set(0, deg(-90), 0);
hull.add(portholeRim7);
const porthole7 = new THREE.Mesh(cylinderGeo, glassMat);
porthole7.name = 'porthole';
porthole7.position.set(-1.495, 0.1, 2.9);
porthole7.rotation.set(0, 0, deg(90));
hull.add(porthole7);
const portholeRim8 = new THREE.Mesh(torusGeo, accentMat);
portholeRim8.name = 'portholeRim';
portholeRim8.position.set(-1.4514, 0.1, 5.3);
portholeRim8.rotation.set(0, deg(-90), 0);
hull.add(portholeRim8);
const porthole8 = new THREE.Mesh(cylinderGeo, glassMat);
porthole8.name = 'porthole';
porthole8.position.set(-1.4264, 0.1, 5.3);
porthole8.rotation.set(0, 0, deg(90));
hull.add(porthole8);
const lampHousing = new THREE.Mesh(cylinderGeo2, darkMat);
lampHousing.name = 'lampHousing';
lampHousing.position.set(0.9065, -0.3309, 7.75);
lampHousing.rotation.set(deg(35.8078), deg(-34.5433), deg(-87.8054));
hull.add(lampHousing);
const headlight = new THREE.Mesh(cylinderGeo3, lightMat);
headlight.name = 'headlight';
headlight.position.set(0.9253, -0.3378, 7.76);
headlight.rotation.set(deg(35.8078), deg(-34.5433), deg(-87.8054));
hull.add(headlight);
const lampHousing2 = new THREE.Mesh(cylinderGeo2, darkMat);
lampHousing2.name = 'lampHousing';
lampHousing2.position.set(-0.9065, -0.3309, 7.75);
lampHousing2.rotation.set(deg(35.8078), deg(34.5433), deg(87.8054));
hull.add(lampHousing2);
const headlight2 = new THREE.Mesh(cylinderGeo3, lightMat);
headlight2.name = 'headlight';
headlight2.position.set(-0.9253, -0.3378, 7.76);
headlight2.rotation.set(deg(35.8078), deg(34.5433), deg(87.8054));
hull.add(headlight2);
const bowPlaneL = new THREE.Mesh(extrude([[0, 0.5], [1.3, 0.25], [1.4, -0.3], [0, -0.45]], 0.1, [], [0.03, 0.03, 1]), accentMat);
bowPlaneL.name = 'bowPlaneL';
bowPlaneL.position.set(1.1, -0.2, 6);
bowPlaneL.rotation.set(deg(90), 0, 0);
hull.add(bowPlaneL);
const bowPlaneR = new THREE.Mesh(extrude([[0, 0.5], [-1.3, 0.25], [-1.4, -0.3], [0, -0.45]], 0.1, [], [0.03, 0.03, 1]), accentMat);
bowPlaneR.name = 'bowPlaneR';
bowPlaneR.position.set(-1.1, -0.2, 6);
bowPlaneR.rotation.set(deg(90), 0, 0);
hull.add(bowPlaneR);
const tower = new THREE.Group();
tower.name = 'tower';
tower.position.set(0, 0, 1.6);
submarine.add(tower);
const towerBody = new THREE.Mesh(new THREE.CylinderGeometry(1, 1.1, 1.9, 14), paintMat);
towerBody.name = 'towerBody';
towerBody.position.set(0, 2.2, 0);
towerBody.scale.set(1, 1, 1.35);
tower.add(towerBody);
const towerRim = new THREE.Mesh(new THREE.TorusGeometry(1.05, 0.07, 4, 14), accentMat);
towerRim.name = 'towerRim';
towerRim.position.set(0, 3.15, 0);
towerRim.rotation.set(deg(90), 0, 0);
towerRim.scale.set(1, 1.35, 1);
tower.add(towerRim);
const hatch = new THREE.Mesh(new THREE.CylinderGeometry(0.42, 0.42, 0.12, 10), accentMat);
hatch.name = 'hatch';
hatch.position.set(0, 3.21, -0.3);
tower.add(hatch);
const hatchDome = new THREE.Mesh(new THREE.SphereGeometry(0.3, 8, 3, 0, Math.PI * 2, 0, Math.PI / 2), accentMat);
hatchDome.name = 'hatchDome';
hatchDome.position.set(0, 3.27, -0.3);
tower.add(hatchDome);
const towerPortRim = new THREE.Mesh(torusGeo2, accentMat);
towerPortRim.name = 'towerPortRim';
towerPortRim.position.set(0.98, 2.45, 0.45);
towerPortRim.rotation.set(0, deg(70.71), 0);
tower.add(towerPortRim);
const towerPort = new THREE.Mesh(cylinderGeo4, glassMat);
towerPort.name = 'towerPort';
towerPort.position.set(0.96, 2.45, 0.44);
towerPort.rotation.set(deg(20.3457), deg(-18.168), deg(-83.4046));
tower.add(towerPort);
const towerPortRim2 = new THREE.Mesh(torusGeo2, accentMat);
towerPortRim2.name = 'towerPortRim';
towerPortRim2.position.set(-0.98, 2.45, 0.45);
towerPortRim2.rotation.set(0, deg(-70.71), 0);
tower.add(towerPortRim2);
const towerPort2 = new THREE.Mesh(cylinderGeo4, glassMat);
towerPort2.name = 'towerPort';
towerPort2.position.set(-0.96, 2.45, 0.44);
towerPort2.rotation.set(deg(20.3457), deg(18.168), deg(83.4046));
tower.add(towerPort2);
const frontPortRim = new THREE.Mesh(new THREE.TorusGeometry(0.3, 0.07, 4, 10), accentMat);
frontPortRim.name = 'frontPortRim';
frontPortRim.position.set(0, 2.45, 1.43);
tower.add(frontPortRim);
const frontPort = new THREE.Mesh(new THREE.CylinderGeometry(0.27, 0.27, 0.05, 10), glassMat);
frontPort.name = 'frontPort';
frontPort.position.set(0, 2.45, 1.41);
frontPort.rotation.set(deg(90), 0, 0);
tower.add(frontPort);
const periscope = new THREE.Group();
periscope.name = 'periscope';
periscope.position.set(0, 3.15, 0.35);
tower.add(periscope);
const periscopeShaft = new THREE.Mesh(new THREE.CylinderGeometry(0.09, 0.11, 1.7, 8), darkMat);
periscopeShaft.name = 'periscopeShaft';
periscopeShaft.position.set(0, 0.85, 0);
periscope.add(periscopeShaft);
const periscopeHead = new THREE.Mesh(new THREE.BoxGeometry(0.24, 0.3, 0.38), darkMat);
periscopeHead.name = 'periscopeHead';
periscopeHead.position.set(0, 1.8, 0.06);
periscope.add(periscopeHead);
const periscopeLens = new THREE.Mesh(new THREE.BoxGeometry(0.16, 0.14, 0.04), glassMat);
periscopeLens.name = 'periscopeLens';
periscopeLens.position.set(0, 1.82, 0.26);
periscope.add(periscopeLens);
const rudderTop = new THREE.Group();
rudderTop.name = 'rudderTop';
submarine.add(rudderTop);
const fin = new THREE.Mesh(extrude([[-5.9, 0.94], [-7.5, 2.4], [-8.4, 2.4], [-8.6, 0.2]], 0.12, [], [0.03, 0.03, 1]), accentMat);
fin.name = 'fin';
fin.rotation.set(0, deg(-90), 0);
rudderTop.add(fin);
const sternPlaneL = new THREE.Group();
sternPlaneL.name = 'sternPlaneL';
sternPlaneL.rotation.set(0, 0, deg(-90));
submarine.add(sternPlaneL);
const fin2 = new THREE.Mesh(extrudeGeo, accentMat);
fin2.name = 'fin';
fin2.rotation.set(0, deg(-90), 0);
sternPlaneL.add(fin2);
const rudderBottom = new THREE.Group();
rudderBottom.name = 'rudderBottom';
rudderBottom.rotation.set(0, 0, deg(-180));
submarine.add(rudderBottom);
const fin3 = new THREE.Mesh(extrude([[-5.9, 0.94], [-7.5, 1.42], [-8.4, 1.42], [-8.6, 0.2]], 0.12, [], [0.03, 0.03, 1]), accentMat);
fin3.name = 'fin';
fin3.rotation.set(0, deg(-90), 0);
rudderBottom.add(fin3);
const sternPlaneR = new THREE.Group();
sternPlaneR.name = 'sternPlaneR';
sternPlaneR.rotation.set(0, 0, deg(-270));
submarine.add(sternPlaneR);
const fin4 = new THREE.Mesh(extrudeGeo, accentMat);
fin4.name = 'fin';
fin4.rotation.set(0, deg(-90), 0);
sternPlaneR.add(fin4);
const propShaft = new THREE.Mesh(new THREE.CylinderGeometry(0.14, 0.22, 0.5, 8), darkMat);
propShaft.name = 'propShaft';
propShaft.position.set(0, 0, -9.1);
propShaft.rotation.set(deg(90), 0, 0);
submarine.add(propShaft);
const propeller = new THREE.Group();
propeller.name = 'propeller';
propeller.position.set(0, 0, -9.45);
submarine.add(propeller);
const propCap = new THREE.Mesh(new THREE.ConeGeometry(0.26, 0.5, 8), propMat);
propCap.name = 'propCap';
propCap.position.set(0, 0, -0.25);
propCap.rotation.set(deg(-90), 0, 0);
propeller.add(propCap);
const propHub = new THREE.Mesh(new THREE.CylinderGeometry(0.26, 0.26, 0.3, 8), propMat);
propHub.name = 'propHub';
propHub.rotation.set(deg(90), 0, 0);
propeller.add(propHub);
const blade1 = new THREE.Group();
blade1.name = 'blade1';
blade1.rotation.set(0, 0, deg(15));
propeller.add(blade1);
const box60 = new THREE.Mesh(boxGeo, propMat);
box60.position.set(0, 0.62, 0);
box60.rotation.set(0, deg(28), 0);
blade1.add(box60);
const blade2 = new THREE.Group();
blade2.name = 'blade2';
blade2.rotation.set(0, 0, deg(105));
propeller.add(blade2);
const box62 = new THREE.Mesh(boxGeo, propMat);
box62.position.set(0, 0.62, 0);
box62.rotation.set(0, deg(28), 0);
blade2.add(box62);
const blade3 = new THREE.Group();
blade3.name = 'blade3';
blade3.rotation.set(0, 0, deg(195));
propeller.add(blade3);
const box64 = new THREE.Mesh(boxGeo, propMat);
box64.position.set(0, 0.62, 0);
box64.rotation.set(0, deg(28), 0);
blade3.add(box64);
const blade4 = new THREE.Group();
blade4.name = 'blade4';
blade4.rotation.set(0, 0, deg(285));
propeller.add(blade4);
const box66 = new THREE.Mesh(boxGeo, propMat);
box66.position.set(0, 0.62, 0);
box66.rotation.set(0, deg(28), 0);
blade4.add(box66);
root.traverse((o) => {
if (o.isMesh) {
o.castShadow = true;
o.receiveShadow = true;
}
});
return root;
}
export default createSubmarine;
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









