1,4 mil tris1,62 × 1,00 × 1,90 m
Úsalo en código
Hacer remix en el editorcannon.js · 210 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.
/**
* Pirate Cannon — Codels 3D model library
* License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
* Triangles: 1,386 · Size (W × H × D): 1.62 × 1.00 × 1.90 m
*
* Usage:
* import { createCannon } from './cannon.js';
*
* const model = createCannon();
* 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 createCannon() {
const root = new THREE.Group();
root.name = 'Cannon';
// Materials
const woodMat = new THREE.MeshStandardMaterial({ name: 'wood', color: 0x8a5a2b, roughness: 0.85, flatShading: true });
const woodDarkMat = new THREE.MeshStandardMaterial({ name: 'woodDark', color: 0x613f1e, roughness: 0.9, flatShading: true });
const ironMat = new THREE.MeshStandardMaterial({ name: 'iron', color: 0x33383f, roughness: 0.45, metalness: 0.6, flatShading: true });
const ironDarkMat = new THREE.MeshStandardMaterial({ name: 'ironDark', color: 0x1c1f23, roughness: 0.6, metalness: 0.4, flatShading: true });
const brassMat = new THREE.MeshStandardMaterial({ name: 'brass', color: 0xc8a24a, roughness: 0.35, metalness: 0.7, flatShading: true });
const boreMat = new THREE.MeshStandardMaterial({ name: 'bore', color: 0x0d0e10, roughness: 1, flatShading: true });
const sparkMat = new THREE.MeshStandardMaterial({ name: 'spark', color: 0xffd36b, roughness: 0.4, emissive: 0xff9a1f, emissiveIntensity: 1.4, flatShading: true });
// Shared geometries
const extrudeGeo = extrude([[0.58, 0.12], [0.58, 0.5], [0.4, 0.6], [0.36, 0.54], [0.2, 0.54], [0.14, 0.6], [0.04, 0.54], [0.04, 0.44], [-0.2, 0.44], [-0.2, 0.34], [-0.42, 0.34], [-0.42, 0.24], [-0.62, 0.24], [-0.62, 0.12]], 0.12);
const boxGeo = new THREE.BoxGeometry(0.14, 0.04, 0.26);
const torusGeo = new THREE.TorusGeometry(0.04, 0.012, 3, 6);
const boxGeo2 = new THREE.BoxGeometry(0.96, 0.11, 0.13);
const cylinderGeo = new THREE.CylinderGeometry(0.21, 0.21, 0.1, 10);
const cylinderGeo2 = new THREE.CylinderGeometry(0.084, 0.084, 0.12, 8);
const cylinderGeo3 = new THREE.CylinderGeometry(0.18, 0.18, 0.1, 10);
const cylinderGeo4 = new THREE.CylinderGeometry(0.072, 0.072, 0.12, 8);
const sphereGeo = new THREE.SphereGeometry(0.1, 7, 5);
// Parts
const cheekLeft = new THREE.Mesh(extrudeGeo, woodMat);
cheekLeft.name = 'cheekLeft';
cheekLeft.position.set(-0.3, 0, 0);
cheekLeft.rotation.set(0, deg(-90), 0);
root.add(cheekLeft);
const capSquareLeft = new THREE.Mesh(boxGeo, ironDarkMat);
capSquareLeft.name = 'capSquareLeft';
capSquareLeft.position.set(-0.3, 0.64, 0.28);
root.add(capSquareLeft);
const torus3 = new THREE.Mesh(torusGeo, ironDarkMat);
torus3.position.set(-0.37, 0.3, -0.35);
torus3.rotation.set(0, deg(90), 0);
root.add(torus3);
const torus4 = new THREE.Mesh(torusGeo, ironDarkMat);
torus4.position.set(-0.37, 0.3, 0.45);
torus4.rotation.set(0, deg(90), 0);
root.add(torus4);
const cheekRight = new THREE.Mesh(extrudeGeo, woodMat);
cheekRight.name = 'cheekRight';
cheekRight.position.set(0.3, 0, 0);
cheekRight.rotation.set(0, deg(-90), 0);
root.add(cheekRight);
const capSquareRight = new THREE.Mesh(boxGeo, ironDarkMat);
capSquareRight.name = 'capSquareRight';
capSquareRight.position.set(0.3, 0.64, 0.28);
root.add(capSquareRight);
const torus7 = new THREE.Mesh(torusGeo, ironDarkMat);
torus7.position.set(0.37, 0.3, -0.35);
torus7.rotation.set(0, deg(90), 0);
root.add(torus7);
const torus8 = new THREE.Mesh(torusGeo, ironDarkMat);
torus8.position.set(0.37, 0.3, 0.45);
torus8.rotation.set(0, deg(90), 0);
root.add(torus8);
const bed = new THREE.Mesh(new THREE.BoxGeometry(0.6, 0.06, 0.95), woodDarkMat);
bed.name = 'bed';
bed.position.set(0, 0.19, -0.05);
root.add(bed);
const transom = new THREE.Mesh(new THREE.BoxGeometry(0.48, 0.18, 0.1), woodMat);
transom.name = 'transom';
transom.position.set(0, 0.31, 0.46);
root.add(transom);
const quoin = new THREE.Mesh(new THREE.BoxGeometry(0.3, 0.1, 0.36), woodMat);
quoin.name = 'quoin';
quoin.position.set(0, 0.27, -0.32);
quoin.rotation.set(deg(-8), 0, 0);
root.add(quoin);
const axleFront = new THREE.Mesh(boxGeo2, woodDarkMat);
axleFront.name = 'axleFront';
axleFront.position.set(0, 0.21, 0.4);
root.add(axleFront);
const wheelFL = new THREE.Mesh(cylinderGeo, woodMat);
wheelFL.name = 'wheelFL';
wheelFL.position.set(-0.45, 0.21, 0.4);
wheelFL.rotation.set(0, 0, deg(90));
root.add(wheelFL);
const cylinder14 = new THREE.Mesh(cylinderGeo2, ironDarkMat);
cylinder14.position.set(-0.45, 0.21, 0.4);
cylinder14.rotation.set(0, 0, deg(90));
root.add(cylinder14);
const wheelFR = new THREE.Mesh(cylinderGeo, woodMat);
wheelFR.name = 'wheelFR';
wheelFR.position.set(0.45, 0.21, 0.4);
wheelFR.rotation.set(0, 0, deg(90));
root.add(wheelFR);
const cylinder16 = new THREE.Mesh(cylinderGeo2, ironDarkMat);
cylinder16.position.set(0.45, 0.21, 0.4);
cylinder16.rotation.set(0, 0, deg(90));
root.add(cylinder16);
const axleRear = new THREE.Mesh(boxGeo2, woodDarkMat);
axleRear.name = 'axleRear';
axleRear.position.set(0, 0.18, -0.46);
root.add(axleRear);
const wheelRL = new THREE.Mesh(cylinderGeo3, woodMat);
wheelRL.name = 'wheelRL';
wheelRL.position.set(-0.45, 0.18, -0.46);
wheelRL.rotation.set(0, 0, deg(90));
root.add(wheelRL);
const cylinder19 = new THREE.Mesh(cylinderGeo4, ironDarkMat);
cylinder19.position.set(-0.45, 0.18, -0.46);
cylinder19.rotation.set(0, 0, deg(90));
root.add(cylinder19);
const wheelRR = new THREE.Mesh(cylinderGeo3, woodMat);
wheelRR.name = 'wheelRR';
wheelRR.position.set(0.45, 0.18, -0.46);
wheelRR.rotation.set(0, 0, deg(90));
root.add(wheelRR);
const cylinder21 = new THREE.Mesh(cylinderGeo4, ironDarkMat);
cylinder21.position.set(0.45, 0.18, -0.46);
cylinder21.rotation.set(0, 0, deg(90));
root.add(cylinder21);
const barrel = new THREE.Group();
barrel.name = 'barrel';
barrel.position.set(0, 0.62, 0.28);
barrel.rotation.set(deg(-12), 0, 0);
root.add(barrel);
const tube2 = new THREE.Mesh(lathe([[0, -0.6], [0.055, -0.585], [0.065, -0.55], [0.035, -0.52], [0.06, -0.5], [0.17, -0.46], [0.205, -0.42], [0.205, -0.37], [0.19, -0.35], [0.19, -0.03], [0.205, -0.01], [0.205, 0.05], [0.18, 0.07], [0.15, 0.72], [0.165, 0.74], [0.165, 0.79], [0.15, 0.81], [0.15, 0.84], [0.18, 0.9], [0.18, 0.96], [0.1, 0.96], [0, 0.96]], 10), ironMat);
tube2.name = 'tube';
tube2.rotation.set(deg(90), 0, 0);
barrel.add(tube2);
const bore = new THREE.Mesh(new THREE.CircleGeometry(0.1, 10), boreMat);
bore.name = 'bore';
bore.position.set(0, 0, 0.962);
barrel.add(bore);
const trunnions = new THREE.Mesh(new THREE.CylinderGeometry(0.065, 0.065, 0.672, 8), ironMat);
trunnions.name = 'trunnions';
trunnions.rotation.set(0, 0, deg(90));
barrel.add(trunnions);
const vent = new THREE.Mesh(new THREE.CylinderGeometry(0.025, 0.03, 0.04, 6), brassMat);
vent.name = 'vent';
vent.position.set(0, 0.19, -0.3);
barrel.add(vent);
const fuse = new THREE.Mesh(tube([[0, 0.2, -0.3], [0.02, 0.26, -0.32], [0.05, 0.29, -0.36]], 0.008, 6, 4), woodDarkMat);
fuse.name = 'fuse';
barrel.add(fuse);
const fuseSpark = new THREE.Mesh(new THREE.OctahedronGeometry(0.035, 0), sparkMat);
fuseSpark.name = 'fuseSpark';
fuseSpark.position.set(0.05, 0.3, -0.37);
fuseSpark.rotation.set(deg(20), deg(30), 0);
barrel.add(fuseSpark);
const cannonballs = new THREE.Group();
cannonballs.name = 'cannonballs';
cannonballs.position.set(0.92, 0, -0.25);
root.add(cannonballs);
const sphere30 = new THREE.Mesh(sphereGeo, ironDarkMat);
sphere30.position.set(0, 0.1, -0.1155);
cannonballs.add(sphere30);
const sphere31 = new THREE.Mesh(sphereGeo, ironDarkMat);
sphere31.position.set(0.1, 0.1, 0.0577);
cannonballs.add(sphere31);
const sphere32 = new THREE.Mesh(sphereGeo, ironDarkMat);
sphere32.position.set(-0.1, 0.1, 0.0577);
cannonballs.add(sphere32);
const sphere33 = new THREE.Mesh(sphereGeo, ironDarkMat);
sphere33.position.set(0, 0.2633, 0);
cannonballs.add(sphere33);
root.traverse((o) => {
if (o.isMesh) {
o.castShadow = true;
o.receiveShadow = true;
}
});
return root;
}
export default createCannon;
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









