Codels
1,2 mil tris9,38 × 2,94 × 12,4 m

Úsalo en código

Hacer remix en el editor
Módulo ES autónomo — solo depende de three. Llama a la función factory y añade el grupo a tu escena.
/**
 * Starfighter — Codels 3D model library
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 1,196 · Size (W × H × D): 9.38 × 2.94 × 12.42 m
 *
 * Usage:
 *   import { createStarfighter } from './starfighter.js';
 *   
 *   const model = createStarfighter();
 *   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);
}

export function createStarfighter() {
  const root = new THREE.Group();
  root.name = 'Starfighter';

  // Materials
  const hullMat = new THREE.MeshStandardMaterial({ name: 'hull', color: 0xd5dbe2, roughness: 0.4, metalness: 0.35, flatShading: true });
  const accentMat = new THREE.MeshStandardMaterial({ name: 'accent', color: 0xe8742f, roughness: 0.45, metalness: 0.2, flatShading: true });
  const glassMat = new THREE.MeshStandardMaterial({ name: 'glass', color: 0x1f2c3a, roughness: 0.15, metalness: 0.35 });
  const darkMat = new THREE.MeshStandardMaterial({ name: 'dark', color: 0x3a3f48, roughness: 0.55, metalness: 0.5, flatShading: true });
  const glowMat = new THREE.MeshStandardMaterial({ name: 'glow', color: 0x46c9ff, roughness: 0.4, emissive: 0x46c9ff, emissiveIntensity: 1.6, flatShading: true });

  // Shared geometries
  const boxGeo = new THREE.BoxGeometry(0.04, 0.22, 1.3);
  const boxGeo2 = new THREE.BoxGeometry(2.2, 0.02, 0.2);
  const cylinderGeo = new THREE.CylinderGeometry(0.09, 0.09, 2.6, 6);
  const cylinderGeo2 = new THREE.CylinderGeometry(0.045, 0.045, 0.7, 6);
  const sphereGeo = new THREE.SphereGeometry(0.07, 6, 4);
  const cylinderGeo3 = new THREE.CylinderGeometry(0.52, 0.6, 3.6, 10);
  const cylinderGeo4 = new THREE.CylinderGeometry(0.65, 0.65, 0.28, 10);
  const cylinderGeo5 = new THREE.CylinderGeometry(0.46, 0.46, 0.02, 10);
  const cylinderGeo6 = new THREE.CylinderGeometry(0.62, 0.62, 0.25, 10);
  const cylinderGeo7 = new THREE.CylinderGeometry(0.44, 0.44, 0.04, 10);
  const coneGeo = new THREE.ConeGeometry(0.4, 1.1, 10);
  const extrudeGeo = extrude([[-3, 0], [-4.9, 0], [-5.25, 1.35], [-4.55, 1.35]], 0.08, [], [0.03, 0.03, 1]);
  const extrudeGeo2 = extrude([[-4.9, 1.1], [-5.19, 1.1], [-5.25, 1.35], [-4.55, 1.35], [-4.62, 1.1]], 0.1);
  const cylinderGeo8 = new THREE.CylinderGeometry(0.24, 0.3, 0.12, 8);
  const cylinderGeo9 = new THREE.CylinderGeometry(0.07, 0.07, 0.6, 6);

  // Parts
  const ship = new THREE.Group();
  ship.name = 'ship';
  root.add(ship);
  const fuselage = new THREE.Mesh(lathe([[0, -4.9], [0.82, -4.9], [1.05, -3.5], [1.1, -1], [0.95, 1.5], [0.6, 3.6], [0.24, 5.4], [0, 6.1]], 6), hullMat);
  fuselage.name = 'fuselage';
  fuselage.position.set(0, 1.3, 0);
  fuselage.rotation.set(deg(90), 0, 0);
  fuselage.scale.set(1, 1, 0.6);
  ship.add(fuselage);
  const noseTip = new THREE.Mesh(lathe([[0.27, 5.25], [0.13, 5.75], [0, 6.12]], 6), accentMat);
  noseTip.name = 'noseTip';
  noseTip.position.set(0, 1.3, 0);
  noseTip.rotation.set(deg(90), 0, 0);
  noseTip.scale.set(1.04, 1, 0.624);
  ship.add(noseTip);
  const cockpit = new THREE.Mesh(new THREE.SphereGeometry(0.55, 12, 5, 0, Math.PI * 2, 0, Math.PI / 2), glassMat);
  cockpit.name = 'cockpit';
  cockpit.position.set(0, 1.6, 1.75);
  cockpit.scale.set(0.82, 0.95, 2.5);
  ship.add(cockpit);
  const canopyFrame = new THREE.Mesh(new THREE.BoxGeometry(0.12, 0.08, 1.2), darkMat);
  canopyFrame.name = 'canopyFrame';
  canopyFrame.position.set(0, 2.1, 1.3);
  ship.add(canopyFrame);
  const intakeL = new THREE.Mesh(boxGeo, darkMat);
  intakeL.name = 'intakeL';
  intakeL.position.set(0.85, 1.3, 0.2);
  ship.add(intakeL);
  const intakeR = new THREE.Mesh(boxGeo, darkMat);
  intakeR.name = 'intakeR';
  intakeR.position.set(-0.85, 1.3, 0.2);
  ship.add(intakeR);
  const wingL = new THREE.Group();
  wingL.name = 'wingL';
  wingL.position.set(0, 1.18, 0);
  wingL.rotation.set(0, 0, deg(-5));
  ship.add(wingL);
  const extrude9 = new THREE.Mesh(extrude([[0.3, 1.1], [4.5, -2.15], [4.65, -3.35], [0.3, -3.8]], 0.1, [], [0.04, 0.05, 1]), hullMat);
  extrude9.rotation.set(deg(90), 0, 0);
  wingL.add(extrude9);
  const box10 = new THREE.Mesh(boxGeo2, accentMat);
  box10.position.set(2.4, 0.095, -2.2);
  box10.rotation.set(0, deg(37), 0);
  wingL.add(box10);
  const cannonL = new THREE.Mesh(cylinderGeo, darkMat);
  cannonL.name = 'cannonL';
  cannonL.position.set(4.62, 0, -1.9);
  cannonL.rotation.set(deg(90), 0, 0);
  wingL.add(cannonL);
  const barrelL = new THREE.Mesh(cylinderGeo2, accentMat);
  barrelL.name = 'barrelL';
  barrelL.position.set(4.62, 0, -0.3);
  barrelL.rotation.set(deg(90), 0, 0);
  wingL.add(barrelL);
  const tipLightL = new THREE.Mesh(sphereGeo, glowMat);
  tipLightL.name = 'tipLightL';
  tipLightL.position.set(4.62, 0, -3.25);
  wingL.add(tipLightL);
  const wingR = new THREE.Group();
  wingR.name = 'wingR';
  wingR.position.set(0, 1.18, 0);
  wingR.rotation.set(0, 0, deg(5));
  ship.add(wingR);
  const extrude15 = new THREE.Mesh(extrude([[-0.3, 1.1], [-4.5, -2.15], [-4.65, -3.35], [-0.3, -3.8]], 0.1, [], [0.04, 0.05, 1]), hullMat);
  extrude15.rotation.set(deg(90), 0, 0);
  wingR.add(extrude15);
  const box16 = new THREE.Mesh(boxGeo2, accentMat);
  box16.position.set(-2.4, 0.095, -2.2);
  box16.rotation.set(0, deg(-37), 0);
  wingR.add(box16);
  const cannonR = new THREE.Mesh(cylinderGeo, darkMat);
  cannonR.name = 'cannonR';
  cannonR.position.set(-4.62, 0, -1.9);
  cannonR.rotation.set(deg(90), 0, 0);
  wingR.add(cannonR);
  const barrelR = new THREE.Mesh(cylinderGeo2, accentMat);
  barrelR.name = 'barrelR';
  barrelR.position.set(-4.62, 0, -0.3);
  barrelR.rotation.set(deg(90), 0, 0);
  wingR.add(barrelR);
  const tipLightR = new THREE.Mesh(sphereGeo, glowMat);
  tipLightR.name = 'tipLightR';
  tipLightR.position.set(-4.62, 0, -3.25);
  wingR.add(tipLightR);
  const engineL = new THREE.Group();
  engineL.name = 'engineL';
  engineL.position.set(1.22, 1.25, 0);
  ship.add(engineL);
  const nacelle = new THREE.Mesh(cylinderGeo3, hullMat);
  nacelle.name = 'nacelle';
  nacelle.position.set(0, 0, -3.3);
  nacelle.rotation.set(deg(-90), 0, 0);
  engineL.add(nacelle);
  const intakeRing = new THREE.Mesh(cylinderGeo4, accentMat);
  intakeRing.name = 'intakeRing';
  intakeRing.position.set(0, 0, -1.62);
  intakeRing.rotation.set(deg(90), 0, 0);
  engineL.add(intakeRing);
  const intake = new THREE.Mesh(cylinderGeo5, darkMat);
  intake.name = 'intake';
  intake.position.set(0, 0, -1.475);
  intake.rotation.set(deg(90), 0, 0);
  engineL.add(intake);
  const nozzle = new THREE.Mesh(cylinderGeo6, darkMat);
  nozzle.name = 'nozzle';
  nozzle.position.set(0, 0, -5.05);
  nozzle.rotation.set(deg(90), 0, 0);
  engineL.add(nozzle);
  const exhaustGlow = new THREE.Mesh(cylinderGeo7, glowMat);
  exhaustGlow.name = 'exhaustGlow';
  exhaustGlow.position.set(0, 0, -5.19);
  exhaustGlow.rotation.set(deg(90), 0, 0);
  engineL.add(exhaustGlow);
  const exhaustPlume = new THREE.Mesh(coneGeo, glowMat);
  exhaustPlume.name = 'exhaustPlume';
  exhaustPlume.position.set(0, 0, -5.75);
  exhaustPlume.rotation.set(deg(-90), 0, 0);
  engineL.add(exhaustPlume);
  const tailFin = new THREE.Group();
  tailFin.name = 'tailFin';
  tailFin.position.set(0, 0.4, 0);
  tailFin.rotation.set(0, 0, deg(-22));
  engineL.add(tailFin);
  const extrude28 = new THREE.Mesh(extrudeGeo, hullMat);
  extrude28.rotation.set(0, deg(-90), 0);
  tailFin.add(extrude28);
  const extrude29 = new THREE.Mesh(extrudeGeo2, accentMat);
  extrude29.rotation.set(0, deg(-90), 0);
  tailFin.add(extrude29);
  const engineR = new THREE.Group();
  engineR.name = 'engineR';
  engineR.position.set(-1.22, 1.25, 0);
  ship.add(engineR);
  const nacelle2 = new THREE.Mesh(cylinderGeo3, hullMat);
  nacelle2.name = 'nacelle';
  nacelle2.position.set(0, 0, -3.3);
  nacelle2.rotation.set(deg(-90), 0, 0);
  engineR.add(nacelle2);
  const intakeRing2 = new THREE.Mesh(cylinderGeo4, accentMat);
  intakeRing2.name = 'intakeRing';
  intakeRing2.position.set(0, 0, -1.62);
  intakeRing2.rotation.set(deg(90), 0, 0);
  engineR.add(intakeRing2);
  const intake2 = new THREE.Mesh(cylinderGeo5, darkMat);
  intake2.name = 'intake';
  intake2.position.set(0, 0, -1.475);
  intake2.rotation.set(deg(90), 0, 0);
  engineR.add(intake2);
  const nozzle2 = new THREE.Mesh(cylinderGeo6, darkMat);
  nozzle2.name = 'nozzle';
  nozzle2.position.set(0, 0, -5.05);
  nozzle2.rotation.set(deg(90), 0, 0);
  engineR.add(nozzle2);
  const exhaustGlow2 = new THREE.Mesh(cylinderGeo7, glowMat);
  exhaustGlow2.name = 'exhaustGlow';
  exhaustGlow2.position.set(0, 0, -5.19);
  exhaustGlow2.rotation.set(deg(90), 0, 0);
  engineR.add(exhaustGlow2);
  const exhaustPlume2 = new THREE.Mesh(coneGeo, glowMat);
  exhaustPlume2.name = 'exhaustPlume';
  exhaustPlume2.position.set(0, 0, -5.75);
  exhaustPlume2.rotation.set(deg(-90), 0, 0);
  engineR.add(exhaustPlume2);
  const tailFin2 = new THREE.Group();
  tailFin2.name = 'tailFin';
  tailFin2.position.set(0, 0.4, 0);
  tailFin2.rotation.set(0, 0, deg(22));
  engineR.add(tailFin2);
  const extrude38 = new THREE.Mesh(extrudeGeo, hullMat);
  extrude38.rotation.set(0, deg(-90), 0);
  tailFin2.add(extrude38);
  const extrude39 = new THREE.Mesh(extrudeGeo2, accentMat);
  extrude39.rotation.set(0, deg(-90), 0);
  tailFin2.add(extrude39);
  const noseGearStrut = new THREE.Mesh(new THREE.CylinderGeometry(0.07, 0.07, 0.8, 6), darkMat);
  noseGearStrut.name = 'noseGearStrut';
  noseGearStrut.position.set(0, 0.5, 3);
  ship.add(noseGearStrut);
  const noseGearPad = new THREE.Mesh(cylinderGeo8, darkMat);
  noseGearPad.name = 'noseGearPad';
  noseGearPad.position.set(0, 0.06, 3);
  ship.add(noseGearPad);
  const mainGearLStrut = new THREE.Mesh(cylinderGeo9, darkMat);
  mainGearLStrut.name = 'mainGearLStrut';
  mainGearLStrut.position.set(1.22, 0.4, -3);
  ship.add(mainGearLStrut);
  const mainGearLPad = new THREE.Mesh(cylinderGeo8, darkMat);
  mainGearLPad.name = 'mainGearLPad';
  mainGearLPad.position.set(1.22, 0.06, -3);
  ship.add(mainGearLPad);
  const mainGearRStrut = new THREE.Mesh(cylinderGeo9, darkMat);
  mainGearRStrut.name = 'mainGearRStrut';
  mainGearRStrut.position.set(-1.22, 0.4, -3);
  ship.add(mainGearRStrut);
  const mainGearRPad = new THREE.Mesh(cylinderGeo8, darkMat);
  mainGearRPad.name = 'mainGearRPad';
  mainGearRPad.position.set(-1.22, 0.06, -3);
  ship.add(mainGearRPad);

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

export default createStarfighter;

Valoraciones y comentarios

—
Aún no hay valoraciones — sé el primero.
5
0
4
0
3
0
2
0
1
0

Inicia sesión para valorar y comentar.

0 comentarios

Aún no hay comentarios. Cuenta cómo usaste este modelo o qué se podría mejorar.

Modelos relacionados

Misma categoría o etiquetas similares