Codels
928 üçgen0,77 × 1,32 × 0,08 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.
/**
 * Recurve Bow — Codels 3D model library
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 928 · Size (W × H × D): 0.77 × 1.32 × 0.08 m
 *
 * Usage:
 *   import { createBow } from './bow.js';
 *   
 *   const model = createBow();
 *   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 createBow() {
  const root = new THREE.Group();
  root.name = 'Bow';

  // Materials
  const woodMat = new THREE.MeshStandardMaterial({ name: 'wood', color: 0x8b5a32, roughness: 0.75, flatShading: true });
  const leatherMat = new THREE.MeshStandardMaterial({ name: 'leather', color: 0x4a2c1a, roughness: 0.9, flatShading: true });
  const hornMat = new THREE.MeshStandardMaterial({ name: 'horn', color: 0xe6d3a8, roughness: 0.6, flatShading: true });
  const stringMat = new THREE.MeshStandardMaterial({ name: 'string', color: 0xefe8d6, roughness: 0.8, flatShading: true });
  const shaftMat = new THREE.MeshStandardMaterial({ name: 'shaft', color: 0xc79c5e, roughness: 0.85, flatShading: true });
  const steelMat = new THREE.MeshStandardMaterial({ name: 'steel', color: 0xa7b0ba, roughness: 0.35, metalness: 0.7, flatShading: true });
  const featherMat = new THREE.MeshStandardMaterial({ name: 'feather', color: 0xd6493a, roughness: 0.9, flatShading: true, side: THREE.DoubleSide });

  // Shared geometries
  const sphereGeo = new THREE.SphereGeometry(0.017, 6, 4);
  const extrudeGeo = extrude([[0.003, 0], [0.028, 0.012], [0.032, 0.08], [0.02, 0.12], [0.003, 0.14]], 0.0025);

  // Parts
  const bow = new THREE.Group();
  bow.name = 'bow';
  bow.position.set(-0.36, 0, 0);
  root.add(bow);
  const limbs = new THREE.Mesh(tube([[0.0204, 0.016, 0], [0, 0.0604, 0], [0.0238, 0.1428, 0], [0.0799, 0.2696, 0], [0.1462, 0.4598, 0], [0.17, 0.65, 0], [0.1462, 0.8402, 0], [0.0799, 1.0304, 0], [0.0238, 1.1572, 0], [0, 1.2396, 0], [0.0204, 1.284, 0]], 0.016, 44, 6), woodMat);
  limbs.name = 'limbs';
  bow.add(limbs);
  const riser = new THREE.Mesh(tube([[0.1224, 0.3837, 0], [0.1581, 0.5232, 0], [0.17, 0.65, 0], [0.1581, 0.7768, 0], [0.1224, 0.9163, 0]], 0.0216, 12, 6), woodMat);
  riser.name = 'riser';
  bow.add(riser);
  const grip = new THREE.Mesh(new THREE.CylinderGeometry(0.024, 0.024, 0.15, 7), leatherMat);
  grip.name = 'grip';
  grip.position.set(0.17, 0.65, 0);
  bow.add(grip);
  const tipTop = new THREE.Mesh(sphereGeo, hornMat);
  tipTop.name = 'tipTop';
  tipTop.position.set(0.0204, 1.284, 0);
  tipTop.scale.set(1, 1.4, 1);
  bow.add(tipTop);
  const tipBottom = new THREE.Mesh(sphereGeo, hornMat);
  tipBottom.name = 'tipBottom';
  tipBottom.position.set(0.0204, 0.016, 0);
  tipBottom.scale.set(1, 1.4, 1);
  bow.add(tipBottom);
  const string = new THREE.Mesh(new THREE.CylinderGeometry(0.0045, 0.0045, 1.1792, 4), stringMat);
  string.name = 'string';
  string.position.set(-0.004, 0.65, 0);
  bow.add(string);
  const arrow = new THREE.Group();
  arrow.name = 'arrow';
  arrow.position.set(-0.012, 0.74, 0.028);
  bow.add(arrow);
  const arrowShaft = new THREE.Mesh(new THREE.CylinderGeometry(0.0065, 0.0065, 0.68, 6), shaftMat);
  arrowShaft.name = 'arrowShaft';
  arrowShaft.position.set(0.34, 0, 0);
  arrowShaft.rotation.set(0, 0, deg(-90));
  arrow.add(arrowShaft);
  const arrowSocket = new THREE.Mesh(new THREE.CylinderGeometry(0.009, 0.0075, 0.035, 6), steelMat);
  arrowSocket.name = 'arrowSocket';
  arrowSocket.position.set(0.67, 0, 0);
  arrowSocket.rotation.set(0, 0, deg(-90));
  arrow.add(arrowSocket);
  const arrowHead = new THREE.Mesh(extrude([[0, 0], [0.025, 0.03], [0.026, 0.05], [0, 0.1], [-0.026, 0.05], [-0.025, 0.03]], 0.002, [], [0.004, 0.003, 1]), steelMat);
  arrowHead.name = 'arrowHead';
  arrowHead.position.set(0.665, 0, 0);
  arrowHead.rotation.set(0, 0, deg(-90));
  arrow.add(arrowHead);
  const vane1 = new THREE.Group();
  vane1.name = 'vane1';
  vane1.position.set(0.03, 0, 0);
  vane1.rotation.set(deg(30), 0, deg(-90));
  arrow.add(vane1);
  const arrowVane1 = new THREE.Mesh(extrudeGeo, featherMat);
  arrowVane1.name = 'arrowVane1';
  arrowVane1.rotation.set(0, deg(90), 0);
  vane1.add(arrowVane1);
  const vane2 = new THREE.Group();
  vane2.name = 'vane2';
  vane2.position.set(0.03, 0, 0);
  vane2.rotation.set(deg(150), 0, deg(-90));
  arrow.add(vane2);
  const arrowVane2 = new THREE.Mesh(extrudeGeo, featherMat);
  arrowVane2.name = 'arrowVane2';
  arrowVane2.rotation.set(0, deg(90), 0);
  vane2.add(arrowVane2);
  const vane3 = new THREE.Group();
  vane3.name = 'vane3';
  vane3.position.set(0.03, 0, 0);
  vane3.rotation.set(deg(270), 0, deg(-90));
  arrow.add(vane3);
  const arrowVane3 = new THREE.Mesh(extrudeGeo, featherMat);
  arrowVane3.name = 'arrowVane3';
  arrowVane3.rotation.set(0, deg(90), 0);
  vane3.add(arrowVane3);

  root.traverse((o) => {
    if (o.isMesh) {
      o.castShadow = true;
      o.receiveShadow = true;
    }
  });
  return root;
}

export default createBow;

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