Codels
980 tris14,9 × 2,88 × 7,18 m
Módulo ES autocontido — depende apenas do three. Chame a factory e adicione o grupo à sua cena.
/**
 * Glider Sailplane — Codels 3D model library
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 980 · Size (W × H × D): 14.91 × 2.88 × 7.18 m
 *
 * Usage:
 *   import { createGlider } from './glider.js';
 *   
 *   const model = createGlider();
 *   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 createGlider() {
  const root = new THREE.Group();
  root.name = 'Glider';

  // Materials
  const paintMat = new THREE.MeshStandardMaterial({ name: 'paint', color: 0xf3f2ee, roughness: 0.4, metalness: 0.05, flatShading: true });
  const accentMat = new THREE.MeshStandardMaterial({ name: 'accent', color: 0xd8443a, roughness: 0.45, metalness: 0.05, 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: 0x2b2e33, roughness: 0.7, metalness: 0.2, flatShading: true });
  const metalMat = new THREE.MeshStandardMaterial({ name: 'metal', color: 0xa7adb5, roughness: 0.4, metalness: 0.6, flatShading: true });

  // Shared geometries
  const extrudeGeo = extrude([[0.08, 0], [-0.08, 0.42], [-0.2, 0.42], [-0.18, 0]], 0.03, [], [0.01, 0.01, 1]);
  const boxGeo = new THREE.BoxGeometry(1.1, 0.012, 0.07);
  const boxGeo2 = new THREE.BoxGeometry(2.625, 0.012, 0.025);

  // Parts
  const glider = new THREE.Group();
  glider.name = 'glider';
  glider.position.set(0, 0.0176, -0.1);
  glider.rotation.set(deg(-3.5228), deg(0.5605), deg(-9.029));
  root.add(glider);
  const airframe = new THREE.Group();
  airframe.name = 'airframe';
  airframe.position.set(0, 0, 0.1);
  glider.add(airframe);
  const fuselage = new THREE.Mesh(lathe([[0, -4.3], [0.08, -4.25], [0.11, -3.4], [0.14, -2.2], [0.2, -1.3], [0.31, -0.55], [0.36, 0.3], [0.36, 1], [0.33, 1.7], [0.26, 2.25], [0.15, 2.58]], 12), paintMat);
  fuselage.name = 'fuselage';
  fuselage.position.set(0, 0.62, 0);
  fuselage.rotation.set(deg(90), 0, 0);
  fuselage.scale.set(1, 1, 1.15);
  airframe.add(fuselage);
  const noseCap = new THREE.Mesh(lathe([[0.15, 2.58], [0.07, 2.72], [0, 2.75]], 12), accentMat);
  noseCap.name = 'noseCap';
  noseCap.position.set(0, 0.62, 0);
  noseCap.rotation.set(deg(90), 0, 0);
  noseCap.scale.set(1, 1, 1.15);
  airframe.add(noseCap);
  const towHook = new THREE.Mesh(new THREE.BoxGeometry(0.03, 0.03, 0.12), darkMat);
  towHook.name = 'towHook';
  towHook.position.set(0, 0.46, 2.62);
  airframe.add(towHook);
  const canopy = new THREE.Mesh(new THREE.SphereGeometry(0.3, 12, 5, 0, Math.PI * 2, 0, Math.PI / 2), glassMat);
  canopy.name = 'canopy';
  canopy.position.set(0, 0.8, 1.3);
  canopy.scale.set(1.06, 1.08, 3);
  airframe.add(canopy);
  const canopyFrame = new THREE.Mesh(new THREE.BoxGeometry(0.66, 0.05, 0.05), darkMat);
  canopyFrame.name = 'canopyFrame';
  canopyFrame.position.set(0, 0.98, 0.42);
  airframe.add(canopyFrame);
  const wingL = new THREE.Group();
  wingL.name = 'wingL';
  wingL.position.set(0, 0.92, 0);
  wingL.rotation.set(0, 0, deg(2.5));
  airframe.add(wingL);
  const wingPanel = new THREE.Mesh(extrude([[0, 0.36], [3.375, 0.3], [7.2, 0.13], [7.5, 0.07], [7.5, -0.17], [7.2, -0.2], [3.375, -0.38], [0, -0.6]], 0.07, [], [0.02, 0.02, 1]), paintMat);
  wingPanel.name = 'wingPanel';
  wingPanel.rotation.set(deg(90), 0, 0);
  wingL.add(wingPanel);
  const wingTip = new THREE.Mesh(extrude([[6.6, 0.1567], [7.2, 0.13], [7.5, 0.07], [7.5, -0.17], [7.2, -0.2], [6.6, -0.2282]], 0.09, [], [0.02, 0.02, 1]), accentMat);
  wingTip.name = 'wingTip';
  wingTip.rotation.set(deg(90), 0, 0);
  wingL.add(wingTip);
  const winglet = new THREE.Mesh(extrudeGeo, accentMat);
  winglet.name = 'winglet';
  winglet.position.set(7.51, 0.03, 0);
  winglet.rotation.set(0, deg(-90), 0);
  wingL.add(winglet);
  const airbrake = new THREE.Mesh(boxGeo, darkMat);
  airbrake.name = 'airbrake';
  airbrake.position.set(2.65, 0.062, -0.08);
  wingL.add(airbrake);
  const aileronLine = new THREE.Mesh(boxGeo2, darkMat);
  aileronLine.name = 'aileronLine';
  aileronLine.position.set(5.4, 0.062, -0.22);
  wingL.add(aileronLine);
  const wingR = new THREE.Group();
  wingR.name = 'wingR';
  wingR.position.set(0, 0.92, 0);
  wingR.rotation.set(0, 0, deg(-2.5));
  airframe.add(wingR);
  const wingPanel2 = new THREE.Mesh(extrude([[0, 0.36], [-3.375, 0.3], [-7.2, 0.13], [-7.5, 0.07], [-7.5, -0.17], [-7.2, -0.2], [-3.375, -0.38], [0, -0.6]], 0.07, [], [0.02, 0.02, 1]), paintMat);
  wingPanel2.name = 'wingPanel';
  wingPanel2.rotation.set(deg(90), 0, 0);
  wingR.add(wingPanel2);
  const wingTip2 = new THREE.Mesh(extrude([[-6.6, 0.1567], [-7.2, 0.13], [-7.5, 0.07], [-7.5, -0.17], [-7.2, -0.2], [-6.6, -0.2282]], 0.09, [], [0.02, 0.02, 1]), accentMat);
  wingTip2.name = 'wingTip';
  wingTip2.rotation.set(deg(90), 0, 0);
  wingR.add(wingTip2);
  const winglet2 = new THREE.Mesh(extrudeGeo, accentMat);
  winglet2.name = 'winglet';
  winglet2.position.set(-7.51, 0.03, 0);
  winglet2.rotation.set(0, deg(-90), 0);
  wingR.add(winglet2);
  const airbrake2 = new THREE.Mesh(boxGeo, darkMat);
  airbrake2.name = 'airbrake';
  airbrake2.position.set(-2.65, 0.062, -0.08);
  wingR.add(airbrake2);
  const aileronLine2 = new THREE.Mesh(boxGeo2, darkMat);
  aileronLine2.name = 'aileronLine';
  aileronLine2.position.set(-5.4, 0.062, -0.22);
  wingR.add(aileronLine2);
  const fin = new THREE.Mesh(extrude([[-3.2, 0.05], [-3.85, 1.2], [-4.12, 1.22], [-4.06, -0.05]], 0.06, [], [0.015, 0.015, 1]), paintMat);
  fin.name = 'fin';
  fin.position.set(0, 0.62, 0);
  fin.rotation.set(0, deg(-90), 0);
  airframe.add(fin);
  const rudder = new THREE.Group();
  rudder.name = 'rudder';
  rudder.position.set(0, 0.62, -4.08);
  airframe.add(rudder);
  const rudderPanel = new THREE.Mesh(extrude([[0, 0.02], [0, 1.2], [-0.28, 1.2], [-0.36, -0.08]], 0.075, [], [0.01, 0.01, 1]), accentMat);
  rudderPanel.name = 'rudderPanel';
  rudderPanel.rotation.set(0, deg(-90), 0);
  rudder.add(rudderPanel);
  const stabilizer = new THREE.Mesh(extrude([[-1.45, -4.18], [-1.38, -3.92], [0, -3.7], [1.38, -3.92], [1.45, -4.18], [0, -4.3]], 0.04, [], [0.012, 0.012, 1]), paintMat);
  stabilizer.name = 'stabilizer';
  stabilizer.position.set(0, 1.84, 0);
  stabilizer.rotation.set(deg(90), 0, 0);
  airframe.add(stabilizer);
  const pitot = new THREE.Mesh(new THREE.BoxGeometry(0.03, 0.03, 0.3), metalMat);
  pitot.name = 'pitot';
  pitot.position.set(0, 1.62, -3.6);
  airframe.add(pitot);
  const wheelWell = new THREE.Mesh(new THREE.BoxGeometry(0.16, 0.08, 0.5), darkMat);
  wheelWell.name = 'wheelWell';
  wheelWell.position.set(0, 0.27, -0.1);
  airframe.add(wheelWell);
  const mainWheel = new THREE.Group();
  mainWheel.name = 'mainWheel';
  mainWheel.position.set(0, 0.19, -0.1);
  airframe.add(mainWheel);
  const tire = new THREE.Mesh(new THREE.CylinderGeometry(0.19, 0.19, 0.11, 12), darkMat);
  tire.name = 'tire';
  tire.rotation.set(0, 0, deg(90));
  mainWheel.add(tire);
  const hub = new THREE.Mesh(new THREE.CylinderGeometry(0.08, 0.08, 0.12, 8), metalMat);
  hub.name = 'hub';
  hub.rotation.set(0, 0, deg(90));
  mainWheel.add(hub);
  const tailWheelStrut = new THREE.Mesh(new THREE.BoxGeometry(0.05, 0.2, 0.08), metalMat);
  tailWheelStrut.name = 'tailWheelStrut';
  tailWheelStrut.position.set(0, 0.42, -3.95);
  airframe.add(tailWheelStrut);
  const tailWheel = new THREE.Group();
  tailWheel.name = 'tailWheel';
  tailWheel.position.set(0, 0.32, -3.95);
  airframe.add(tailWheel);
  const tire2 = new THREE.Mesh(new THREE.CylinderGeometry(0.08, 0.08, 0.05, 8), darkMat);
  tire2.name = 'tire';
  tire2.rotation.set(0, 0, deg(90));
  tailWheel.add(tire2);

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

export default createGlider;

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