1,4 k tris0,45 × 0,59 × 0,35 m
Utiliser dans le code
Remixer dans l’éditeurbackpack.js · 172 lignes
Module ES autonome — ne dépend que de three. Appelez la fonction factory et ajoutez le groupe à votre scène.
/**
* Adventurer Backpack — Codels 3D model library
* License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
* Triangles: 1,384 · Size (W × H × D): 0.45 × 0.59 × 0.35 m
*
* Usage:
* import { createBackpack } from './backpack.js';
*
* const model = createBackpack();
* model.position.set(0, 0, 0);
* scene.add(model);
*/
import * as THREE from 'three';
const deg = THREE.MathUtils.degToRad;
// 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 createBackpack() {
const root = new THREE.Group();
root.name = 'Backpack';
// Materials
const bagMat = new THREE.MeshStandardMaterial({ name: 'bag', color: 0x6f7a47, roughness: 0.95, flatShading: true });
const leatherMat = new THREE.MeshStandardMaterial({ name: 'leather', color: 0x6b4527, roughness: 0.85, flatShading: true });
const buckleMat = new THREE.MeshStandardMaterial({ name: 'buckle', color: 0xd6ad4a, roughness: 0.35, metalness: 0.75, flatShading: true });
const blanketMat = new THREE.MeshStandardMaterial({ name: 'blanket', color: 0xb34a3a, roughness: 0.95, flatShading: true });
const blanketEdgeMat = new THREE.MeshStandardMaterial({ name: 'blanketEdge', color: 0xe8d9b5, roughness: 0.95, flatShading: true });
const ropeMat = new THREE.MeshStandardMaterial({ name: 'rope', color: 0xc9a66b, roughness: 0.95, flatShading: true });
const tinMat = new THREE.MeshStandardMaterial({ name: 'tin', color: 0x9aa3ab, roughness: 0.4, metalness: 0.65, flatShading: true });
// Shared geometries
const boxGeo = new THREE.BoxGeometry(0.034, 0.2, 0.008);
const boxGeo2 = new THREE.BoxGeometry(0.046, 0.036, 0.008);
const boxGeo3 = new THREE.BoxGeometry(0.024, 0.016, 0.008);
const cylinderGeo = new THREE.CylinderGeometry(0.073, 0.073, 0.026, 12);
// Parts
const body = new THREE.Mesh(extrude([[0.1, -0.2], [0.1354, -0.1854], [0.15, -0.15], [0.15, 0.15], [0.1354, 0.1854], [0.1, 0.2], [-0.1, 0.2], [-0.1354, 0.1854], [-0.15, 0.15], [-0.15, -0.15], [-0.1354, -0.1854], [-0.1, -0.2]], 0.14, [], [0.03, 0.02, 2]), bagMat);
body.name = 'body';
body.position.set(0, 0.22, 0);
root.add(body);
const pocket = new THREE.Mesh(extrude([[0.075, -0.075], [0.0997, -0.0647], [0.11, -0.04], [0.11, 0.04], [0.0997, 0.0647], [0.075, 0.075], [-0.075, 0.075], [-0.0997, 0.0647], [-0.11, 0.04], [-0.11, -0.04], [-0.0997, -0.0647], [-0.075, -0.075]], 0.04, [], [0.015, 0.012, 2]), bagMat);
pocket.name = 'pocket';
pocket.position.set(0, 0.13, 0.123);
root.add(pocket);
const pocketFlap = new THREE.Mesh(extrude([[0.095, -0.035], [0.1075, -0.0317], [0.1167, -0.0225], [0.12, -0.01], [0.12, 0.01], [0.1167, 0.0225], [0.1075, 0.0317], [0.095, 0.035], [-0.095, 0.035], [-0.1075, 0.0317], [-0.1167, 0.0225], [-0.12, 0.01], [-0.12, -0.01], [-0.1167, -0.0225], [-0.1075, -0.0317], [-0.095, -0.035]], 0.008, [], [0.003, 0.003, 1]), leatherMat);
pocketFlap.name = 'pocketFlap';
pocketFlap.position.set(0, 0.19, 0.162);
root.add(pocketFlap);
const pocketBuckle = new THREE.Mesh(new THREE.BoxGeometry(0.04, 0.03, 0.01), buckleMat);
pocketBuckle.name = 'pocketBuckle';
pocketBuckle.position.set(0, 0.165, 0.168);
root.add(pocketBuckle);
const pocketBuckleHole = new THREE.Mesh(new THREE.BoxGeometry(0.022, 0.012, 0.012), leatherMat);
pocketBuckleHole.name = 'pocketBuckleHole';
pocketBuckleHole.position.set(0, 0.165, 0.17);
root.add(pocketBuckleHole);
const flapTop = new THREE.Mesh(new THREE.BoxGeometry(0.306, 0.014, 0.184), leatherMat);
flapTop.name = 'flapTop';
flapTop.position.set(0, 0.442, 0);
root.add(flapTop);
const flapFold = new THREE.Mesh(new THREE.CylinderGeometry(0.018, 0.018, 0.306, 8), leatherMat);
flapFold.name = 'flapFold';
flapFold.position.set(0, 0.428, 0.088);
flapFold.rotation.set(0, 0, deg(90));
root.add(flapFold);
const flapFront = new THREE.Mesh(extrude([[0.108, -0.085], [0.1305, -0.079], [0.147, -0.0625], [0.153, -0.04], [0.153, 0.04], [0.147, 0.0625], [0.1305, 0.079], [0.108, 0.085], [-0.108, 0.085], [-0.1305, 0.079], [-0.147, 0.0625], [-0.153, 0.04], [-0.153, -0.04], [-0.147, -0.0625], [-0.1305, -0.079], [-0.108, -0.085]], 0.012), leatherMat);
flapFront.name = 'flapFront';
flapFront.position.set(0, 0.355, 0.104);
root.add(flapFront);
const strapR = new THREE.Mesh(boxGeo, leatherMat);
strapR.name = 'strapR';
strapR.position.set(0.085, 0.34, 0.113);
root.add(strapR);
const buckleR = new THREE.Mesh(boxGeo2, buckleMat);
buckleR.name = 'buckleR';
buckleR.position.set(0.085, 0.265, 0.118);
root.add(buckleR);
const buckleBarR = new THREE.Mesh(boxGeo3, leatherMat);
buckleBarR.name = 'buckleBarR';
buckleBarR.position.set(0.085, 0.265, 0.121);
root.add(buckleBarR);
const strapL = new THREE.Mesh(boxGeo, leatherMat);
strapL.name = 'strapL';
strapL.position.set(-0.085, 0.34, 0.113);
root.add(strapL);
const buckleL = new THREE.Mesh(boxGeo2, buckleMat);
buckleL.name = 'buckleL';
buckleL.position.set(-0.085, 0.265, 0.118);
root.add(buckleL);
const buckleBarL = new THREE.Mesh(boxGeo3, leatherMat);
buckleBarL.name = 'buckleBarL';
buckleBarL.position.set(-0.085, 0.265, 0.121);
root.add(buckleBarL);
const shoulderStrapR = new THREE.Mesh(tube([[0.085, 0.41, -0.09], [0.085, 0.36, -0.145], [0.085, 0.22, -0.16], [0.0978, 0.1, -0.135], [0.102, 0.045, -0.09]], 0.014, 12, 4), leatherMat);
shoulderStrapR.name = 'shoulderStrapR';
root.add(shoulderStrapR);
const shoulderStrapL = new THREE.Mesh(tube([[-0.085, 0.41, -0.09], [-0.085, 0.36, -0.145], [-0.085, 0.22, -0.16], [-0.0977, 0.1, -0.135], [-0.102, 0.045, -0.09]], 0.014, 12, 4), leatherMat);
shoulderStrapL.name = 'shoulderStrapL';
root.add(shoulderStrapL);
const ropeCoil = new THREE.Mesh(new THREE.TorusGeometry(0.058, 0.014, 4, 12), ropeMat);
ropeCoil.name = 'ropeCoil';
ropeCoil.position.set(-0.178, 0.198, 0);
ropeCoil.rotation.set(0, deg(90), 0);
root.add(ropeCoil);
const ropeCoil2 = new THREE.Mesh(new THREE.TorusGeometry(0.04, 0.012, 4, 10), ropeMat);
ropeCoil2.name = 'ropeCoil2';
ropeCoil2.position.set(-0.186, 0.198, 0);
ropeCoil2.rotation.set(0, deg(90), 0);
root.add(ropeCoil2);
const canteen = new THREE.Mesh(new THREE.CylinderGeometry(0.062, 0.062, 0.038, 10), tinMat);
canteen.name = 'canteen';
canteen.position.set(0.2, 0.1584, 0.01);
canteen.rotation.set(0, 0, deg(90));
root.add(canteen);
const canteenCap = new THREE.Mesh(new THREE.CylinderGeometry(0.014, 0.016, 0.03, 6), leatherMat);
canteenCap.name = 'canteenCap';
canteenCap.position.set(0.2, 0.2334, 0.01);
root.add(canteenCap);
const canteenStrap = new THREE.Mesh(new THREE.BoxGeometry(0.008, 0.16, 0.02), leatherMat);
canteenStrap.name = 'canteenStrap';
canteenStrap.position.set(0.2, 0.1936, 0.01);
canteenStrap.rotation.set(0, 0, deg(-8));
root.add(canteenStrap);
const bedroll = new THREE.Mesh(new THREE.CylinderGeometry(0.068, 0.068, 0.44, 12), blanketMat);
bedroll.name = 'bedroll';
bedroll.position.set(0, 0.517, 0);
bedroll.rotation.set(0, 0, deg(90));
root.add(bedroll);
const bedrollSpiralR = new THREE.Mesh(tube([[0.222, 0.517, 0.0102], [0.222, 0.5276, 0.0085], [0.222, 0.5336, -0.0038], [0.222, 0.5259, -0.0184], [0.222, 0.5067, -0.0214], [0.222, 0.4905, -0.0061], [0.222, 0.4931, 0.0191], [0.222, 0.517, 0.034], [0.222, 0.5462, 0.0233], [0.222, 0.5568, -0.0091], [0.222, 0.5362, -0.0398], [0.222, 0.4963, -0.0429], [0.222, 0.4673, -0.0113], [0.222, 0.4745, 0.0339], [0.222, 0.517, 0.0578]], 0.005, 16, 3), blanketEdgeMat);
bedrollSpiralR.name = 'bedrollSpiralR';
root.add(bedrollSpiralR);
const bedrollStrapR = new THREE.Mesh(cylinderGeo, leatherMat);
bedrollStrapR.name = 'bedrollStrapR';
bedrollStrapR.position.set(0.12, 0.517, 0);
bedrollStrapR.rotation.set(0, 0, deg(90));
root.add(bedrollStrapR);
const bedrollSpiralL = new THREE.Mesh(tube([[-0.222, 0.517, 0.0102], [-0.222, 0.5276, 0.0085], [-0.222, 0.5336, -0.0038], [-0.222, 0.5259, -0.0184], [-0.222, 0.5067, -0.0214], [-0.222, 0.4905, -0.0061], [-0.222, 0.4931, 0.0191], [-0.222, 0.517, 0.034], [-0.222, 0.5462, 0.0233], [-0.222, 0.5568, -0.0091], [-0.222, 0.5362, -0.0398], [-0.222, 0.4963, -0.0429], [-0.222, 0.4673, -0.0113], [-0.222, 0.4745, 0.0339], [-0.222, 0.517, 0.0578]], 0.005, 16, 3), blanketEdgeMat);
bedrollSpiralL.name = 'bedrollSpiralL';
root.add(bedrollSpiralL);
const bedrollStrapL = new THREE.Mesh(cylinderGeo, leatherMat);
bedrollStrapL.name = 'bedrollStrapL';
bedrollStrapL.position.set(-0.12, 0.517, 0);
bedrollStrapL.rotation.set(0, 0, deg(90));
root.add(bedrollStrapL);
root.traverse((o) => {
if (o.isMesh) {
o.castShadow = true;
o.receiveShadow = true;
}
});
return root;
}
export default createBackpack;
Notes et commentaires
0 commentaire
Aucun commentaire pour l’instant. Dites comment vous avez utilisé ce modèle ou ce qui pourrait être amélioré.
Modèles similaires
Même catégorie ou étiquettes proches









