Codels
1,4 B üçgen0,45 × 0,59 × 0,35 m
Bağımsız bir ES modülü — yalnızca three paketine bağımlıdır. Fabrika fonksiyonunu çağırıp dönen grubu sahnene ekle.
/**
 * 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;

Puanlar ve yorumlar

—
Henüz puan yok — ilk puanı sen ver.
5
0
4
0
3
0
2
0
1
0

Puan vermek ve yorum yapmak için giriş yap.

0 yorum

Henüz yorum yok. Bu modeli nasıl kullandığını ya da neyin daha iyi olabileceğini paylaş.

Benzer modeller

Aynı kategori ya da benzer etiketler