Codels
1000 ポリゴン5.07 × 2.81 × 8.48 m
自己完結型の ES モジュールで、依存先は three のみです。ファクトリー関数を呼び出し、返された group をシーンに追加してください。
/**
 * Whale — Codels 3D model library
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the model (it floats — pickups, planets)
 * Triangles: 1,000 · Size (W × H × D): 5.07 × 2.81 × 8.48 m
 *
 * Usage:
 *   import { createWhale } from './whale.js';
 *   
 *   const model = createWhale();
 *   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);
}

// 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 createWhale() {
  const root = new THREE.Group();
  root.name = 'Whale';

  // Materials
  const bodyMat = new THREE.MeshStandardMaterial({ name: 'body', color: 0x3f6fb4, roughness: 0.55, flatShading: true });
  const bellyMat = new THREE.MeshStandardMaterial({ name: 'belly', color: 0xe2ebf0, roughness: 0.6, flatShading: true });
  const finMat = new THREE.MeshStandardMaterial({ name: 'fin', color: 0x365e99, roughness: 0.55, flatShading: true });
  const eyeMat = new THREE.MeshStandardMaterial({ name: 'eye', color: 0x151318, roughness: 0.25, flatShading: true });
  const shineMat = new THREE.MeshStandardMaterial({ name: 'shine', color: 0xffffff, roughness: 0.3, flatShading: true });

  // Shared geometries
  const sphereGeo = new THREE.SphereGeometry(0.022, 8, 6);
  const sphereGeo2 = new THREE.SphereGeometry(0.0075, 4, 3);
  const boxGeo = new THREE.BoxGeometry(0.012, 0.01, 0.03);

  // Parts
  const whale = new THREE.Group();
  whale.name = 'whale';
  whale.position.set(0, 0.2223, 0);
  whale.scale.setScalar(8);
  root.add(whale);
  const body = new THREE.Group();
  body.name = 'body';
  whale.add(body);
  const bodyShell = new THREE.Mesh(lathe([[0, -0.47], [0.035, -0.45], [0.06, -0.38], [0.1, -0.26], [0.145, -0.1], [0.168, 0.04], [0.172, 0.18], [0.158, 0.3], [0.125, 0.4], [0.07, 0.465], [0, 0.49]], 12), bodyMat);
  bodyShell.name = 'bodyShell';
  bodyShell.rotation.set(deg(90), 0, 0);
  bodyShell.scale.set(1, 1, 0.86);
  body.add(bodyShell);
  const bellyShell = new THREE.Mesh(lathe([[0, -0.4512], [0.0333, -0.432], [0.057, -0.3648], [0.095, -0.2496], [0.1377, -0.096], [0.1596, 0.0384], [0.1634, 0.1728], [0.1501, 0.288], [0.1188, 0.384], [0.0665, 0.4464], [0, 0.4704]], 12), bellyMat);
  bellyShell.name = 'bellyShell';
  bellyShell.position.set(0, -0.038, 0.004);
  bellyShell.rotation.set(deg(90), 0, 0);
  bellyShell.scale.set(0.93, 1, 0.774);
  body.add(bellyShell);
  const mouthL = new THREE.Mesh(tube([[0.0286, -0.0425, 0.47], [0.0869, -0.0584, 0.42], [0.1388, -0.0582, 0.32], [0.1559, -0.0597, 0.22], [0.1681, -0.0414, 0.16]], 0.006, 12, 4), eyeMat);
  mouthL.name = 'mouthL';
  body.add(mouthL);
  const eyeL = new THREE.Mesh(sphereGeo, eyeMat);
  eyeL.name = 'eyeL';
  eyeL.position.set(0.1693, -0.0102, 0.2);
  eyeL.scale.set(0.6, 1, 1);
  body.add(eyeL);
  const eyeShineL = new THREE.Mesh(sphereGeo2, shineMat);
  eyeShineL.name = 'eyeShineL';
  eyeShineL.position.set(0.1813, -0.0012, 0.206);
  body.add(eyeShineL);
  const mouthR = new THREE.Mesh(tube([[-0.0286, -0.0425, 0.47], [-0.0869, -0.0584, 0.42], [-0.1388, -0.0582, 0.32], [-0.1559, -0.0597, 0.22], [-0.1681, -0.0414, 0.16]], 0.006, 12, 4), eyeMat);
  mouthR.name = 'mouthR';
  body.add(mouthR);
  const eyeR = new THREE.Mesh(sphereGeo, eyeMat);
  eyeR.name = 'eyeR';
  eyeR.position.set(-0.1693, -0.0102, 0.2);
  eyeR.scale.set(0.6, 1, 1);
  body.add(eyeR);
  const eyeShineR = new THREE.Mesh(sphereGeo2, shineMat);
  eyeShineR.name = 'eyeShineR';
  eyeShineR.position.set(-0.1813, -0.0012, 0.206);
  body.add(eyeShineR);
  const blowhole = new THREE.Mesh(boxGeo, eyeMat);
  blowhole.name = 'blowhole';
  blowhole.position.set(0.01, 0.1369, 0.27);
  blowhole.rotation.set(0, deg(15), 0);
  body.add(blowhole);
  const blowhole2 = new THREE.Mesh(boxGeo, eyeMat);
  blowhole2.name = 'blowhole';
  blowhole2.position.set(-0.01, 0.1369, 0.27);
  blowhole2.rotation.set(0, deg(-15), 0);
  body.add(blowhole2);
  const dorsalFin = new THREE.Mesh(extrude([[-0.06, 0], [0.05, 0], [-0.03, 0.045], [-0.05, 0.04]], 0.02), finMat);
  dorsalFin.name = 'dorsalFin';
  dorsalFin.position.set(0, 0.0975, -0.2);
  dorsalFin.rotation.set(0, deg(90), 0);
  body.add(dorsalFin);
  const tail = new THREE.Group();
  tail.name = 'tail';
  tail.position.set(0, 0, -0.44);
  whale.add(tail);
  const flukes = new THREE.Mesh(extrude([[0, 0.03], [0.07, -0.02], [0.17, -0.07], [0.23, -0.13], [0.16, -0.13], [0.07, -0.11], [0, -0.08], [-0.07, -0.11], [-0.16, -0.13], [-0.23, -0.13], [-0.17, -0.07], [-0.07, -0.02]], 0.022), finMat);
  flukes.name = 'flukes';
  flukes.rotation.set(deg(90), 0, 0);
  tail.add(flukes);
  const finL = new THREE.Group();
  finL.name = 'finL';
  finL.position.set(0.1206, -0.0934, 0.14);
  finL.rotation.set(deg(18.1971), deg(30.4269), deg(-32.9875));
  whale.add(finL);
  const flipperL = new THREE.Mesh(extrude([[0, 0.035], [0.09, 0.045], [0.2, 0.03], [0.26, 0.008], [0.25, -0.012], [0.18, -0.02], [0.06, -0.03], [0, -0.03]], 0.018), finMat);
  flipperL.name = 'flipperL';
  flipperL.rotation.set(deg(90), 0, 0);
  finL.add(flipperL);
  const finR = new THREE.Group();
  finR.name = 'finR';
  finR.position.set(-0.1206, -0.0934, 0.14);
  finR.rotation.set(deg(18.1971), deg(-30.4269), deg(32.9875));
  whale.add(finR);
  const flipperR = new THREE.Mesh(extrude([[0, 0.035], [-0.09, 0.045], [-0.2, 0.03], [-0.26, 0.008], [-0.25, -0.012], [-0.18, -0.02], [-0.06, -0.03], [0, -0.03]], 0.018), finMat);
  flipperR.name = 'flipperR';
  flipperR.rotation.set(deg(90), 0, 0);
  finR.add(flipperR);

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

export default createWhale;

評価とコメント

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

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

0 件のコメント

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

関連モデル

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