Codels
1,2 тыс. треуг.3,64 × 4,53 × 4,00 m

Использовать в коде

Ремикс в редакторе
Самодостаточный ES-модуль — зависит только от three. Вызовите фабрику и добавьте группу в сцену.
/**
 * Station Module — Codels 3D model library
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 1,240 · Size (W × H × D): 3.64 × 4.53 × 4.00 m
 *
 * Usage:
 *   import { createStationModule } from './station-module.js';
 *   
 *   const model = createStationModule();
 *   model.position.set(0, 0, 0);
 *   scene.add(model);
 */
import * as THREE from 'three';

const deg = THREE.MathUtils.degToRad;

// 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);
}

// Tube along a smooth curve through the given points.
function tube(path, radius, tubularSegments, radialSegments, closed = false) {
  const curve = new THREE.CatmullRomCurve3(path.map(([x, y, z]) => new THREE.Vector3(x, y, z)), closed);
  return new THREE.TubeGeometry(curve, tubularSegments, radius, radialSegments, closed);
}

export function createStationModule() {
  const root = new THREE.Group();
  root.name = 'StationModule';

  // Materials
  const hullMat = new THREE.MeshStandardMaterial({ name: 'hull', color: 0xd4dae1, roughness: 0.45, metalness: 0.3, flatShading: true });
  const trimMat = new THREE.MeshStandardMaterial({ name: 'trim', color: 0x3a4049, roughness: 0.55, metalness: 0.45, flatShading: true });
  const floorMat = new THREE.MeshStandardMaterial({ name: 'floor', color: 0x4a515c, roughness: 0.7, metalness: 0.4, flatShading: true });
  const metalMat = new THREE.MeshStandardMaterial({ name: 'metal', color: 0x8a929c, roughness: 0.4, metalness: 0.6, flatShading: true });
  const glassMat = new THREE.MeshStandardMaterial({ name: 'glass', color: 0x9fd6ef, roughness: 0.08, metalness: 0.2, transparent: true, opacity: 0.45 });
  const glowMat = new THREE.MeshStandardMaterial({ name: 'glow', color: 0x3ad6ff, roughness: 0.4, emissive: 0x3ad6ff, emissiveIntensity: 1.3, flatShading: true });
  const hazardMat = new THREE.MeshStandardMaterial({ name: 'hazard', color: 0xf2b630, roughness: 0.55, metalness: 0.2, flatShading: true });
  const redMat = new THREE.MeshStandardMaterial({ name: 'red', color: 0xff5a4a, roughness: 0.4, emissive: 0xff3b2f, emissiveIntensity: 1.2, flatShading: true });

  // Shared geometries
  const boxGeo = new THREE.BoxGeometry(2.22, 0.12, 3.72);
  const boxGeo2 = new THREE.BoxGeometry(0.9368, 0.12, 3.72);
  const boxGeo3 = new THREE.BoxGeometry(0.12, 0.42, 3.72);
  const boxGeo4 = new THREE.BoxGeometry(0.04, 1, 3.72);
  const boxGeo5 = new THREE.BoxGeometry(0.16, 1, 0.16);
  const boxGeo6 = new THREE.BoxGeometry(0.18, 0.08, 3.72);
  const boxGeo7 = new THREE.BoxGeometry(0.1, 0.05, 0.3);
  const boxGeo8 = new THREE.BoxGeometry(2.16, 0.012, 0.05);
  const boxGeo9 = new THREE.BoxGeometry(0.05, 0.03, 3.52);
  const extrudeGeo = extrude([[-1.1297, 0.18], [1.1297, 0.18], [1.82, 0.8703], [1.82, 2.7297], [1.1297, 3.42], [-1.1297, 3.42], [-1.82, 2.7297], [-1.82, 0.8703]], 0.14, [[[-1.64, 0.9448], [-1.64, 2.6552], [-1.0552, 3.24], [1.0552, 3.24], [1.64, 2.6552], [1.64, 0.9448], [1.0552, 0.36], [-1.0552, 0.36]]]);
  const extrudeGeo2 = extrude([[-1.08, 0.3], [1.08, 0.3], [1.7, 0.92], [1.7, 2.68], [1.08, 3.3], [-1.08, 3.3], [-1.7, 2.68], [-1.7, 0.92]], 0.2, [[[-0.72, 2.43], [-0.42, 2.73], [0.42, 2.73], [0.72, 2.43], [0.72, 0.46], [-0.72, 0.46]]]);
  const boxGeo10 = new THREE.BoxGeometry(0.12, 2.05, 0.06);
  const boxGeo11 = new THREE.BoxGeometry(1.2, 0.1, 0.06);
  const boxGeo12 = new THREE.BoxGeometry(0.14, 0.24, 0.05);
  const boxGeo13 = new THREE.BoxGeometry(0.08, 0.08, 0.03);
  const boxGeo14 = new THREE.BoxGeometry(0.72, 2.21, 0.08);
  const boxGeo15 = new THREE.BoxGeometry(0.03, 1.95, 0.02);
  const boxGeo16 = new THREE.BoxGeometry(0.09, 0.4, 0.02);
  const boxGeo17 = new THREE.BoxGeometry(0.3, 0.3, 3.5);
  const boxGeo18 = new THREE.BoxGeometry(0.5, 0.08, 0.5);

  // Parts
  const hull = new THREE.Group();
  hull.name = 'hull';
  root.add(hull);
  const panel1 = new THREE.Mesh(boxGeo, hullMat);
  panel1.name = 'panel1';
  panel1.position.set(0, 0.36, 0);
  hull.add(panel1);
  const panel2 = new THREE.Mesh(boxGeo2, hullMat);
  panel2.name = 'panel2';
  panel2.position.set(1.3476, 0.6524, 0);
  panel2.rotation.set(0, 0, deg(45));
  hull.add(panel2);
  const wallLowR = new THREE.Mesh(boxGeo3, hullMat);
  wallLowR.name = 'wallLowR';
  wallLowR.position.set(1.64, 1.11, 0);
  hull.add(wallLowR);
  const wallHighR = new THREE.Mesh(boxGeo3, hullMat);
  wallHighR.name = 'wallHighR';
  wallHighR.position.set(1.64, 2.49, 0);
  hull.add(wallHighR);
  const windowR = new THREE.Mesh(boxGeo4, glassMat);
  windowR.name = 'windowR';
  windowR.position.set(1.64, 1.8, 0);
  hull.add(windowR);
  const box7 = new THREE.Mesh(boxGeo5, trimMat);
  box7.position.set(1.64, 1.8, -1.78);
  hull.add(box7);
  const box8 = new THREE.Mesh(boxGeo5, trimMat);
  box8.position.set(1.64, 1.8, 0);
  hull.add(box8);
  const box9 = new THREE.Mesh(boxGeo5, trimMat);
  box9.position.set(1.64, 1.8, 1.78);
  hull.add(box9);
  const box10 = new THREE.Mesh(boxGeo6, trimMat);
  box10.position.set(1.64, 1.28, 0);
  hull.add(box10);
  const box11 = new THREE.Mesh(boxGeo6, trimMat);
  box11.position.set(1.64, 2.32, 0);
  hull.add(box11);
  const panel4 = new THREE.Mesh(boxGeo2, hullMat);
  panel4.name = 'panel4';
  panel4.position.set(1.3476, 2.9476, 0);
  panel4.rotation.set(0, 0, deg(135));
  hull.add(panel4);
  const panel5 = new THREE.Mesh(boxGeo, hullMat);
  panel5.name = 'panel5';
  panel5.position.set(0, 3.24, 0);
  panel5.rotation.set(0, 0, deg(180));
  hull.add(panel5);
  const panel6 = new THREE.Mesh(boxGeo2, hullMat);
  panel6.name = 'panel6';
  panel6.position.set(-1.3476, 2.9476, 0);
  panel6.rotation.set(0, 0, deg(-135));
  hull.add(panel6);
  const wallLowL = new THREE.Mesh(boxGeo3, hullMat);
  wallLowL.name = 'wallLowL';
  wallLowL.position.set(-1.64, 1.11, 0);
  hull.add(wallLowL);
  const wallHighL = new THREE.Mesh(boxGeo3, hullMat);
  wallHighL.name = 'wallHighL';
  wallHighL.position.set(-1.64, 2.49, 0);
  hull.add(wallHighL);
  const windowL = new THREE.Mesh(boxGeo4, glassMat);
  windowL.name = 'windowL';
  windowL.position.set(-1.64, 1.8, 0);
  hull.add(windowL);
  const box18 = new THREE.Mesh(boxGeo5, trimMat);
  box18.position.set(-1.64, 1.8, -1.78);
  hull.add(box18);
  const box19 = new THREE.Mesh(boxGeo5, trimMat);
  box19.position.set(-1.64, 1.8, 0);
  hull.add(box19);
  const box20 = new THREE.Mesh(boxGeo5, trimMat);
  box20.position.set(-1.64, 1.8, 1.78);
  hull.add(box20);
  const box21 = new THREE.Mesh(boxGeo6, trimMat);
  box21.position.set(-1.64, 1.28, 0);
  hull.add(box21);
  const box22 = new THREE.Mesh(boxGeo6, trimMat);
  box22.position.set(-1.64, 2.32, 0);
  hull.add(box22);
  const panel8 = new THREE.Mesh(boxGeo2, hullMat);
  panel8.name = 'panel8';
  panel8.position.set(-1.3476, 0.6524, 0);
  panel8.rotation.set(0, 0, deg(-45));
  hull.add(panel8);
  const midRib = new THREE.Mesh(extrude([[-1.1214, 0.2], [1.1214, 0.2], [1.8, 0.8786], [1.8, 2.7214], [1.1214, 3.4], [-1.1214, 3.4], [-1.8, 2.7214], [-1.8, 0.8786]], 0.3, [[[-1.68, 0.9283], [-1.68, 2.6717], [-1.0717, 3.28], [1.0717, 3.28], [1.68, 2.6717], [1.68, 0.9283], [1.0717, 0.32], [-1.0717, 0.32]]]), trimMat);
  midRib.name = 'midRib';
  root.add(midRib);
  const conduitL = new THREE.Mesh(tube([[-1.445, 3.045, -1.86], [-1.445, 3.045, 1.86]], 0.07, 1, 6), metalMat);
  conduitL.name = 'conduitL';
  root.add(conduitL);
  const markerL = new THREE.Mesh(boxGeo7, redMat);
  markerL.name = 'markerL';
  markerL.position.set(-1.73, 2.58, 0);
  root.add(markerL);
  const conduitR = new THREE.Mesh(tube([[1.445, 3.045, -1.86], [1.445, 3.045, 1.86]], 0.07, 1, 6), metalMat);
  conduitR.name = 'conduitR';
  root.add(conduitR);
  const markerR = new THREE.Mesh(boxGeo7, redMat);
  markerR.name = 'markerR';
  markerR.position.set(1.73, 2.58, 0);
  root.add(markerR);
  const roofVent = new THREE.Mesh(new THREE.BoxGeometry(1, 0.25, 1.2), trimMat);
  roofVent.name = 'roofVent';
  roofVent.position.set(-0.25, 3.425, -0.9);
  root.add(roofVent);
  const box30 = new THREE.Mesh(new THREE.BoxGeometry(0.7, 0.04, 0.9), metalMat);
  box30.position.set(-0.25, 3.57, -0.9);
  root.add(box30);
  const roofBox = new THREE.Mesh(new THREE.BoxGeometry(0.5, 0.35, 0.5), hullMat);
  roofBox.name = 'roofBox';
  roofBox.position.set(0.45, 3.475, 0.95);
  root.add(roofBox);
  const roofAntenna = new THREE.Mesh(new THREE.CylinderGeometry(0.03, 0.03, 0.8, 5), metalMat);
  roofAntenna.name = 'roofAntenna';
  roofAntenna.position.set(0.55, 4.05, 1.05);
  root.add(roofAntenna);
  const roofBeacon = new THREE.Mesh(new THREE.SphereGeometry(0.05, 6, 4), redMat);
  roofBeacon.name = 'roofBeacon';
  roofBeacon.position.set(0.55, 4.48, 1.05);
  root.add(roofBeacon);
  const floor = new THREE.Mesh(new THREE.BoxGeometry(2.26, 0.06, 3.72), floorMat);
  floor.name = 'floor';
  floor.position.set(0, 0.45, 0);
  root.add(floor);
  const box35 = new THREE.Mesh(boxGeo8, trimMat);
  box35.position.set(0, 0.484, -1.51);
  root.add(box35);
  const box36 = new THREE.Mesh(boxGeo8, trimMat);
  box36.position.set(0, 0.484, -0.69);
  root.add(box36);
  const box37 = new THREE.Mesh(boxGeo8, trimMat);
  box37.position.set(0, 0.484, 0.13);
  root.add(box37);
  const box38 = new THREE.Mesh(boxGeo8, trimMat);
  box38.position.set(0, 0.484, 0.95);
  root.add(box38);
  const box39 = new THREE.Mesh(boxGeo8, trimMat);
  box39.position.set(0, 0.484, 1.77);
  root.add(box39);
  const guideL = new THREE.Mesh(boxGeo9, glowMat);
  guideL.name = 'guideL';
  guideL.position.set(-1.03, 0.49, 0);
  root.add(guideL);
  const pipeL = new THREE.Mesh(tube([[-1.53, 2.5, -1.86], [-1.53, 2.5, 1.86]], 0.05, 1, 5), metalMat);
  pipeL.name = 'pipeL';
  root.add(pipeL);
  const cableL = new THREE.Mesh(tube([[-1.54, 1.08, -1.86], [-1.54, 1.08, 1.86]], 0.04, 1, 5), redMat);
  cableL.name = 'cableL';
  root.add(cableL);
  const guideR = new THREE.Mesh(boxGeo9, glowMat);
  guideR.name = 'guideR';
  guideR.position.set(1.03, 0.49, 0);
  root.add(guideR);
  const pipeR = new THREE.Mesh(tube([[1.53, 2.5, -1.86], [1.53, 2.5, 1.86]], 0.05, 1, 5), metalMat);
  pipeR.name = 'pipeR';
  root.add(pipeR);
  const cableR = new THREE.Mesh(tube([[1.54, 1.08, -1.86], [1.54, 1.08, 1.86]], 0.04, 1, 5), redMat);
  cableR.name = 'cableR';
  root.add(cableR);
  const ceilingLight = new THREE.Mesh(new THREE.BoxGeometry(0.45, 0.04, 3.42), glowMat);
  ceilingLight.name = 'ceilingLight';
  ceilingLight.position.set(0, 3.16, 0);
  root.add(ceilingLight);
  const frontEnd = new THREE.Group();
  frontEnd.name = 'frontEnd';
  root.add(frontEnd);
  const flange = new THREE.Mesh(extrudeGeo, trimMat);
  flange.name = 'flange';
  flange.position.set(0, 0, 1.93);
  frontEnd.add(flange);
  const bulkhead = new THREE.Mesh(extrudeGeo2, hullMat);
  bulkhead.name = 'bulkhead';
  bulkhead.position.set(0, 0, 1.82);
  frontEnd.add(bulkhead);
  const box50 = new THREE.Mesh(boxGeo10, trimMat);
  box50.position.set(-0.78, 1.505, 1.94);
  frontEnd.add(box50);
  const box51 = new THREE.Mesh(boxGeo10, trimMat);
  box51.position.set(0.78, 1.505, 1.94);
  frontEnd.add(box51);
  const doorLight = new THREE.Mesh(boxGeo11, glowMat);
  doorLight.name = 'doorLight';
  doorLight.position.set(0, 2.91, 1.94);
  frontEnd.add(doorLight);
  const doorPanel = new THREE.Mesh(boxGeo12, trimMat);
  doorPanel.name = 'doorPanel';
  doorPanel.position.set(1.04, 1.45, 1.94);
  frontEnd.add(doorPanel);
  const doorButton = new THREE.Mesh(boxGeo13, glowMat);
  doorButton.name = 'doorButton';
  doorButton.position.set(1.04, 1.5, 1.97);
  frontEnd.add(doorButton);
  const doorLeafL = new THREE.Group();
  doorLeafL.name = 'doorLeafL';
  doorLeafL.position.set(0, 0, 1.82);
  frontEnd.add(doorLeafL);
  const leaf = new THREE.Mesh(boxGeo14, metalMat);
  leaf.name = 'leaf';
  leaf.position.set(-0.36, 1.585, 0);
  doorLeafL.add(leaf);
  const seam = new THREE.Mesh(boxGeo15, glowMat);
  seam.name = 'seam';
  seam.position.set(-0.03, 1.555, 0.045);
  doorLeafL.add(seam);
  const box58 = new THREE.Mesh(boxGeo16, hazardMat);
  box58.position.set(-0.18, 1.03, 0.045);
  box58.rotation.set(0, 0, deg(35));
  doorLeafL.add(box58);
  const box59 = new THREE.Mesh(boxGeo16, hazardMat);
  box59.position.set(-0.38, 1.03, 0.045);
  box59.rotation.set(0, 0, deg(35));
  doorLeafL.add(box59);
  const doorLeafR = new THREE.Group();
  doorLeafR.name = 'doorLeafR';
  doorLeafR.position.set(0, 0, 1.82);
  frontEnd.add(doorLeafR);
  const leaf2 = new THREE.Mesh(boxGeo14, metalMat);
  leaf2.name = 'leaf';
  leaf2.position.set(0.36, 1.585, 0);
  doorLeafR.add(leaf2);
  const seam2 = new THREE.Mesh(boxGeo15, glowMat);
  seam2.name = 'seam';
  seam2.position.set(0.03, 1.555, 0.045);
  doorLeafR.add(seam2);
  const box63 = new THREE.Mesh(boxGeo16, hazardMat);
  box63.position.set(0.18, 1.03, 0.045);
  box63.rotation.set(0, 0, deg(-35));
  doorLeafR.add(box63);
  const box64 = new THREE.Mesh(boxGeo16, hazardMat);
  box64.position.set(0.38, 1.03, 0.045);
  box64.rotation.set(0, 0, deg(-35));
  doorLeafR.add(box64);
  const backEnd = new THREE.Group();
  backEnd.name = 'backEnd';
  backEnd.rotation.set(0, deg(180), 0);
  root.add(backEnd);
  const flange2 = new THREE.Mesh(extrudeGeo, trimMat);
  flange2.name = 'flange';
  flange2.position.set(0, 0, 1.93);
  backEnd.add(flange2);
  const bulkhead2 = new THREE.Mesh(extrudeGeo2, hullMat);
  bulkhead2.name = 'bulkhead';
  bulkhead2.position.set(0, 0, 1.82);
  backEnd.add(bulkhead2);
  const box68 = new THREE.Mesh(boxGeo10, trimMat);
  box68.position.set(-0.78, 1.505, 1.94);
  backEnd.add(box68);
  const box69 = new THREE.Mesh(boxGeo10, trimMat);
  box69.position.set(0.78, 1.505, 1.94);
  backEnd.add(box69);
  const doorLight2 = new THREE.Mesh(boxGeo11, glowMat);
  doorLight2.name = 'doorLight';
  doorLight2.position.set(0, 2.91, 1.94);
  backEnd.add(doorLight2);
  const doorPanel2 = new THREE.Mesh(boxGeo12, trimMat);
  doorPanel2.name = 'doorPanel';
  doorPanel2.position.set(1.04, 1.45, 1.94);
  backEnd.add(doorPanel2);
  const doorButton2 = new THREE.Mesh(boxGeo13, glowMat);
  doorButton2.name = 'doorButton';
  doorButton2.position.set(1.04, 1.5, 1.97);
  backEnd.add(doorButton2);
  const doorLeafL2 = new THREE.Group();
  doorLeafL2.name = 'doorLeafL';
  doorLeafL2.position.set(0, 0, 1.82);
  backEnd.add(doorLeafL2);
  const leaf3 = new THREE.Mesh(boxGeo14, metalMat);
  leaf3.name = 'leaf';
  leaf3.position.set(-0.36, 1.585, 0);
  doorLeafL2.add(leaf3);
  const seam3 = new THREE.Mesh(boxGeo15, glowMat);
  seam3.name = 'seam';
  seam3.position.set(-0.03, 1.555, 0.045);
  doorLeafL2.add(seam3);
  const box76 = new THREE.Mesh(boxGeo16, hazardMat);
  box76.position.set(-0.18, 1.03, 0.045);
  box76.rotation.set(0, 0, deg(35));
  doorLeafL2.add(box76);
  const box77 = new THREE.Mesh(boxGeo16, hazardMat);
  box77.position.set(-0.38, 1.03, 0.045);
  box77.rotation.set(0, 0, deg(35));
  doorLeafL2.add(box77);
  const doorLeafR2 = new THREE.Group();
  doorLeafR2.name = 'doorLeafR';
  doorLeafR2.position.set(0, 0, 1.82);
  backEnd.add(doorLeafR2);
  const leaf4 = new THREE.Mesh(boxGeo14, metalMat);
  leaf4.name = 'leaf';
  leaf4.position.set(0.36, 1.585, 0);
  doorLeafR2.add(leaf4);
  const seam4 = new THREE.Mesh(boxGeo15, glowMat);
  seam4.name = 'seam';
  seam4.position.set(0.03, 1.555, 0.045);
  doorLeafR2.add(seam4);
  const box81 = new THREE.Mesh(boxGeo16, hazardMat);
  box81.position.set(0.18, 1.03, 0.045);
  box81.rotation.set(0, 0, deg(-35));
  doorLeafR2.add(box81);
  const box82 = new THREE.Mesh(boxGeo16, hazardMat);
  box82.position.set(0.38, 1.03, 0.045);
  box82.rotation.set(0, 0, deg(-35));
  doorLeafR2.add(box82);
  const skidL = new THREE.Mesh(boxGeo17, trimMat);
  skidL.name = 'skidL';
  skidL.position.set(-0.85, 0.15, 0);
  root.add(skidL);
  const box84 = new THREE.Mesh(boxGeo18, metalMat);
  box84.position.set(-0.85, 0.04, -1.2);
  root.add(box84);
  const box85 = new THREE.Mesh(boxGeo18, metalMat);
  box85.position.set(-0.85, 0.04, 1.2);
  root.add(box85);
  const skidR = new THREE.Mesh(boxGeo17, trimMat);
  skidR.name = 'skidR';
  skidR.position.set(0.85, 0.15, 0);
  root.add(skidR);
  const box87 = new THREE.Mesh(boxGeo18, metalMat);
  box87.position.set(0.85, 0.04, -1.2);
  root.add(box87);
  const box88 = new THREE.Mesh(boxGeo18, metalMat);
  box88.position.set(0.85, 0.04, 1.2);
  root.add(box88);

  root.traverse((o) => {
    if (o.isMesh) {
      o.castShadow = true;
      o.receiveShadow = true;
    }
  });
  return root;
}

export default createStationModule;

Оценки и комментарии

—
Оценок пока нет — будьте первым.
5
0
4
0
3
0
2
0
1
0

Войдите, чтобы ставить оценки и оставлять комментарии.

0 комментариев

Комментариев пока нет. Расскажите, как вы использовали эту модель или что можно улучшить.

Похожие модели

Та же категория или похожие теги