Codels
2508 ポリゴン2.02 × 2.00 × 2.01 m
自己完結型の ES モジュールで、依存先は three のみです。ファクトリー関数を呼び出し、返された group をシーンに追加してください。
/**
 * Moon — Codels 3D model library
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the model (it floats — pickups, planets)
 * Triangles: 2,508 · Size (W × H × D): 2.02 × 2.00 × 2.00 m
 *
 * Usage:
 *   import { createMoon } from './moon.js';
 *   
 *   const model = createMoon();
 *   model.position.set(0, 0, 0);
 *   scene.add(model);
 *   
 *   // Animations: idle
 *   const mixer = new THREE.AnimationMixer(model);
 *   mixer.clipAction(THREE.AnimationClip.findByName(model.animations, 'idle')).play();
 *   // in your render loop: mixer.update(clock.getDelta());
 */
import * as THREE from 'three';

const deg = THREE.MathUtils.degToRad;

// Build animation clips from simple descriptions (Codels). Play them with THREE.AnimationMixer.
function codelsClips(THREE, entries) {
  var TAU = Math.PI * 2;
  var DEG = Math.PI / 180;
  var AX = { x: new THREE.Vector3(1, 0, 0), y: new THREE.Vector3(0, 1, 0), z: new THREE.Vector3(0, 0, 1) };
  var periodOf = function (a) { return a.type === 'spin' ? 360 / Math.abs(a.speed) : a.period; };
  var clips = [];

  // loops → 'idle'
  var loops = [];
  entries.forEach(function (e) {
    var l = e.anim.filter(function (a) { return a.type !== 'hinge'; });
    if (l.length) loops.push({ target: e.target, anim: l });
  });
  if (loops.length) {
    var periods = [];
    loops.forEach(function (e) { e.anim.forEach(function (a) { periods.push(periodOf(a)); }); });
    var longest = Math.max.apply(null, periods);
    var D = longest;
    var bestErr = Infinity;
    for (var m = 1; m <= 6 && bestErr > 0.01; m++) {
      var err = 0;
      periods.forEach(function (p) {
        var n = Math.max(1, Math.round((longest * m) / p));
        err = Math.max(err, Math.abs((longest * m) / n - p) / p);
      });
      if (err < bestErr - 1e-9) { bestErr = err; D = longest * m; }
    }
    var cycles = function (a) { return Math.max(1, Math.round(D / periodOf(a))); };
    var steps = 24;
    loops.forEach(function (e) { e.anim.forEach(function (a) { steps = Math.max(steps, cycles(a) * 24); }); });
    steps = Math.min(steps, 720);
    var tracks = [];
    loops.forEach(function (e) {
      var o = e.target;
      var q0 = o.quaternion.clone(), p0 = o.position.clone(), s0 = o.scale.clone();
      var q = new THREE.Quaternion(), turn = new THREE.Quaternion(), p = new THREE.Vector3(), s = new THREE.Vector3();
      var has = function (type) { return e.anim.some(function (a) { return a.type === type; }); };
      var turns = has('spin') || has('swing'), moves = has('bob'), grows = has('pulse');
      var times = [], qv = [], pv = [], sv = [];
      for (var k = 0; k <= steps; k++) {
        var t = (D * k) / steps;
        q.copy(q0); p.copy(p0); s.copy(s0);
        e.anim.forEach(function (a) {
          var n = cycles(a);
          var w = Math.sin(TAU * ((n * t) / D + (a.phase || 0)));
          if (a.type === 'spin') q.multiply(turn.setFromAxisAngle(AX[a.axis], (a.speed < 0 ? -TAU : TAU) * ((n * t) / D)));
          else if (a.type === 'swing') q.multiply(turn.setFromAxisAngle(AX[a.axis], a.angle * DEG * w));
          else if (a.type === 'bob') p.addScaledVector(AX[a.axis], a.distance * w);
          else if (a.type === 'pulse') s.multiplyScalar(1 + a.amount * w);
        });
        times.push(t);
        if (turns) qv.push(q.x, q.y, q.z, q.w);
        if (moves) pv.push(p.x, p.y, p.z);
        if (grows) sv.push(s.x, s.y, s.z);
      }
      if (turns) tracks.push(new THREE.QuaternionKeyframeTrack(o.uuid + '.quaternion', times, qv));
      if (moves) tracks.push(new THREE.VectorKeyframeTrack(o.uuid + '.position', times, pv));
      if (grows) tracks.push(new THREE.VectorKeyframeTrack(o.uuid + '.scale', times, sv));
    });
    clips.push(new THREE.AnimationClip('idle', D, tracks));
  }

  // hinge moves → one-shot clips ('open' …)
  var shots = {};
  entries.forEach(function (e) {
    e.anim.forEach(function (a) {
      if (a.type !== 'hinge') return;
      var name = a.clip || 'open';
      (shots[name] = shots[name] || []).push({ target: e.target, a: a });
    });
  });
  Object.keys(shots).forEach(function (name) {
    var tracks = [];
    var length = 0;
    shots[name].forEach(function (h) {
      var o = h.target, q0 = o.quaternion.clone(), q = new THREE.Quaternion(), turn = new THREE.Quaternion();
      var n = Math.max(4, Math.ceil(Math.abs(h.a.angle) / 10));
      var times = [], qv = [];
      for (var k = 0; k <= n; k++) {
        var f = k / n;
        var eased = f * f * (3 - 2 * f);
        q.copy(q0).multiply(turn.setFromAxisAngle(AX[h.a.axis], h.a.angle * DEG * eased));
        times.push(h.a.duration * f);
        qv.push(q.x, q.y, q.z, q.w);
      }
      length = Math.max(length, h.a.duration);
      tracks.push(new THREE.QuaternionKeyframeTrack(o.uuid + '.quaternion', times, qv));
    });
    clips.push(new THREE.AnimationClip(name, length, tracks));
  });
  return clips;
}

export function createMoon() {
  const root = new THREE.Group();
  root.name = 'Moon';

  // Materials
  const surfaceMat = new THREE.MeshStandardMaterial({ name: 'surface', color: 0xa7a49d, roughness: 0.95, flatShading: true });
  const seaMat = new THREE.MeshStandardMaterial({ name: 'sea', color: 0x6e6d6e, roughness: 0.95, flatShading: true });
  const floorMat = new THREE.MeshStandardMaterial({ name: 'floor', color: 0x787775, roughness: 0.95, flatShading: true });
  const rimMat = new THREE.MeshStandardMaterial({ name: 'rim', color: 0xb7b4af, roughness: 0.9, flatShading: true });

  // Parts
  const moon = new THREE.Group();
  moon.name = 'moon';
  moon.scale.setScalar(2);
  root.add(moon);
  const surface = new THREE.Mesh(new THREE.SphereGeometry(0.5, 22, 16), surfaceMat);
  surface.name = 'surface';
  moon.add(surface);
  const sea1 = new THREE.Mesh(new THREE.SphereGeometry(0.5035, 16, 4, 0, Math.PI * 2, 0, 0.4183), seaMat);
  sea1.name = 'sea1';
  sea1.rotation.set(deg(51.572), 0, deg(17.4818));
  moon.add(sea1);
  const sea2 = new THREE.Mesh(new THREE.SphereGeometry(0.5045, 16, 4, 0, Math.PI * 2, 0, 0.3732), seaMat);
  sea2.name = 'sea2';
  sea2.rotation.set(deg(-38.1833), 0, deg(-33.5104));
  moon.add(sea2);
  const sea3 = new THREE.Mesh(new THREE.SphereGeometry(0.5055, 16, 4, 0, Math.PI * 2, 0, 0.4264), seaMat);
  sea3.name = 'sea3';
  sea3.rotation.set(deg(70.5942), 0, deg(-24.8337));
  moon.add(sea3);
  const craterFloor1 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.2072), floorMat);
  craterFloor1.name = 'craterFloor1';
  craterFloor1.rotation.set(deg(-1.9855), 0, deg(-26.7075));
  moon.add(craterFloor1);
  const craterRim1 = new THREE.Group();
  craterRim1.name = 'craterRim1';
  craterRim1.position.set(0.2208, 0.4386, -0.0152);
  craterRim1.rotation.set(deg(-1.9855), 0, deg(-26.7075));
  moon.add(craterRim1);
  const torus8 = new THREE.Mesh(new THREE.TorusGeometry(0.1029, 0.0249, 3, 12), rimMat);
  torus8.rotation.set(deg(90), 0, 0);
  torus8.scale.set(1, 1, 0.6);
  craterRim1.add(torus8);
  const craterFloor2 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.2196), floorMat);
  craterFloor2.name = 'craterFloor2';
  craterFloor2.rotation.set(deg(132.2205), 0, deg(5.0209));
  moon.add(craterFloor2);
  const craterRim2 = new THREE.Group();
  craterRim2.name = 'craterRim2';
  craterRim2.position.set(-0.0429, -0.328, 0.3615);
  craterRim2.rotation.set(deg(132.2205), 0, deg(5.0209));
  moon.add(craterRim2);
  const torus11 = new THREE.Mesh(new THREE.TorusGeometry(0.1089, 0.0263, 3, 12), rimMat);
  torus11.rotation.set(deg(90), 0, 0);
  torus11.scale.set(1, 1, 0.6);
  craterRim2.add(torus11);
  const craterFloor3 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.1276), floorMat);
  craterFloor3.name = 'craterFloor3';
  craterFloor3.rotation.set(deg(-32.0851), 0, deg(44.4602));
  moon.add(craterFloor3);
  const craterRim3 = new THREE.Group();
  craterRim3.name = 'craterRim3';
  craterRim3.position.set(-0.3488, 0.3011, -0.1888);
  craterRim3.rotation.set(deg(-32.0851), 0, deg(44.4602));
  moon.add(craterRim3);
  const torus14 = new THREE.Mesh(new THREE.TorusGeometry(0.0636, 0.0153, 3, 12), rimMat);
  torus14.rotation.set(deg(90), 0, 0);
  torus14.scale.set(1, 1, 0.6);
  craterRim3.add(torus14);
  const craterFloor4 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.0836), floorMat);
  craterFloor4.name = 'craterFloor4';
  craterFloor4.rotation.set(deg(-114.26), 0, deg(44.481));
  moon.add(craterFloor4);
  const craterRim4 = new THREE.Group();
  craterRim4.name = 'craterRim4';
  craterRim4.position.set(-0.3505, -0.1467, -0.3254);
  craterRim4.rotation.set(deg(-114.26), 0, deg(44.481));
  moon.add(craterRim4);
  const torus17 = new THREE.Mesh(new THREE.TorusGeometry(0.0417, 0.01, 3, 12), rimMat);
  torus17.rotation.set(deg(90), 0, 0);
  torus17.scale.set(1, 1, 0.6);
  craterRim4.add(torus17);
  const craterFloor5 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.1327), floorMat);
  craterFloor5.name = 'craterFloor5';
  craterFloor5.rotation.set(deg(167.4273), 0, deg(-55.9671));
  moon.add(craterFloor5);
  const craterRim5 = new THREE.Group();
  craterRim5.name = 'craterRim5';
  craterRim5.position.set(0.4124, -0.2718, 0.0606);
  craterRim5.rotation.set(deg(167.4273), 0, deg(-55.9671));
  moon.add(craterRim5);
  const torus20 = new THREE.Mesh(new THREE.TorusGeometry(0.0661, 0.0159, 3, 12), rimMat);
  torus20.rotation.set(deg(90), 0, 0);
  torus20.scale.set(1, 1, 0.6);
  craterRim5.add(torus20);
  const craterFloor6 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.0787), floorMat);
  craterFloor6.name = 'craterFloor6';
  craterFloor6.rotation.set(deg(153.2506), 0, deg(-11.8131));
  moon.add(craterFloor6);
  const craterRim6 = new THREE.Group();
  craterRim6.name = 'craterRim6';
  craterRim6.position.set(0.1025, -0.4374, 0.2205);
  craterRim6.rotation.set(deg(153.2506), 0, deg(-11.8131));
  moon.add(craterRim6);
  const torus23 = new THREE.Mesh(new THREE.TorusGeometry(0.0393, 0.0094, 3, 12), rimMat);
  torus23.rotation.set(deg(90), 0, 0);
  torus23.scale.set(1, 1, 0.6);
  craterRim6.add(torus23);
  const craterFloor7 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.1062), floorMat);
  craterFloor7.name = 'craterFloor7';
  craterFloor7.rotation.set(deg(-41.1398), 0, deg(19.1448));
  moon.add(craterFloor7);
  const craterRim7 = new THREE.Group();
  craterRim7.name = 'craterRim7';
  craterRim7.position.set(-0.1637, 0.3551, -0.3102);
  craterRim7.rotation.set(deg(-41.1398), 0, deg(19.1448));
  moon.add(craterRim7);
  const torus26 = new THREE.Mesh(new THREE.TorusGeometry(0.053, 0.0127, 3, 12), rimMat);
  torus26.rotation.set(deg(90), 0, 0);
  torus26.scale.set(1, 1, 0.6);
  craterRim7.add(torus26);
  const craterFloor8 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.1433), floorMat);
  craterFloor8.name = 'craterFloor8';
  craterFloor8.rotation.set(deg(71.4527), 0, deg(84.9938));
  moon.add(craterFloor8);
  const craterRim8 = new THREE.Group();
  craterRim8.name = 'craterRim8';
  craterRim8.position.set(-0.495, 0.0138, 0.0411);
  craterRim8.rotation.set(deg(71.4527), 0, deg(84.9938));
  moon.add(craterRim8);
  const torus29 = new THREE.Mesh(new THREE.TorusGeometry(0.0714, 0.0172, 3, 12), rimMat);
  torus29.rotation.set(deg(90), 0, 0);
  torus29.scale.set(1, 1, 0.6);
  craterRim8.add(torus29);
  const craterFloor9 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.1016), floorMat);
  craterFloor9.name = 'craterFloor9';
  craterFloor9.rotation.set(deg(-113.2903), 0, deg(-48.2352));
  moon.add(craterFloor9);
  const craterRim9 = new THREE.Group();
  craterRim9.name = 'craterRim9';
  craterRim9.position.set(0.3725, -0.1315, -0.3055);
  craterRim9.rotation.set(deg(-113.2903), 0, deg(-48.2352));
  moon.add(craterRim9);
  const torus32 = new THREE.Mesh(new THREE.TorusGeometry(0.0507, 0.0122, 3, 12), rimMat);
  torus32.rotation.set(deg(90), 0, 0);
  torus32.scale.set(1, 1, 0.6);
  craterRim9.add(torus32);
  const craterFloor10 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.1061), floorMat);
  craterFloor10.name = 'craterFloor10';
  craterFloor10.rotation.set(deg(97.1458), 0, deg(0.109));
  moon.add(craterFloor10);
  const craterRim10 = new THREE.Group();
  craterRim10.name = 'craterRim10';
  craterRim10.position.set(-0.0009, -0.0621, 0.4953);
  craterRim10.rotation.set(deg(97.1458), 0, deg(0.109));
  moon.add(craterRim10);
  const torus35 = new THREE.Mesh(new THREE.TorusGeometry(0.0529, 0.0127, 3, 12), rimMat);
  torus35.rotation.set(deg(90), 0, 0);
  torus35.scale.set(1, 1, 0.6);
  craterRim10.add(torus35);
  const craterFloor11 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.0802), floorMat);
  craterFloor11.name = 'craterFloor11';
  craterFloor11.rotation.set(deg(-2.6629), 0, deg(21.392));
  moon.add(craterFloor11);
  const craterRim11 = new THREE.Group();
  craterRim11.name = 'craterRim11';
  craterRim11.position.set(-0.1825, 0.4654, -0.0216);
  craterRim11.rotation.set(deg(-2.6629), 0, deg(21.392));
  moon.add(craterRim11);
  const torus38 = new THREE.Mesh(new THREE.TorusGeometry(0.0401, 0.0096, 3, 12), rimMat);
  torus38.rotation.set(deg(90), 0, 0);
  torus38.scale.set(1, 1, 0.6);
  craterRim11.add(torus38);
  const craterFloor12 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.0879), floorMat);
  craterFloor12.name = 'craterFloor12';
  craterFloor12.rotation.set(deg(-50.471), 0, deg(-55.5141));
  moon.add(craterFloor12);
  const craterRim12 = new THREE.Group();
  craterRim12.name = 'craterRim12';
  craterRim12.position.set(0.4122, 0.1802, -0.2184);
  craterRim12.rotation.set(deg(-50.471), 0, deg(-55.5141));
  moon.add(craterRim12);
  const torus41 = new THREE.Mesh(new THREE.TorusGeometry(0.0439, 0.0106, 3, 12), rimMat);
  torus41.rotation.set(deg(90), 0, 0);
  torus41.scale.set(1, 1, 0.6);
  craterRim12.add(torus41);
  const craterFloor13 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.1311), floorMat);
  craterFloor13.name = 'craterFloor13';
  craterFloor13.rotation.set(deg(21.7535), 0, deg(-39.9478));
  moon.add(craterFloor13);
  const craterRim13 = new THREE.Group();
  craterRim13.name = 'craterRim13';
  craterRim13.position.set(0.3196, 0.3544, 0.1414);
  craterRim13.rotation.set(deg(21.7535), 0, deg(-39.9478));
  moon.add(craterRim13);
  const torus44 = new THREE.Mesh(new THREE.TorusGeometry(0.0654, 0.0157, 3, 12), rimMat);
  torus44.rotation.set(deg(90), 0, 0);
  torus44.scale.set(1, 1, 0.6);
  craterRim13.add(torus44);
  const craterFloor14 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.0876), floorMat);
  craterFloor14.name = 'craterFloor14';
  craterFloor14.rotation.set(deg(-157.1896), 0, deg(-42.0196));
  moon.add(craterFloor14);
  const craterRim14 = new THREE.Group();
  craterRim14.name = 'craterRim14';
  craterRim14.position.set(0.3347, -0.3425, -0.144);
  craterRim14.rotation.set(deg(-157.1896), 0, deg(-42.0196));
  moon.add(craterRim14);
  const torus47 = new THREE.Mesh(new THREE.TorusGeometry(0.0438, 0.0105, 3, 12), rimMat);
  torus47.rotation.set(deg(90), 0, 0);
  torus47.scale.set(1, 1, 0.6);
  craterRim14.add(torus47);

  // Animations ('idle') — play them with THREE.AnimationMixer
  root.animations = codelsClips(THREE, [
    { target: moon, anim: [{ type: 'spin', axis: 'y', speed: 15 }] },
  ]);

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

export default createMoon;

評価とコメント

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

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

0 件のコメント

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

関連モデル

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