Codels
958 三角面4.98 × 3.80 × 16.1 m

在代码中使用

在编辑器中改编
自包含的 ES 模块,仅依赖 three。调用工厂函数,然后把返回的 group 添加到场景中。
/**
 * Comet — Codels 3D model library
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the model (it floats — pickups, planets)
 * Triangles: 958 · Size (W × H × D): 4.98 × 3.80 × 16.05 m
 *
 * Usage:
 *   import { createComet } from './comet.js';
 *   
 *   const model = createComet();
 *   model.position.set(0, 0, 0);
 *   scene.add(model);
 */
import * as THREE from 'three';

const deg = THREE.MathUtils.degToRad;

// Deterministic vertex displacement (organic low-poly look).
function jitter(geometry, amount, seed) {
  const pos = geometry.attributes.position;
  const h = (a, b, c, s) => {
    let x = Math.imul(a, 73856093) ^ Math.imul(b, 19349663) ^ Math.imul(c, 83492791) ^ Math.imul(s, 2654435761);
    x = Math.imul(x ^ (x >>> 16), 2246822507);
    x = Math.imul(x ^ (x >>> 13), 3266489909);
    return ((x ^ (x >>> 16)) >>> 0) / 4294967295 - 0.5;
  };
  for (let i = 0; i < pos.count; i++) {
    const x = pos.getX(i), y = pos.getY(i), z = pos.getZ(i);
    const qx = Math.round(x * 1000), qy = Math.round(y * 1000), qz = Math.round(z * 1000);
    pos.setXYZ(i, x + h(qx, qy, qz, seed) * 2 * amount, y + h(qx, qy, qz, seed + 1) * 2 * amount, z + h(qx, qy, qz, seed + 2) * 2 * amount);
  }
  pos.needsUpdate = true;
  geometry.computeVertexNormals();
  return geometry;
}

export function createComet() {
  const root = new THREE.Group();
  root.name = 'Comet';

  // Materials
  const rockMat = new THREE.MeshStandardMaterial({ name: 'rock', color: 0x5b616d, roughness: 0.9, flatShading: true });
  const iceMat = new THREE.MeshStandardMaterial({ name: 'ice', color: 0xd6ecf7, roughness: 0.35, flatShading: true });
  const comaMat = new THREE.MeshStandardMaterial({ name: 'coma', color: 0x84ccff, roughness: 0.8, emissive: 0x4fb6ff, emissiveIntensity: 0.5, transparent: true, opacity: 0.35 });
  const comaOuterMat = new THREE.MeshStandardMaterial({ name: 'comaOuter', color: 0x4fb6ff, roughness: 0.8, emissive: 0x4fb6ff, emissiveIntensity: 0.7, transparent: true, opacity: 0.18 });
  const ionMat = new THREE.MeshStandardMaterial({ name: 'ion', color: 0x47a4e6, roughness: 0.8, emissive: 0x4fb6ff, emissiveIntensity: 0.6, transparent: true, opacity: 0.55, side: THREE.DoubleSide });
  const dustMat = new THREE.MeshStandardMaterial({ name: 'dust', color: 0xb9d0cb, roughness: 0.8, emissive: 0xc1ccb3, emissiveIntensity: 0.45, transparent: true, opacity: 0.4, side: THREE.DoubleSide });
  const sparkleMat = new THREE.MeshStandardMaterial({ name: 'sparkle', color: 0xb9e2ff, roughness: 0.3, emissive: 0x4fb6ff, emissiveIntensity: 1.2, flatShading: true });

  // Parts
  const comet = new THREE.Group();
  comet.name = 'comet';
  comet.position.set(-1.1168, 0, 6.15);
  comet.scale.setScalar(2);
  root.add(comet);
  const nucleus = new THREE.Group();
  nucleus.name = 'nucleus';
  nucleus.rotation.set(deg(36.743), deg(25.5005), 0);
  comet.add(nucleus);
  const rock = new THREE.Mesh(jitter(new THREE.IcosahedronGeometry(0.5, 1), 0.05, 9), rockMat);
  rock.name = 'rock';
  rock.scale.set(1, 0.82, 0.92);
  nucleus.add(rock);
  const lump1 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.1641, 0), 0.0246, 45), rockMat);
  lump1.name = 'lump1';
  lump1.position.set(-0.0977, 0.3097, -0.1159);
  lump1.rotation.set(deg(80.3639), deg(19.8083), 0);
  nucleus.add(lump1);
  const lump2 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.1593, 0), 0.0239, 46), iceMat);
  lump2.name = 'lump2';
  lump2.position.set(0.1611, 0.203, 0.2616);
  lump2.rotation.set(deg(32.3315), deg(34.4613), 0);
  nucleus.add(lump2);
  const lump3 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.1567, 0), 0.0235, 47), rockMat);
  lump3.name = 'lump3';
  lump3.position.set(0.3571, -0.1372, 0.1031);
  lump3.rotation.set(deg(70.1489), deg(84.5626), 0);
  nucleus.add(lump3);
  const lump4 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.1226, 0), 0.0184, 48), iceMat);
  lump4.name = 'lump4';
  lump4.position.set(-0.367, -0.1143, 0.1088);
  lump4.rotation.set(deg(85.8831), deg(40.5874), 0);
  nucleus.add(lump4);
  const lump5 = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.1579, 0), 0.0237, 49), rockMat);
  lump5.name = 'lump5';
  lump5.position.set(-0.0303, 0.334, 0.0334);
  lump5.rotation.set(deg(53.7665), deg(83.3643), 0);
  nucleus.add(lump5);
  const frost = new THREE.Mesh(jitter(new THREE.SphereGeometry(0.48, 10, 3, 0, Math.PI * 2, 0, 0.9), 0.025, 16), iceMat);
  frost.name = 'frost';
  frost.rotation.set(deg(70), 0, 0);
  frost.scale.set(1, 0.84, 0.94);
  nucleus.add(frost);
  const coma = new THREE.Mesh(new THREE.SphereGeometry(0.7, 14, 10), comaMat);
  coma.name = 'coma';
  comet.add(coma);
  const comaHalo = new THREE.Mesh(new THREE.SphereGeometry(0.95, 14, 10), comaOuterMat);
  comaHalo.name = 'comaHalo';
  comet.add(comaHalo);
  const ionTail = new THREE.Mesh(new THREE.ConeGeometry(0.525, 7, 10, 1, true), ionMat);
  ionTail.name = 'ionTail';
  ionTail.position.set(0, 0, -3.6);
  ionTail.rotation.set(deg(-90), 0, 0);
  comet.add(ionTail);
  const ionCore = new THREE.Mesh(new THREE.ConeGeometry(0.25, 5.6, 8, 1, true), ionMat);
  ionCore.name = 'ionCore';
  ionCore.position.set(0, 0, -2.9);
  ionCore.rotation.set(deg(-90), 0, 0);
  comet.add(ionCore);
  const dustTail1 = new THREE.Mesh(new THREE.ConeGeometry(0.75, 5.46, 10, 1, true), dustMat);
  dustTail1.name = 'dustTail1';
  dustTail1.position.set(0.351, 0, -2.8585);
  dustTail1.rotation.set(deg(-89.1427), deg(6.9476), deg(-7.052));
  comet.add(dustTail1);
  const dustTail2 = new THREE.Mesh(new THREE.ConeGeometry(0.675, 4.62, 10, 1, true), dustMat);
  dustTail2.name = 'dustTail2';
  dustTail2.position.set(0.6367, 0, -2.3762);
  dustTail2.rotation.set(deg(-86.0329), deg(14.4775), deg(-15.5041));
  comet.add(dustTail2);
  const dustTail3 = new THREE.Mesh(new THREE.ConeGeometry(0.575, 3.64, 10, 1, true), dustMat);
  dustTail3.name = 'dustTail3';
  dustTail3.position.set(0.8013, 0, -1.7997);
  dustTail3.rotation.set(deg(-79.7355), deg(21.8126), deg(-25.9829));
  comet.add(dustTail3);
  const sparkle1 = new THREE.Mesh(new THREE.OctahedronGeometry(0.0145, 0), sparkleMat);
  sparkle1.name = 'sparkle1';
  sparkle1.position.set(0.8081, 0.1074, -4.8832);
  sparkle1.rotation.set(deg(6.4706), deg(25.1685), 0);
  comet.add(sparkle1);
  const sparkle2 = new THREE.Mesh(new THREE.OctahedronGeometry(0.0146, 0), sparkleMat);
  sparkle2.name = 'sparkle2';
  sparkle2.position.set(0.8817, 0.0261, -5.6084);
  sparkle2.rotation.set(deg(4.7463), deg(84.5044), 0);
  comet.add(sparkle2);
  const sparkle3 = new THREE.Mesh(new THREE.OctahedronGeometry(0.0434, 0), sparkleMat);
  sparkle3.name = 'sparkle3';
  sparkle3.position.set(0.5775, 0.1304, -1.1562);
  sparkle3.rotation.set(deg(52.1873), deg(48.1786), 0);
  comet.add(sparkle3);
  const sparkle4 = new THREE.Mesh(new THREE.OctahedronGeometry(0.0273, 0), sparkleMat);
  sparkle4.name = 'sparkle4';
  sparkle4.position.set(0.2987, 0.0234, -2.4222);
  sparkle4.rotation.set(deg(13.7574), deg(30.4144), 0);
  comet.add(sparkle4);
  const sparkle5 = new THREE.Mesh(new THREE.OctahedronGeometry(0.0162, 0), sparkleMat);
  sparkle5.name = 'sparkle5';
  sparkle5.position.set(1.0481, -0.0443, -4.9774);
  sparkle5.rotation.set(deg(39.7097), deg(26.4777), 0);
  comet.add(sparkle5);
  const sparkle6 = new THREE.Mesh(new THREE.OctahedronGeometry(0.022, 0), sparkleMat);
  sparkle6.name = 'sparkle6';
  sparkle6.position.set(0.1865, -0.0379, -5.2461);
  sparkle6.rotation.set(deg(24.8239), deg(71.4129), 0);
  comet.add(sparkle6);
  const sparkle7 = new THREE.Mesh(new THREE.OctahedronGeometry(0.0254, 0), sparkleMat);
  sparkle7.name = 'sparkle7';
  sparkle7.position.set(0.0387, 0.2468, -1.7486);
  sparkle7.rotation.set(deg(66.8711), deg(89.827), 0);
  comet.add(sparkle7);
  const sparkle8 = new THREE.Mesh(new THREE.OctahedronGeometry(0.0248, 0), sparkleMat);
  sparkle8.name = 'sparkle8';
  sparkle8.position.set(1.3581, 0.0319, -4.1748);
  sparkle8.rotation.set(deg(24.3689), deg(60.8498), 0);
  comet.add(sparkle8);
  const sparkle9 = new THREE.Mesh(new THREE.OctahedronGeometry(0.0334, 0), sparkleMat);
  sparkle9.name = 'sparkle9';
  sparkle9.position.set(0.5366, 0.1393, -1.8963);
  sparkle9.rotation.set(deg(51.9365), deg(67.3483), 0);
  comet.add(sparkle9);
  const sparkle10 = new THREE.Mesh(new THREE.OctahedronGeometry(0.0236, 0), sparkleMat);
  sparkle10.name = 'sparkle10';
  sparkle10.position.set(-0.1174, -0.0025, -3.4172);
  sparkle10.rotation.set(deg(29.6265), deg(65.7689), 0);
  comet.add(sparkle10);
  const sparkle11 = new THREE.Mesh(new THREE.OctahedronGeometry(0.0132, 0), sparkleMat);
  sparkle11.name = 'sparkle11';
  sparkle11.position.set(0.9331, -0.0245, -5.3372);
  sparkle11.rotation.set(deg(31.7683), deg(68.8992), 0);
  comet.add(sparkle11);
  const sparkle12 = new THREE.Mesh(new THREE.OctahedronGeometry(0.0438, 0), sparkleMat);
  sparkle12.name = 'sparkle12';
  sparkle12.position.set(0.17, 0.1538, -2.1857);
  sparkle12.rotation.set(deg(54.4662), deg(48.9422), 0);
  comet.add(sparkle12);

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

export default createComet;

评分与评论

—
暂无评分,快来抢先评分吧。
5
0
4
0
3
0
2
0
1
0

登录后即可评分和评论。

0 条评论

暂无评论。分享一下你是如何使用这个模型的,或者有哪些可以改进的地方。

相关模型

同一分类或相似标签