2352 三角面11.5 × 14.3 × 40.4 m
在代码中使用
在编辑器中改编blimp.js · 361 行
自包含的 ES 模块,仅依赖 three。调用工厂函数,然后把返回的 group 添加到场景中。
/**
* 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;
评分与评论
0 条评论
暂无评论。分享一下你是如何使用这个模型的,或者有哪些可以改进的地方。
相关模型
同一分类或相似标签









