Codels
3132 ポリゴン5.07 × 6.63 × 19.0 m
自己完結型の ES モジュールで、依存先は three のみです。ファクトリー関数を呼び出し、返された group をシーンに追加してください。
/**
 * 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;

評価とコメント

—
まだ評価はありません。最初の評価をしてみましょう。
5
0
4
0
3
0
2
0
1
0

評価やコメントをするにはログインしてください。

0 件のコメント

まだコメントはありません。このモデルの使い方や改善できる点を共有しましょう。

関連モデル

同じカテゴリまたは似たタグ