Codels
1084 ポリゴン2.27 × 10.1 × 6.36 m
自己完結型の ES モジュールで、依存先は three のみです。ファクトリー関数を呼び出し、返された group をシーンに追加してください。
/**
 * Sailboat — Codels 3D model library
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 1,084 · Size (W × H × D): 2.27 × 10.10 × 6.36 m
 *
 * Usage:
 *   import { createSailboat } from './sailboat.js';
 *   
 *   const model = createSailboat();
 *   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 createSailboat() {
  const root = new THREE.Group();
  root.name = 'Sailboat';

  // Materials
  const hullMat = new THREE.MeshStandardMaterial({ name: 'hull', color: 0x24527d, roughness: 0.45, metalness: 0.1, flatShading: true });
  const whiteMat = new THREE.MeshStandardMaterial({ name: 'white', color: 0xf1eee6, roughness: 0.55, flatShading: true });
  const woodMat = new THREE.MeshStandardMaterial({ name: 'wood', color: 0xb98a5c, roughness: 0.85, flatShading: true });
  const sailMat = new THREE.MeshStandardMaterial({ name: 'sail', color: 0xf5f1e6, roughness: 0.8, flatShading: true });
  const accentMat = new THREE.MeshStandardMaterial({ name: 'accent', color: 0xd6493c, roughness: 0.5, flatShading: true });
  const darkMat = new THREE.MeshStandardMaterial({ name: 'dark', color: 0x3b3f46, roughness: 0.5, metalness: 0.4, flatShading: true });
  const glassMat = new THREE.MeshStandardMaterial({ name: 'glass', color: 0x2a3746, roughness: 0.2, metalness: 0.3, flatShading: true });

  // Shared geometries
  const boxGeo = new THREE.BoxGeometry(0.02, 0.14, 0.32);
  const boxGeo2 = new THREE.BoxGeometry(0.06, 0.16, 1.46);

  // Parts
  const hull = new THREE.Group();
  hull.name = 'hull';
  root.add(hull);
  const bowHull = new THREE.Mesh(new THREE.SphereGeometry(1, 12, 5, 0, Math.PI, Math.PI / 2, Math.PI / 2), hullMat);
  bowHull.name = 'bowHull';
  bowHull.position.set(0, 1.6, 0);
  bowHull.scale.set(1.12, 0.55, 3.55);
  hull.add(bowHull);
  const sternHull = new THREE.Mesh(new THREE.SphereGeometry(1, 12, 5, Math.PI, Math.PI, Math.PI / 2, Math.PI / 2), hullMat);
  sternHull.name = 'sternHull';
  sternHull.position.set(0, 1.6, 0);
  sternHull.scale.set(1.12, 0.55, 2.75);
  hull.add(sternHull);
  const topsides = new THREE.Mesh(extrude([[-1.12, 0], [-1.0818, 0.9188], [-0.9699, 1.775], [-0.792, 2.5102], [-0.56, 3.0744], [-0.2899, 3.429], [0, 3.55], [0.2899, 3.429], [0.56, 3.0744], [0.792, 2.5102], [0.9699, 1.775], [1.0818, 0.9188], [1.12, 0], [1.0818, -0.7118], [0.9699, -1.375], [0.792, -1.9445], [0.56, -2.3816], [0.2899, -2.6563], [0, -2.75], [-0.2899, -2.6563], [-0.56, -2.3816], [-0.792, -1.9445], [-0.9699, -1.375], [-1.0818, -0.7118]], 0.42), hullMat);
  topsides.name = 'topsides';
  topsides.position.set(0, 1.81, 0);
  topsides.rotation.set(deg(90), 0, 0);
  hull.add(topsides);
  const waterlineStripe = new THREE.Mesh(extrude([[-1.12, 0], [-1.0818, 0.9188], [-0.9699, 1.775], [-0.792, 2.5102], [-0.56, 3.0744], [-0.2899, 3.429], [0, 3.55], [0.2899, 3.429], [0.56, 3.0744], [0.792, 2.5102], [0.9699, 1.775], [1.0818, 0.9188], [1.12, 0], [1.0818, -0.7118], [0.9699, -1.375], [0.792, -1.9445], [0.56, -2.3816], [0.2899, -2.6563], [0, -2.75], [-0.2899, -2.6563], [-0.56, -2.3816], [-0.792, -1.9445], [-0.9699, -1.375], [-1.0818, -0.7118]], 0.1), accentMat);
  waterlineStripe.name = 'waterlineStripe';
  waterlineStripe.position.set(0, 1.67, 0);
  waterlineStripe.rotation.set(deg(90), 0, 0);
  waterlineStripe.scale.set(1.012, 1.008, 1);
  hull.add(waterlineStripe);
  const deck = new THREE.Mesh(extrude([[-1.12, 0], [-1.0818, 0.9188], [-0.9699, 1.775], [-0.792, 2.5102], [-0.56, 3.0744], [-0.2899, 3.429], [0, 3.55], [0.2899, 3.429], [0.56, 3.0744], [0.792, 2.5102], [0.9699, 1.775], [1.0818, 0.9188], [1.12, 0], [1.0818, -0.7118], [0.9699, -1.375], [0.792, -1.9445], [0.56, -2.3816], [0.2899, -2.6563], [0, -2.75], [-0.2899, -2.6563], [-0.56, -2.3816], [-0.792, -1.9445], [-0.9699, -1.375], [-1.0818, -0.7118]], 0.06), woodMat);
  deck.name = 'deck';
  deck.position.set(0, 2.03, 0);
  deck.rotation.set(deg(90), 0, 0);
  deck.scale.set(1.015, 1.01, 1);
  hull.add(deck);
  const keel = new THREE.Mesh(extrude([[0.45, 1.13], [-0.3, 1.13], [-0.42, 0.14], [0.12, 0.14]], 0.1), darkMat);
  keel.name = 'keel';
  keel.rotation.set(0, deg(-90), 0);
  hull.add(keel);
  const keelBulb = new THREE.Mesh(new THREE.CapsuleGeometry(0.13, 0.7, 3, 8), darkMat);
  keelBulb.name = 'keelBulb';
  keelBulb.position.set(0, 0.13, -0.12);
  keelBulb.rotation.set(deg(90), 0, 0);
  hull.add(keelBulb);
  const rudder = new THREE.Mesh(extrude([[-2.3, 1.5], [-2.62, 1.5], [-2.72, 0.75], [-2.45, 0.8]], 0.06), woodMat);
  rudder.name = 'rudder';
  rudder.rotation.set(0, deg(-90), 0);
  hull.add(rudder);
  const deckGear = new THREE.Group();
  deckGear.name = 'deckGear';
  root.add(deckGear);
  const cabin = new THREE.Mesh(extrude([[1.65, 2.04], [1.32, 2.52], [-0.45, 2.56], [-0.52, 2.04]], 1.24, [], [0.04, 0.04, 2]), whiteMat);
  cabin.name = 'cabin';
  cabin.rotation.set(0, deg(-90), 0);
  deckGear.add(cabin);
  const box12 = new THREE.Mesh(boxGeo, glassMat);
  box12.position.set(0.665, 2.33, 0.95);
  deckGear.add(box12);
  const box13 = new THREE.Mesh(boxGeo, glassMat);
  box13.position.set(0.665, 2.33, 0.47);
  deckGear.add(box13);
  const box14 = new THREE.Mesh(boxGeo, glassMat);
  box14.position.set(0.665, 2.33, -0.01);
  deckGear.add(box14);
  const box15 = new THREE.Mesh(boxGeo, glassMat);
  box15.position.set(-0.665, 2.33, 0.95);
  deckGear.add(box15);
  const box16 = new THREE.Mesh(boxGeo, glassMat);
  box16.position.set(-0.665, 2.33, 0.47);
  deckGear.add(box16);
  const box17 = new THREE.Mesh(boxGeo, glassMat);
  box17.position.set(-0.665, 2.33, -0.01);
  deckGear.add(box17);
  const frontWindow = new THREE.Mesh(new THREE.BoxGeometry(0.9, 0.02, 0.28), glassMat);
  frontWindow.name = 'frontWindow';
  frontWindow.position.set(0, 2.31, 1.535);
  frontWindow.rotation.set(deg(55.5), 0, 0);
  deckGear.add(frontWindow);
  const cockpitFloor = new THREE.Mesh(new THREE.BoxGeometry(1.3, 0.02, 1.4), darkMat);
  cockpitFloor.name = 'cockpitFloor';
  cockpitFloor.position.set(0, 2.062, -1.3);
  deckGear.add(cockpitFloor);
  const box20 = new THREE.Mesh(boxGeo2, whiteMat);
  box20.position.set(0.68, 2.14, -1.3);
  deckGear.add(box20);
  const box21 = new THREE.Mesh(boxGeo2, whiteMat);
  box21.position.set(-0.68, 2.14, -1.3);
  deckGear.add(box21);
  const box22 = new THREE.Mesh(new THREE.BoxGeometry(1.42, 0.16, 0.06), whiteMat);
  box22.position.set(0, 2.14, -2.03);
  deckGear.add(box22);
  const rudderStock = new THREE.Mesh(new THREE.CylinderGeometry(0.03, 0.03, 0.3, 6), darkMat);
  rudderStock.name = 'rudderStock';
  rudderStock.position.set(0, 2.21, -2.5);
  deckGear.add(rudderStock);
  const tiller = new THREE.Mesh(new THREE.BoxGeometry(0.05, 0.05, 1), woodMat);
  tiller.name = 'tiller';
  tiller.position.set(0, 2.39, -2.05);
  tiller.rotation.set(deg(-6), 0, 0);
  deckGear.add(tiller);
  const pulpit = new THREE.Mesh(tube([[-0.42, 2.06, 3], [-0.3, 2.51, 3.25], [0, 2.56, 3.45], [0.3, 2.51, 3.25], [0.42, 2.06, 3]], 0.02, 10, 4), darkMat);
  pulpit.name = 'pulpit';
  deckGear.add(pulpit);
  const rig = new THREE.Group();
  rig.name = 'rig';
  root.add(rig);
  const mast = new THREE.Mesh(new THREE.CylinderGeometry(0.055, 0.075, 8, 8), darkMat);
  mast.name = 'mast';
  mast.position.set(0, 6.02, 0.85);
  rig.add(mast);
  const masthead = new THREE.Mesh(new THREE.SphereGeometry(0.06, 6, 4), accentMat);
  masthead.name = 'masthead';
  masthead.position.set(0, 10.04, 0.85);
  rig.add(masthead);
  const forestay = new THREE.Mesh(tube([[0, 2.07, 3.43], [0, 9.92, 0.85]], 0.012, 1, 4), darkMat);
  forestay.name = 'forestay';
  rig.add(forestay);
  const backstay = new THREE.Mesh(tube([[0, 9.92, 0.85], [0, 2.12, -2.63]], 0.012, 1, 4), darkMat);
  backstay.name = 'backstay';
  rig.add(backstay);
  const shroudL = new THREE.Mesh(tube([[0, 8.82, 0.85], [1.07, 2.06, 0.6]], 0.012, 1, 4), darkMat);
  shroudL.name = 'shroudL';
  rig.add(shroudL);
  const shroudR = new THREE.Mesh(tube([[0, 8.82, 0.85], [-1.07, 2.06, 0.6]], 0.012, 1, 4), darkMat);
  shroudR.name = 'shroudR';
  rig.add(shroudR);
  const spreader = new THREE.Mesh(new THREE.BoxGeometry(0.7, 0.04, 0.05), darkMat);
  spreader.name = 'spreader';
  spreader.position.set(0, 6.62, 0.85);
  rig.add(spreader);
  const mainsail = new THREE.Group();
  mainsail.name = 'mainsail';
  mainsail.position.set(0, 0, 0.85);
  mainsail.rotation.set(0, deg(-22), 0);
  rig.add(mainsail);
  const boom = new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.05, 2.9, 6), darkMat);
  boom.name = 'boom';
  boom.position.set(0, 2.97, -1.45);
  boom.rotation.set(deg(90), 0, 0);
  mainsail.add(boom);
  const mainSail = new THREE.Mesh(extrude([[-0.08, 3.03], [-2.85, 3.03], [-0.08, 9.77]], 0.03), sailMat);
  mainSail.name = 'mainSail';
  mainSail.rotation.set(0, deg(-90), 0);
  mainsail.add(mainSail);
  const sailStripe = new THREE.Mesh(extrude([[-0.08, 4.57], [-2.2471, 4.57], [-2.1649, 4.77], [-0.08, 4.77]], 0.05), accentMat);
  sailStripe.name = 'sailStripe';
  sailStripe.rotation.set(0, deg(-90), 0);
  mainsail.add(sailStripe);
  const jib = new THREE.Group();
  jib.name = 'jib';
  jib.position.set(0, 2.07, 3.43);
  jib.rotation.set(deg(-18.1938), 0, 0);
  rig.add(jib);
  const jibSwing = new THREE.Group();
  jibSwing.name = 'jibSwing';
  jibSwing.rotation.set(0, deg(-14), 0);
  jib.add(jibSwing);
  const jibSail = new THREE.Mesh(extrude([[0, 0.25], [0, 6.4452], [-2.55, 1.6]], 0.03), sailMat);
  jibSail.name = 'jibSail';
  jibSail.rotation.set(0, deg(-90), 0);
  jibSwing.add(jibSail);

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

export default createSailboat;

評価とコメント

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

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

0 件のコメント

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

関連モデル

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