2,5 mil tris2,02 × 2,00 × 2,01 m
Úsalo en código
Hacer remix en el editormoon.js · 344 líneas
Módulo ES autónomo — solo depende de three. Llama a la función factory y añade el grupo a tu escena.
/**
* Moon — Codels 3D model library
* License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the model (it floats — pickups, planets)
* Triangles: 2,508 · Size (W × H × D): 2.02 × 2.00 × 2.00 m
*
* Usage:
* import { createMoon } from './moon.js';
*
* const model = createMoon();
* 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 createMoon() {
const root = new THREE.Group();
root.name = 'Moon';
// Materials
const surfaceMat = new THREE.MeshStandardMaterial({ name: 'surface', color: 0xa7a49d, roughness: 0.95, flatShading: true });
const seaMat = new THREE.MeshStandardMaterial({ name: 'sea', color: 0x6e6d6e, roughness: 0.95, flatShading: true });
const floorMat = new THREE.MeshStandardMaterial({ name: 'floor', color: 0x787775, roughness: 0.95, flatShading: true });
const rimMat = new THREE.MeshStandardMaterial({ name: 'rim', color: 0xb7b4af, roughness: 0.9, flatShading: true });
// Parts
const moon = new THREE.Group();
moon.name = 'moon';
moon.scale.setScalar(2);
root.add(moon);
const surface = new THREE.Mesh(new THREE.SphereGeometry(0.5, 22, 16), surfaceMat);
surface.name = 'surface';
moon.add(surface);
const sea1 = new THREE.Mesh(new THREE.SphereGeometry(0.5035, 16, 4, 0, Math.PI * 2, 0, 0.4183), seaMat);
sea1.name = 'sea1';
sea1.rotation.set(deg(51.572), 0, deg(17.4818));
moon.add(sea1);
const sea2 = new THREE.Mesh(new THREE.SphereGeometry(0.5045, 16, 4, 0, Math.PI * 2, 0, 0.3732), seaMat);
sea2.name = 'sea2';
sea2.rotation.set(deg(-38.1833), 0, deg(-33.5104));
moon.add(sea2);
const sea3 = new THREE.Mesh(new THREE.SphereGeometry(0.5055, 16, 4, 0, Math.PI * 2, 0, 0.4264), seaMat);
sea3.name = 'sea3';
sea3.rotation.set(deg(70.5942), 0, deg(-24.8337));
moon.add(sea3);
const craterFloor1 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.2072), floorMat);
craterFloor1.name = 'craterFloor1';
craterFloor1.rotation.set(deg(-1.9855), 0, deg(-26.7075));
moon.add(craterFloor1);
const craterRim1 = new THREE.Group();
craterRim1.name = 'craterRim1';
craterRim1.position.set(0.2208, 0.4386, -0.0152);
craterRim1.rotation.set(deg(-1.9855), 0, deg(-26.7075));
moon.add(craterRim1);
const torus8 = new THREE.Mesh(new THREE.TorusGeometry(0.1029, 0.0249, 3, 12), rimMat);
torus8.rotation.set(deg(90), 0, 0);
torus8.scale.set(1, 1, 0.6);
craterRim1.add(torus8);
const craterFloor2 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.2196), floorMat);
craterFloor2.name = 'craterFloor2';
craterFloor2.rotation.set(deg(132.2205), 0, deg(5.0209));
moon.add(craterFloor2);
const craterRim2 = new THREE.Group();
craterRim2.name = 'craterRim2';
craterRim2.position.set(-0.0429, -0.328, 0.3615);
craterRim2.rotation.set(deg(132.2205), 0, deg(5.0209));
moon.add(craterRim2);
const torus11 = new THREE.Mesh(new THREE.TorusGeometry(0.1089, 0.0263, 3, 12), rimMat);
torus11.rotation.set(deg(90), 0, 0);
torus11.scale.set(1, 1, 0.6);
craterRim2.add(torus11);
const craterFloor3 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.1276), floorMat);
craterFloor3.name = 'craterFloor3';
craterFloor3.rotation.set(deg(-32.0851), 0, deg(44.4602));
moon.add(craterFloor3);
const craterRim3 = new THREE.Group();
craterRim3.name = 'craterRim3';
craterRim3.position.set(-0.3488, 0.3011, -0.1888);
craterRim3.rotation.set(deg(-32.0851), 0, deg(44.4602));
moon.add(craterRim3);
const torus14 = new THREE.Mesh(new THREE.TorusGeometry(0.0636, 0.0153, 3, 12), rimMat);
torus14.rotation.set(deg(90), 0, 0);
torus14.scale.set(1, 1, 0.6);
craterRim3.add(torus14);
const craterFloor4 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.0836), floorMat);
craterFloor4.name = 'craterFloor4';
craterFloor4.rotation.set(deg(-114.26), 0, deg(44.481));
moon.add(craterFloor4);
const craterRim4 = new THREE.Group();
craterRim4.name = 'craterRim4';
craterRim4.position.set(-0.3505, -0.1467, -0.3254);
craterRim4.rotation.set(deg(-114.26), 0, deg(44.481));
moon.add(craterRim4);
const torus17 = new THREE.Mesh(new THREE.TorusGeometry(0.0417, 0.01, 3, 12), rimMat);
torus17.rotation.set(deg(90), 0, 0);
torus17.scale.set(1, 1, 0.6);
craterRim4.add(torus17);
const craterFloor5 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.1327), floorMat);
craterFloor5.name = 'craterFloor5';
craterFloor5.rotation.set(deg(167.4273), 0, deg(-55.9671));
moon.add(craterFloor5);
const craterRim5 = new THREE.Group();
craterRim5.name = 'craterRim5';
craterRim5.position.set(0.4124, -0.2718, 0.0606);
craterRim5.rotation.set(deg(167.4273), 0, deg(-55.9671));
moon.add(craterRim5);
const torus20 = new THREE.Mesh(new THREE.TorusGeometry(0.0661, 0.0159, 3, 12), rimMat);
torus20.rotation.set(deg(90), 0, 0);
torus20.scale.set(1, 1, 0.6);
craterRim5.add(torus20);
const craterFloor6 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.0787), floorMat);
craterFloor6.name = 'craterFloor6';
craterFloor6.rotation.set(deg(153.2506), 0, deg(-11.8131));
moon.add(craterFloor6);
const craterRim6 = new THREE.Group();
craterRim6.name = 'craterRim6';
craterRim6.position.set(0.1025, -0.4374, 0.2205);
craterRim6.rotation.set(deg(153.2506), 0, deg(-11.8131));
moon.add(craterRim6);
const torus23 = new THREE.Mesh(new THREE.TorusGeometry(0.0393, 0.0094, 3, 12), rimMat);
torus23.rotation.set(deg(90), 0, 0);
torus23.scale.set(1, 1, 0.6);
craterRim6.add(torus23);
const craterFloor7 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.1062), floorMat);
craterFloor7.name = 'craterFloor7';
craterFloor7.rotation.set(deg(-41.1398), 0, deg(19.1448));
moon.add(craterFloor7);
const craterRim7 = new THREE.Group();
craterRim7.name = 'craterRim7';
craterRim7.position.set(-0.1637, 0.3551, -0.3102);
craterRim7.rotation.set(deg(-41.1398), 0, deg(19.1448));
moon.add(craterRim7);
const torus26 = new THREE.Mesh(new THREE.TorusGeometry(0.053, 0.0127, 3, 12), rimMat);
torus26.rotation.set(deg(90), 0, 0);
torus26.scale.set(1, 1, 0.6);
craterRim7.add(torus26);
const craterFloor8 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.1433), floorMat);
craterFloor8.name = 'craterFloor8';
craterFloor8.rotation.set(deg(71.4527), 0, deg(84.9938));
moon.add(craterFloor8);
const craterRim8 = new THREE.Group();
craterRim8.name = 'craterRim8';
craterRim8.position.set(-0.495, 0.0138, 0.0411);
craterRim8.rotation.set(deg(71.4527), 0, deg(84.9938));
moon.add(craterRim8);
const torus29 = new THREE.Mesh(new THREE.TorusGeometry(0.0714, 0.0172, 3, 12), rimMat);
torus29.rotation.set(deg(90), 0, 0);
torus29.scale.set(1, 1, 0.6);
craterRim8.add(torus29);
const craterFloor9 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.1016), floorMat);
craterFloor9.name = 'craterFloor9';
craterFloor9.rotation.set(deg(-113.2903), 0, deg(-48.2352));
moon.add(craterFloor9);
const craterRim9 = new THREE.Group();
craterRim9.name = 'craterRim9';
craterRim9.position.set(0.3725, -0.1315, -0.3055);
craterRim9.rotation.set(deg(-113.2903), 0, deg(-48.2352));
moon.add(craterRim9);
const torus32 = new THREE.Mesh(new THREE.TorusGeometry(0.0507, 0.0122, 3, 12), rimMat);
torus32.rotation.set(deg(90), 0, 0);
torus32.scale.set(1, 1, 0.6);
craterRim9.add(torus32);
const craterFloor10 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.1061), floorMat);
craterFloor10.name = 'craterFloor10';
craterFloor10.rotation.set(deg(97.1458), 0, deg(0.109));
moon.add(craterFloor10);
const craterRim10 = new THREE.Group();
craterRim10.name = 'craterRim10';
craterRim10.position.set(-0.0009, -0.0621, 0.4953);
craterRim10.rotation.set(deg(97.1458), 0, deg(0.109));
moon.add(craterRim10);
const torus35 = new THREE.Mesh(new THREE.TorusGeometry(0.0529, 0.0127, 3, 12), rimMat);
torus35.rotation.set(deg(90), 0, 0);
torus35.scale.set(1, 1, 0.6);
craterRim10.add(torus35);
const craterFloor11 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.0802), floorMat);
craterFloor11.name = 'craterFloor11';
craterFloor11.rotation.set(deg(-2.6629), 0, deg(21.392));
moon.add(craterFloor11);
const craterRim11 = new THREE.Group();
craterRim11.name = 'craterRim11';
craterRim11.position.set(-0.1825, 0.4654, -0.0216);
craterRim11.rotation.set(deg(-2.6629), 0, deg(21.392));
moon.add(craterRim11);
const torus38 = new THREE.Mesh(new THREE.TorusGeometry(0.0401, 0.0096, 3, 12), rimMat);
torus38.rotation.set(deg(90), 0, 0);
torus38.scale.set(1, 1, 0.6);
craterRim11.add(torus38);
const craterFloor12 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.0879), floorMat);
craterFloor12.name = 'craterFloor12';
craterFloor12.rotation.set(deg(-50.471), 0, deg(-55.5141));
moon.add(craterFloor12);
const craterRim12 = new THREE.Group();
craterRim12.name = 'craterRim12';
craterRim12.position.set(0.4122, 0.1802, -0.2184);
craterRim12.rotation.set(deg(-50.471), 0, deg(-55.5141));
moon.add(craterRim12);
const torus41 = new THREE.Mesh(new THREE.TorusGeometry(0.0439, 0.0106, 3, 12), rimMat);
torus41.rotation.set(deg(90), 0, 0);
torus41.scale.set(1, 1, 0.6);
craterRim12.add(torus41);
const craterFloor13 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.1311), floorMat);
craterFloor13.name = 'craterFloor13';
craterFloor13.rotation.set(deg(21.7535), 0, deg(-39.9478));
moon.add(craterFloor13);
const craterRim13 = new THREE.Group();
craterRim13.name = 'craterRim13';
craterRim13.position.set(0.3196, 0.3544, 0.1414);
craterRim13.rotation.set(deg(21.7535), 0, deg(-39.9478));
moon.add(craterRim13);
const torus44 = new THREE.Mesh(new THREE.TorusGeometry(0.0654, 0.0157, 3, 12), rimMat);
torus44.rotation.set(deg(90), 0, 0);
torus44.scale.set(1, 1, 0.6);
craterRim13.add(torus44);
const craterFloor14 = new THREE.Mesh(new THREE.SphereGeometry(0.5065, 12, 2, 0, Math.PI * 2, 0, 0.0876), floorMat);
craterFloor14.name = 'craterFloor14';
craterFloor14.rotation.set(deg(-157.1896), 0, deg(-42.0196));
moon.add(craterFloor14);
const craterRim14 = new THREE.Group();
craterRim14.name = 'craterRim14';
craterRim14.position.set(0.3347, -0.3425, -0.144);
craterRim14.rotation.set(deg(-157.1896), 0, deg(-42.0196));
moon.add(craterRim14);
const torus47 = new THREE.Mesh(new THREE.TorusGeometry(0.0438, 0.0105, 3, 12), rimMat);
torus47.rotation.set(deg(90), 0, 0);
torus47.scale.set(1, 1, 0.6);
craterRim14.add(torus47);
// Animations ('idle') — play them with THREE.AnimationMixer
root.animations = codelsClips(THREE, [
{ target: moon, anim: [{ type: 'spin', axis: 'y', speed: 15 }] },
]);
root.traverse((o) => {
if (o.isMesh) {
o.castShadow = true;
o.receiveShadow = true;
}
});
return root;
}
export default createMoon;
Valoraciones y comentarios
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









