Codels
2,4 mil tris11,5 × 14,3 × 40,4 m
Módulo ES autocontido — depende apenas do three. Chame a factory e adicione o grupo à sua cena.
/**
 * Blimp Airship — Codels 3D model library
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 2,352 · Size (W × H × D): 11.50 × 14.33 × 40.40 m
 *
 * Usage:
 *   import { createBlimp } from './blimp.js';
 *   
 *   const model = createBlimp();
 *   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 createBlimp() {
  const root = new THREE.Group();
  root.name = 'Blimp';

  // Materials
  const envelopeMat = new THREE.MeshStandardMaterial({ name: 'envelope', color: 0xe4e1d8, roughness: 0.6, metalness: 0.08, flatShading: true });
  const stripeMat = new THREE.MeshStandardMaterial({ name: 'stripe', color: 0x2d5ea3, roughness: 0.55, flatShading: true });
  const cabinMat = new THREE.MeshStandardMaterial({ name: 'cabin', color: 0xf2f0ea, roughness: 0.45, metalness: 0.1, flatShading: true });
  const glassMat = new THREE.MeshStandardMaterial({ name: 'glass', color: 0x25313e, roughness: 0.2, metalness: 0.35 });
  const darkMat = new THREE.MeshStandardMaterial({ name: 'dark', color: 0x2e3238, roughness: 0.6, metalness: 0.3, flatShading: true });
  const metalMat = new THREE.MeshStandardMaterial({ name: 'metal', color: 0xa9afb7, roughness: 0.4, metalness: 0.6, flatShading: true });
  const beaconMat = new THREE.MeshStandardMaterial({ name: 'beacon', color: 0xff4a3a, roughness: 0.4, emissive: 0xff2a1a, emissiveIntensity: 1.3, flatShading: true });

  // Shared geometries
  const extrudeGeo = extrude([[-10, 3.2], [-15.2, 5.7], [-18.9, 5.7], [-19.15, 0.55]], 0.22, [], [0.04, 0.05, 1]);
  const extrudeGeo2 = extrude([[-17.5, 1.35], [-17.5, 5.72], [-18.92, 5.72], [-19.16, 0.62]], 0.3, [], [0.03, 0.03, 1]);
  const boxGeo = new THREE.BoxGeometry(1.9, 0.18, 0.4);
  const capsuleGeo = new THREE.CapsuleGeometry(0.38, 1.1, 3, 8);
  const cylinderGeo = new THREE.CylinderGeometry(0.12, 0.2, 0.3, 6);
  const torusGeo = new THREE.TorusGeometry(0.95, 0.13, 5, 16);
  const boxGeo2 = new THREE.BoxGeometry(1.9, 0.06, 0.06);
  const coneGeo = new THREE.ConeGeometry(0.16, 0.3, 6);
  const boxGeo3 = new THREE.BoxGeometry(0.16, 0.78, 0.035);

  // Parts
  const envelope = new THREE.Group();
  envelope.name = 'envelope';
  envelope.position.set(0, 8.6, 0);
  root.add(envelope);
  const hull = new THREE.Mesh(lathe([[0, -20], [0.3221, -19.6], [0.766, -18.8], [1.3905, -17.4], [2.0899, -15.5], [2.85, -13], [3.5876, -10], [4.2544, -6.5], [4.7404, -3], [5.0941, 1], [5.25, 6], [5.0833, 9.5], [4.6498, 12.5], [4.0214, 15], [3.15, 17.2]], 18, 0.1745, Math.PI * 2), envelopeMat);
  hull.name = 'hull';
  hull.rotation.set(deg(90), 0, 0);
  envelope.add(hull);
  const noseCap = new THREE.Mesh(lathe([[3.15, 17.2], [2.5075, 18.3], [1.8015, 19.15], [1.081, 19.7], [0, 20]], 18, 0.1745, Math.PI * 2), stripeMat);
  noseCap.name = 'noseCap';
  noseCap.rotation.set(deg(90), 0, 0);
  envelope.add(noseCap);
  const mooringCone = new THREE.Mesh(new THREE.CylinderGeometry(0.12, 0.2, 0.5, 6), darkMat);
  mooringCone.name = 'mooringCone';
  mooringCone.position.set(0, 0, 20.15);
  mooringCone.rotation.set(deg(90), 0, 0);
  envelope.add(mooringCone);
  const batten1 = new THREE.Mesh(tube([[1.7298, -2.9961, 16.6], [1.3354, -2.3129, 18.1], [0.8056, -1.3953, 19.35]], 0.07, 6, 4), darkMat);
  batten1.name = 'batten1';
  envelope.add(batten1);
  const batten2 = new THREE.Mesh(tube([[3.4596, 0, 16.6], [2.6708, 0, 18.1], [1.6111, 0, 19.35]], 0.07, 6, 4), darkMat);
  batten2.name = 'batten2';
  envelope.add(batten2);
  const batten3 = new THREE.Mesh(tube([[1.7298, 2.9961, 16.6], [1.3354, 2.3129, 18.1], [0.8056, 1.3953, 19.35]], 0.07, 6, 4), darkMat);
  batten3.name = 'batten3';
  envelope.add(batten3);
  const batten4 = new THREE.Mesh(tube([[-1.7298, 2.9961, 16.6], [-1.3354, 2.3129, 18.1], [-0.8056, 1.3953, 19.35]], 0.07, 6, 4), darkMat);
  batten4.name = 'batten4';
  envelope.add(batten4);
  const batten5 = new THREE.Mesh(tube([[-3.4596, 0, 16.6], [-2.6708, 0, 18.1], [-1.6111, 0, 19.35]], 0.07, 6, 4), darkMat);
  batten5.name = 'batten5';
  envelope.add(batten5);
  const batten6 = new THREE.Mesh(tube([[-1.7298, -2.9961, 16.6], [-1.3354, -2.3129, 18.1], [-0.8056, -1.3953, 19.35]], 0.07, 6, 4), darkMat);
  batten6.name = 'batten6';
  envelope.add(batten6);
  const bannerL = new THREE.Mesh(lathe([[2.9, -13], [3.8479, -9], [4.6689, -4], [5.1441, 1], [5.3, 6], [5.178, 9], [4.7934, 12]], 4, 1.2308, 0.68), stripeMat);
  bannerL.name = 'bannerL';
  bannerL.rotation.set(deg(90), 0, 0);
  envelope.add(bannerL);
  const pinstripeL = new THREE.Mesh(lathe([[2.9, -13], [3.8479, -9], [4.6689, -4], [5.1441, 1], [5.3, 6], [5.178, 9], [4.7934, 12]], 1, 1.0308, 0.08), stripeMat);
  pinstripeL.name = 'pinstripeL';
  pinstripeL.rotation.set(deg(90), 0, 0);
  envelope.add(pinstripeL);
  const bannerR = new THREE.Mesh(lathe([[2.9, -13], [3.8479, -9], [4.6689, -4], [5.1441, 1], [5.3, 6], [5.178, 9], [4.7934, 12]], 4, 4.3724, 0.68), stripeMat);
  bannerR.name = 'bannerR';
  bannerR.rotation.set(deg(90), 0, 0);
  envelope.add(bannerR);
  const pinstripeR = new THREE.Mesh(lathe([[2.9, -13], [3.8479, -9], [4.6689, -4], [5.1441, 1], [5.3, 6], [5.178, 9], [4.7934, 12]], 1, 5.1724, 0.08), stripeMat);
  pinstripeR.name = 'pinstripeR';
  pinstripeR.rotation.set(deg(90), 0, 0);
  envelope.add(pinstripeR);
  const topBeacon = new THREE.Mesh(new THREE.SphereGeometry(0.22, 6, 4), beaconMat);
  topBeacon.name = 'topBeacon';
  topBeacon.position.set(0, 5.2004, 2);
  envelope.add(topBeacon);
  const finTop = new THREE.Group();
  finTop.name = 'finTop';
  envelope.add(finTop);
  const fin = new THREE.Mesh(extrudeGeo, envelopeMat);
  fin.name = 'fin';
  fin.rotation.set(0, deg(-90), 0);
  finTop.add(fin);
  const rudder = new THREE.Mesh(extrudeGeo2, stripeMat);
  rudder.name = 'rudder';
  rudder.rotation.set(0, deg(-90), 0);
  finTop.add(rudder);
  const finLeft = new THREE.Group();
  finLeft.name = 'finLeft';
  finLeft.rotation.set(0, 0, deg(-90));
  envelope.add(finLeft);
  const fin2 = new THREE.Mesh(extrudeGeo, envelopeMat);
  fin2.name = 'fin';
  fin2.rotation.set(0, deg(-90), 0);
  finLeft.add(fin2);
  const rudder2 = new THREE.Mesh(extrudeGeo2, stripeMat);
  rudder2.name = 'rudder';
  rudder2.rotation.set(0, deg(-90), 0);
  finLeft.add(rudder2);
  const finBottom = new THREE.Group();
  finBottom.name = 'finBottom';
  finBottom.rotation.set(0, 0, deg(-180));
  envelope.add(finBottom);
  const fin3 = new THREE.Mesh(extrudeGeo, envelopeMat);
  fin3.name = 'fin';
  fin3.rotation.set(0, deg(-90), 0);
  finBottom.add(fin3);
  const rudder3 = new THREE.Mesh(extrudeGeo2, stripeMat);
  rudder3.name = 'rudder';
  rudder3.rotation.set(0, deg(-90), 0);
  finBottom.add(rudder3);
  const finRight = new THREE.Group();
  finRight.name = 'finRight';
  finRight.rotation.set(0, 0, deg(-270));
  envelope.add(finRight);
  const fin4 = new THREE.Mesh(extrudeGeo, envelopeMat);
  fin4.name = 'fin';
  fin4.rotation.set(0, deg(-90), 0);
  finRight.add(fin4);
  const rudder4 = new THREE.Mesh(extrudeGeo2, stripeMat);
  rudder4.name = 'rudder';
  rudder4.rotation.set(0, deg(-90), 0);
  finRight.add(rudder4);
  const gondola = new THREE.Group();
  gondola.name = 'gondola';
  gondola.position.set(0, 1.05, 2.2);
  root.add(gondola);
  const cabin = new THREE.Mesh(extrude([[-4.3, 0.55], [-3.7, 0.08], [2.9, 0], [3.9, 0.3], [4.55, 1.2], [4.35, 2.7], [-4.3, 2.7]], 2.2, [], [0.12, 0.12, 2]), cabinMat);
  cabin.name = 'cabin';
  cabin.rotation.set(0, deg(-90), 0);
  gondola.add(cabin);
  const windowBand = new THREE.Mesh(new THREE.BoxGeometry(2.5, 0.62, 6.6), glassMat);
  windowBand.name = 'windowBand';
  windowBand.position.set(0, 1.72, 0.2);
  gondola.add(windowBand);
  const windshield = new THREE.Mesh(new THREE.BoxGeometry(2, 0.95, 0.08), glassMat);
  windshield.name = 'windshield';
  windshield.position.set(0, 1.98, 4.43);
  windshield.rotation.set(deg(-8), 0, 0);
  gondola.add(windshield);
  const cabinStripe = new THREE.Mesh(new THREE.BoxGeometry(2.48, 0.22, 7.9), stripeMat);
  cabinStripe.name = 'cabinStripe';
  cabinStripe.position.set(0, 0.62, 0);
  gondola.add(cabinStripe);
  const door = new THREE.Mesh(new THREE.BoxGeometry(0.06, 1.5, 0.85), darkMat);
  door.name = 'door';
  door.position.set(1.18, 1.25, -2.6);
  gondola.add(door);
  const wheelStrut = new THREE.Mesh(new THREE.CylinderGeometry(0.07, 0.07, 0.75, 6), metalMat);
  wheelStrut.name = 'wheelStrut';
  wheelStrut.position.set(0, -0.375, -2);
  gondola.add(wheelStrut);
  const wheelFork = new THREE.Mesh(new THREE.BoxGeometry(0.36, 0.08, 0.5), metalMat);
  wheelFork.name = 'wheelFork';
  wheelFork.position.set(0, -0.39, -2);
  gondola.add(wheelFork);
  const landingWheel = new THREE.Group();
  landingWheel.name = 'landingWheel';
  landingWheel.position.set(0, -0.73, -2);
  gondola.add(landingWheel);
  const tire = new THREE.Mesh(new THREE.CylinderGeometry(0.32, 0.32, 0.22, 10), darkMat);
  tire.name = 'tire';
  tire.rotation.set(0, 0, deg(90));
  landingWheel.add(tire);
  const hub = new THREE.Mesh(new THREE.CylinderGeometry(0.14, 0.14, 0.24, 6), metalMat);
  hub.name = 'hub';
  hub.rotation.set(0, 0, deg(90));
  landingWheel.add(hub);
  const outriggerL = new THREE.Mesh(boxGeo, metalMat);
  outriggerL.name = 'outriggerL';
  outriggerL.position.set(1.95, 1.45, -2.9);
  gondola.add(outriggerL);
  const engineL = new THREE.Group();
  engineL.name = 'engineL';
  engineL.position.set(3.05, 1.45, -2.9);
  gondola.add(engineL);
  const nacelle = new THREE.Mesh(capsuleGeo, cabinMat);
  nacelle.name = 'nacelle';
  nacelle.position.set(0, 0, 0.1);
  nacelle.rotation.set(deg(90), 0, 0);
  engineL.add(nacelle);
  const shaft = new THREE.Mesh(cylinderGeo, darkMat);
  shaft.name = 'shaft';
  shaft.position.set(0, 0, -0.75);
  shaft.rotation.set(deg(90), 0, 0);
  engineL.add(shaft);
  const duct = new THREE.Mesh(torusGeo, stripeMat);
  duct.name = 'duct';
  duct.position.set(0, 0, -1.05);
  engineL.add(duct);
  const box44 = new THREE.Mesh(boxGeo2, darkMat);
  box44.position.set(0, 0, -1.2);
  engineL.add(box44);
  const box45 = new THREE.Mesh(boxGeo2, darkMat);
  box45.position.set(0, 0, -1.2);
  box45.rotation.set(0, 0, deg(90));
  engineL.add(box45);
  const propeller = new THREE.Group();
  propeller.name = 'propeller';
  propeller.position.set(0, 0, -0.98);
  engineL.add(propeller);
  const spinner = new THREE.Mesh(coneGeo, metalMat);
  spinner.name = 'spinner';
  spinner.position.set(0, 0, -0.1);
  spinner.rotation.set(deg(-90), 0, 0);
  propeller.add(spinner);
  const blade1 = new THREE.Group();
  blade1.name = 'blade1';
  blade1.rotation.set(0, 0, deg(45));
  propeller.add(blade1);
  const box49 = new THREE.Mesh(boxGeo3, darkMat);
  box49.position.set(0, 0.45, 0);
  box49.rotation.set(0, deg(20), 0);
  blade1.add(box49);
  const blade2 = new THREE.Group();
  blade2.name = 'blade2';
  blade2.rotation.set(0, 0, deg(135));
  propeller.add(blade2);
  const box51 = new THREE.Mesh(boxGeo3, darkMat);
  box51.position.set(0, 0.45, 0);
  box51.rotation.set(0, deg(20), 0);
  blade2.add(box51);
  const blade3 = new THREE.Group();
  blade3.name = 'blade3';
  blade3.rotation.set(0, 0, deg(225));
  propeller.add(blade3);
  const box53 = new THREE.Mesh(boxGeo3, darkMat);
  box53.position.set(0, 0.45, 0);
  box53.rotation.set(0, deg(20), 0);
  blade3.add(box53);
  const blade4 = new THREE.Group();
  blade4.name = 'blade4';
  blade4.rotation.set(0, 0, deg(315));
  propeller.add(blade4);
  const box55 = new THREE.Mesh(boxGeo3, darkMat);
  box55.position.set(0, 0.45, 0);
  box55.rotation.set(0, deg(20), 0);
  blade4.add(box55);
  const outriggerR = new THREE.Mesh(boxGeo, metalMat);
  outriggerR.name = 'outriggerR';
  outriggerR.position.set(-1.95, 1.45, -2.9);
  gondola.add(outriggerR);
  const engineR = new THREE.Group();
  engineR.name = 'engineR';
  engineR.position.set(-3.05, 1.45, -2.9);
  gondola.add(engineR);
  const nacelle2 = new THREE.Mesh(capsuleGeo, cabinMat);
  nacelle2.name = 'nacelle';
  nacelle2.position.set(0, 0, 0.1);
  nacelle2.rotation.set(deg(90), 0, 0);
  engineR.add(nacelle2);
  const shaft2 = new THREE.Mesh(cylinderGeo, darkMat);
  shaft2.name = 'shaft';
  shaft2.position.set(0, 0, -0.75);
  shaft2.rotation.set(deg(90), 0, 0);
  engineR.add(shaft2);
  const duct2 = new THREE.Mesh(torusGeo, stripeMat);
  duct2.name = 'duct';
  duct2.position.set(0, 0, -1.05);
  engineR.add(duct2);
  const box61 = new THREE.Mesh(boxGeo2, darkMat);
  box61.position.set(0, 0, -1.2);
  engineR.add(box61);
  const box62 = new THREE.Mesh(boxGeo2, darkMat);
  box62.position.set(0, 0, -1.2);
  box62.rotation.set(0, 0, deg(90));
  engineR.add(box62);
  const propeller2 = new THREE.Group();
  propeller2.name = 'propeller';
  propeller2.position.set(0, 0, -0.98);
  engineR.add(propeller2);
  const spinner2 = new THREE.Mesh(coneGeo, metalMat);
  spinner2.name = 'spinner';
  spinner2.position.set(0, 0, -0.1);
  spinner2.rotation.set(deg(-90), 0, 0);
  propeller2.add(spinner2);
  const blade12 = new THREE.Group();
  blade12.name = 'blade1';
  blade12.rotation.set(0, 0, deg(45));
  propeller2.add(blade12);
  const box66 = new THREE.Mesh(boxGeo3, darkMat);
  box66.position.set(0, 0.45, 0);
  box66.rotation.set(0, deg(20), 0);
  blade12.add(box66);
  const blade22 = new THREE.Group();
  blade22.name = 'blade2';
  blade22.rotation.set(0, 0, deg(135));
  propeller2.add(blade22);
  const box68 = new THREE.Mesh(boxGeo3, darkMat);
  box68.position.set(0, 0.45, 0);
  box68.rotation.set(0, deg(20), 0);
  blade22.add(box68);
  const blade32 = new THREE.Group();
  blade32.name = 'blade3';
  blade32.rotation.set(0, 0, deg(225));
  propeller2.add(blade32);
  const box70 = new THREE.Mesh(boxGeo3, darkMat);
  box70.position.set(0, 0.45, 0);
  box70.rotation.set(0, deg(20), 0);
  blade32.add(box70);
  const blade42 = new THREE.Group();
  blade42.name = 'blade4';
  blade42.rotation.set(0, 0, deg(315));
  propeller2.add(blade42);
  const box72 = new THREE.Mesh(boxGeo3, darkMat);
  box72.position.set(0, 0.45, 0);
  box72.rotation.set(0, deg(20), 0);
  blade42.add(box72);

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

export default createBlimp;

Avaliações e comentários

—
Nenhuma avaliação ainda — seja o primeiro.
5
0
4
0
3
0
2
0
1
0

Entre para avaliar e comentar.

0 comentário

Nenhum comentário ainda. Conte como você usou este modelo ou o que poderia melhorar.

Modelos relacionados

Mesma categoria ou tags parecidas