528 Tris2,09 × 6,19 × 1,40 m
Im Code verwenden
Im Editor remixenflag-pole.js · 306 Zeilen
Eigenständiges ES-Modul — hängt nur von three ab. Ruf die Factory auf und füge die Gruppe deiner Szene hinzu.
/**
* Flag Pole — Codels 3D model library
* License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
* Triangles: 528 · Size (W × H × D): 2.09 × 6.19 × 1.40 m
*
* Usage:
* import { createFlagPole } from './flag-pole.js';
*
* const model = createFlagPole();
* model.position.set(0, 0, 0);
* scene.add(model);
*
* // Animations: idle
* const mixer = new THREE.AnimationMixer(model);
* mixer.clipAction(THREE.AnimationClip.findByName(model.animations, 'idle')).play();
* // in your render loop: mixer.update(clock.getDelta());
*/
import * as THREE from 'three';
const deg = THREE.MathUtils.degToRad;
// Build animation clips from simple descriptions (Codels). Play them with THREE.AnimationMixer.
function codelsClips(THREE, entries) {
var TAU = Math.PI * 2;
var DEG = Math.PI / 180;
var AX = { x: new THREE.Vector3(1, 0, 0), y: new THREE.Vector3(0, 1, 0), z: new THREE.Vector3(0, 0, 1) };
var periodOf = function (a) { return a.type === 'spin' ? 360 / Math.abs(a.speed) : a.period; };
var clips = [];
// loops → 'idle'
var loops = [];
entries.forEach(function (e) {
var l = e.anim.filter(function (a) { return a.type !== 'hinge'; });
if (l.length) loops.push({ target: e.target, anim: l });
});
if (loops.length) {
var periods = [];
loops.forEach(function (e) { e.anim.forEach(function (a) { periods.push(periodOf(a)); }); });
var longest = Math.max.apply(null, periods);
var D = longest;
var bestErr = Infinity;
for (var m = 1; m <= 6 && bestErr > 0.01; m++) {
var err = 0;
periods.forEach(function (p) {
var n = Math.max(1, Math.round((longest * m) / p));
err = Math.max(err, Math.abs((longest * m) / n - p) / p);
});
if (err < bestErr - 1e-9) { bestErr = err; D = longest * m; }
}
var cycles = function (a) { return Math.max(1, Math.round(D / periodOf(a))); };
var steps = 24;
loops.forEach(function (e) { e.anim.forEach(function (a) { steps = Math.max(steps, cycles(a) * 24); }); });
steps = Math.min(steps, 720);
var tracks = [];
loops.forEach(function (e) {
var o = e.target;
var q0 = o.quaternion.clone(), p0 = o.position.clone(), s0 = o.scale.clone();
var q = new THREE.Quaternion(), turn = new THREE.Quaternion(), p = new THREE.Vector3(), s = new THREE.Vector3();
var has = function (type) { return e.anim.some(function (a) { return a.type === type; }); };
var turns = has('spin') || has('swing'), moves = has('bob'), grows = has('pulse');
var times = [], qv = [], pv = [], sv = [];
for (var k = 0; k <= steps; k++) {
var t = (D * k) / steps;
q.copy(q0); p.copy(p0); s.copy(s0);
e.anim.forEach(function (a) {
var n = cycles(a);
var w = Math.sin(TAU * ((n * t) / D + (a.phase || 0)));
if (a.type === 'spin') q.multiply(turn.setFromAxisAngle(AX[a.axis], (a.speed < 0 ? -TAU : TAU) * ((n * t) / D)));
else if (a.type === 'swing') q.multiply(turn.setFromAxisAngle(AX[a.axis], a.angle * DEG * w));
else if (a.type === 'bob') p.addScaledVector(AX[a.axis], a.distance * w);
else if (a.type === 'pulse') s.multiplyScalar(1 + a.amount * w);
});
times.push(t);
if (turns) qv.push(q.x, q.y, q.z, q.w);
if (moves) pv.push(p.x, p.y, p.z);
if (grows) sv.push(s.x, s.y, s.z);
}
if (turns) tracks.push(new THREE.QuaternionKeyframeTrack(o.uuid + '.quaternion', times, qv));
if (moves) tracks.push(new THREE.VectorKeyframeTrack(o.uuid + '.position', times, pv));
if (grows) tracks.push(new THREE.VectorKeyframeTrack(o.uuid + '.scale', times, sv));
});
clips.push(new THREE.AnimationClip('idle', D, tracks));
}
// hinge moves → one-shot clips ('open' …)
var shots = {};
entries.forEach(function (e) {
e.anim.forEach(function (a) {
if (a.type !== 'hinge') return;
var name = a.clip || 'open';
(shots[name] = shots[name] || []).push({ target: e.target, a: a });
});
});
Object.keys(shots).forEach(function (name) {
var tracks = [];
var length = 0;
shots[name].forEach(function (h) {
var o = h.target, q0 = o.quaternion.clone(), q = new THREE.Quaternion(), turn = new THREE.Quaternion();
var n = Math.max(4, Math.ceil(Math.abs(h.a.angle) / 10));
var times = [], qv = [];
for (var k = 0; k <= n; k++) {
var f = k / n;
var eased = f * f * (3 - 2 * f);
q.copy(q0).multiply(turn.setFromAxisAngle(AX[h.a.axis], h.a.angle * DEG * eased));
times.push(h.a.duration * f);
qv.push(q.x, q.y, q.z, q.w);
}
length = Math.max(length, h.a.duration);
tracks.push(new THREE.QuaternionKeyframeTrack(o.uuid + '.quaternion', times, qv));
});
clips.push(new THREE.AnimationClip(name, length, tracks));
});
return clips;
}
export function createFlagPole() {
const root = new THREE.Group();
root.name = 'FlagPole';
// Materials
const poleMat = new THREE.MeshStandardMaterial({ name: 'pole', color: 0xc3c7cd, roughness: 0.35, metalness: 0.65, flatShading: true });
const goldMat = new THREE.MeshStandardMaterial({ name: 'gold', color: 0xd1a33f, roughness: 0.3, metalness: 0.75, flatShading: true });
const stoneMat = new THREE.MeshStandardMaterial({ name: 'stone', color: 0x9a958c, roughness: 0.92, flatShading: true });
const stoneDarkMat = new THREE.MeshStandardMaterial({ name: 'stoneDark', color: 0x7d786f, roughness: 0.95, flatShading: true });
const ropeMat = new THREE.MeshStandardMaterial({ name: 'rope', color: 0xebe5d4, roughness: 0.9, flatShading: true });
const flagMat = new THREE.MeshStandardMaterial({ name: 'flag', color: 0x2a5db0, roughness: 0.9, flatShading: true });
const accentMat = new THREE.MeshStandardMaterial({ name: 'accent', color: 0xf2f0e8, roughness: 0.9, flatShading: true });
// Parts
const baseStep = new THREE.Mesh(new THREE.BoxGeometry(1.4, 0.15, 1.4), stoneDarkMat);
baseStep.name = 'baseStep';
baseStep.position.set(0, 0.075, 0);
root.add(baseStep);
const basePlinth = new THREE.Mesh(new THREE.BoxGeometry(0.91, 0.17, 0.91), stoneMat);
basePlinth.name = 'basePlinth';
basePlinth.position.set(0, 0.235, 0);
root.add(basePlinth);
const collar = new THREE.Mesh(new THREE.CylinderGeometry(0.08, 0.1, 0.1, 8), poleMat);
collar.name = 'collar';
collar.position.set(0, 0.37, 0);
root.add(collar);
const pole = new THREE.Mesh(new THREE.CylinderGeometry(0.032, 0.055, 5.68, 8), poleMat);
pole.name = 'pole';
pole.position.set(0, 3.16, 0);
root.add(pole);
const truck = new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.05, 0.06, 8), poleMat);
truck.name = 'truck';
truck.position.set(0, 6.03, 0);
root.add(truck);
const finial = new THREE.Mesh(new THREE.SphereGeometry(0.065, 8, 6), goldMat);
finial.name = 'finial';
finial.position.set(0, 6.125, 0);
root.add(finial);
const cleat = new THREE.Mesh(new THREE.BoxGeometry(0.02, 0.12, 0.03), poleMat);
cleat.name = 'cleat';
cleat.position.set(0.059, 1.15, 0);
root.add(cleat);
const halyard = new THREE.Mesh(new THREE.CylinderGeometry(0.005, 0.005, 4.85, 4), ropeMat);
halyard.name = 'halyard';
halyard.position.set(0.057, 3.575, 0.012);
root.add(halyard);
const hoist = new THREE.Mesh(new THREE.BoxGeometry(0.04, 0.8448, 0.02), ropeMat);
hoist.name = 'hoist';
hoist.position.set(0.047, 5.4976, 0);
root.add(hoist);
const flagCloth = new THREE.Group();
flagCloth.name = 'flagCloth';
flagCloth.position.set(0.067, 0, 0);
root.add(flagCloth);
const flag = new THREE.Mesh(new THREE.BoxGeometry(0.1716, 0.323, 0.012), flagMat);
flag.name = 'flag';
flag.position.set(0.0825, 5.7595, 0.0069);
flag.rotation.set(0, deg(-4.81), 0);
flagCloth.add(flag);
const flagAccent = new THREE.Mesh(new THREE.BoxGeometry(0.1716, 0.2048, 0.012), accentMat);
flagAccent.name = 'flagAccent';
flagAccent.position.set(0.0825, 5.4976, 0.0069);
flagAccent.rotation.set(0, deg(-4.81), 0);
flagCloth.add(flagAccent);
const flag2 = new THREE.Mesh(new THREE.BoxGeometry(0.1716, 0.321, 0.012), flagMat);
flag2.name = 'flag';
flag2.position.set(0.0825, 5.2357, 0.0069);
flag2.rotation.set(0, deg(-4.81), 0);
flagCloth.add(flag2);
const flag3 = new THREE.Mesh(new THREE.BoxGeometry(0.1742, 0.323, 0.012), flagMat);
flag3.name = 'flag';
flag3.position.set(0.2475, 5.7595, 0.0301);
flag3.rotation.set(0, deg(-11.1206), 0);
flagCloth.add(flag3);
const flagAccent2 = new THREE.Mesh(new THREE.BoxGeometry(0.1742, 0.2048, 0.012), accentMat);
flagAccent2.name = 'flagAccent';
flagAccent2.position.set(0.2475, 5.4976, 0.0301);
flagAccent2.rotation.set(0, deg(-11.1206), 0);
flagCloth.add(flagAccent2);
const flag4 = new THREE.Mesh(new THREE.BoxGeometry(0.1742, 0.321, 0.012), flagMat);
flag4.name = 'flag';
flag4.position.set(0.2475, 5.2357, 0.0301);
flag4.rotation.set(0, deg(-11.1206), 0);
flagCloth.add(flag4);
const flagAccent3 = new THREE.Mesh(new THREE.BoxGeometry(0.171, 0.323, 0.012), accentMat);
flagAccent3.name = 'flagAccent';
flagAccent3.position.set(0.4125, 5.7595, 0.0452);
flagAccent3.rotation.set(0, deg(0.7991), 0);
flagCloth.add(flagAccent3);
const flagAccent4 = new THREE.Mesh(new THREE.BoxGeometry(0.171, 0.2048, 0.012), accentMat);
flagAccent4.name = 'flagAccent';
flagAccent4.position.set(0.4125, 5.4976, 0.0452);
flagAccent4.rotation.set(0, deg(0.7991), 0);
flagCloth.add(flagAccent4);
const flagAccent5 = new THREE.Mesh(new THREE.BoxGeometry(0.171, 0.321, 0.012), accentMat);
flagAccent5.name = 'flagAccent';
flagAccent5.position.set(0.4125, 5.2357, 0.0452);
flagAccent5.rotation.set(0, deg(0.7991), 0);
flagCloth.add(flagAccent5);
const flag5 = new THREE.Mesh(new THREE.BoxGeometry(0.1803, 0.323, 0.012), flagMat);
flag5.name = 'flag';
flag5.position.set(0.5775, 5.7595, 0.016);
flag5.rotation.set(0, deg(18.7738), 0);
flagCloth.add(flag5);
const flagAccent6 = new THREE.Mesh(new THREE.BoxGeometry(0.1803, 0.2048, 0.012), accentMat);
flagAccent6.name = 'flagAccent';
flagAccent6.position.set(0.5775, 5.4976, 0.016);
flagAccent6.rotation.set(0, deg(18.7738), 0);
flagCloth.add(flagAccent6);
const flag6 = new THREE.Mesh(new THREE.BoxGeometry(0.1803, 0.321, 0.012), flagMat);
flag6.name = 'flag';
flag6.position.set(0.5775, 5.2357, 0.016);
flag6.rotation.set(0, deg(18.7738), 0);
flagCloth.add(flag6);
const flag7 = new THREE.Mesh(new THREE.BoxGeometry(0.1851, 0.323, 0.012), flagMat);
flag7.name = 'flag';
flag7.position.set(0.7425, 5.7595, -0.0469);
flag7.rotation.set(0, deg(22.8983), 0);
flagCloth.add(flag7);
const flagAccent7 = new THREE.Mesh(new THREE.BoxGeometry(0.1851, 0.2048, 0.012), accentMat);
flagAccent7.name = 'flagAccent';
flagAccent7.position.set(0.7425, 5.4976, -0.0469);
flagAccent7.rotation.set(0, deg(22.8983), 0);
flagCloth.add(flagAccent7);
const flag8 = new THREE.Mesh(new THREE.BoxGeometry(0.1851, 0.321, 0.012), flagMat);
flag8.name = 'flag';
flag8.position.set(0.7425, 5.2357, -0.0469);
flag8.rotation.set(0, deg(22.8983), 0);
flagCloth.add(flag8);
const flag9 = new THREE.Mesh(new THREE.BoxGeometry(0.1717, 0.323, 0.012), flagMat);
flag9.name = 'flag';
flag9.position.set(0.9075, 5.7595, -0.0892);
flag9.rotation.set(0, deg(5.1474), 0);
flagCloth.add(flag9);
const flagAccent8 = new THREE.Mesh(new THREE.BoxGeometry(0.1717, 0.2048, 0.012), accentMat);
flagAccent8.name = 'flagAccent';
flagAccent8.position.set(0.9075, 5.4976, -0.0892);
flagAccent8.rotation.set(0, deg(5.1474), 0);
flagCloth.add(flagAccent8);
const flag10 = new THREE.Mesh(new THREE.BoxGeometry(0.1717, 0.321, 0.012), flagMat);
flag10.name = 'flag';
flag10.position.set(0.9075, 5.2357, -0.0892);
flag10.rotation.set(0, deg(5.1474), 0);
flagCloth.add(flag10);
const flag11 = new THREE.Mesh(new THREE.BoxGeometry(0.1857, 0.323, 0.012), flagMat);
flag11.name = 'flag';
flag11.position.set(1.0725, 5.7595, -0.0611);
flag11.rotation.set(0, deg(-23.3191), 0);
flagCloth.add(flag11);
const flagAccent9 = new THREE.Mesh(new THREE.BoxGeometry(0.1857, 0.2048, 0.012), accentMat);
flagAccent9.name = 'flagAccent';
flagAccent9.position.set(1.0725, 5.4976, -0.0611);
flagAccent9.rotation.set(0, deg(-23.3191), 0);
flagCloth.add(flagAccent9);
const flag12 = new THREE.Mesh(new THREE.BoxGeometry(0.1857, 0.321, 0.012), flagMat);
flag12.name = 'flag';
flag12.position.set(1.0725, 5.2357, -0.0611);
flag12.rotation.set(0, deg(-23.3191), 0);
flagCloth.add(flag12);
const flag13 = new THREE.Mesh(new THREE.BoxGeometry(0.2051, 0.323, 0.012), flagMat);
flag13.name = 'flag';
flag13.position.set(1.2375, 5.7595, 0.0302);
flag13.rotation.set(0, deg(-34.0308), 0);
flagCloth.add(flag13);
const flagAccent10 = new THREE.Mesh(new THREE.BoxGeometry(0.2051, 0.2048, 0.012), accentMat);
flagAccent10.name = 'flagAccent';
flagAccent10.position.set(1.2375, 5.4976, 0.0302);
flagAccent10.rotation.set(0, deg(-34.0308), 0);
flagCloth.add(flagAccent10);
const flag14 = new THREE.Mesh(new THREE.BoxGeometry(0.2051, 0.321, 0.012), flagMat);
flag14.name = 'flag';
flag14.position.set(1.2375, 5.2357, 0.0302);
flag14.rotation.set(0, deg(-34.0308), 0);
flagCloth.add(flag14);
// Animations ('idle') — play them with THREE.AnimationMixer
root.animations = codelsClips(THREE, [
{ target: flagCloth, anim: [{ type: 'swing', axis: 'y', angle: 12, period: 2.8 }] },
]);
root.traverse((o) => {
if (o.isMesh) {
o.castShadow = true;
o.receiveShadow = true;
}
});
return root;
}
export default createFlagPole;
Bewertungen & Kommentare
—
Noch keine Bewertungen — gib die erste ab.
5
0
4
0
3
0
2
0
1
0
Melde dich an, um zu bewerten und zu kommentieren.
0 Kommentare
Noch keine Kommentare. Erzähl, wie du dieses Modell genutzt hast oder was besser sein könnte.
Ähnliche Modelle
Gleiche Kategorie oder ähnliche Tags









