Codels
1448 三角面1.01 × 0.85 × 1.01 m

在代码中使用

在编辑器中改编
自包含的 ES 模块,仅依赖 three。调用工厂函数,然后把返回的 group 添加到场景中。
/**
 * Spring Bouncer — Codels 3D model library
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 1,448 · Size (W × H × D): 1.01 × 0.85 × 1.01 m
 *
 * Usage:
 *   import { createSpring } from './spring.js';
 *   
 *   const model = createSpring();
 *   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 createSpring() {
  const root = new THREE.Group();
  root.name = 'Spring';

  // Materials
  const baseMat = new THREE.MeshStandardMaterial({ name: 'base', color: 0x323a4a, roughness: 0.6, metalness: 0.3, flatShading: true });
  const darkMat = new THREE.MeshStandardMaterial({ name: 'dark', color: 0x20242c, roughness: 0.7, metalness: 0.3, flatShading: true });
  const hazardMat = new THREE.MeshStandardMaterial({ name: 'hazard', color: 0xf5c02a, roughness: 0.55, flatShading: true });
  const stripeMat = new THREE.MeshStandardMaterial({ name: 'stripe', color: 0x1d1f25, roughness: 0.7, flatShading: true });
  const coilMat = new THREE.MeshStandardMaterial({ name: 'coil', color: 0xd3d9e2, roughness: 0.25, metalness: 0.8, flatShading: true });
  const plateMat = new THREE.MeshStandardMaterial({ name: 'plate', color: 0xe8392f, roughness: 0.4, flatShading: true });
  const plateTopMat = new THREE.MeshStandardMaterial({ name: 'plateTop', color: 0xec5d54, roughness: 0.45, flatShading: true });
  const arrowMat = new THREE.MeshStandardMaterial({ name: 'arrow', color: 0xffffff, roughness: 0.4, emissive: 0xfff4c8, emissiveIntensity: 0.8, flatShading: true });

  // Shared geometries
  const extrudeGeo = extrude([[-0.5, 0.03], [-0.5, -0.03], [-0.49, -0.03], [-0.43, 0.03]], 0.006);
  const extrudeGeo2 = extrude([[-0.42, -0.03], [-0.35, -0.03], [-0.29, 0.03], [-0.36, 0.03]], 0.006);
  const extrudeGeo3 = extrude([[-0.28, -0.03], [-0.21, -0.03], [-0.15, 0.03], [-0.22, 0.03]], 0.006);
  const extrudeGeo4 = extrude([[-0.14, -0.03], [-0.07, -0.03], [-0.01, 0.03], [-0.08, 0.03]], 0.006);
  const extrudeGeo5 = extrude([[0, -0.03], [0.07, -0.03], [0.13, 0.03], [0.06, 0.03]], 0.006);
  const extrudeGeo6 = extrude([[0.14, -0.03], [0.21, -0.03], [0.27, 0.03], [0.2, 0.03]], 0.006);
  const extrudeGeo7 = extrude([[0.28, -0.03], [0.35, -0.03], [0.41, 0.03], [0.34, 0.03]], 0.006);
  const extrudeGeo8 = extrude([[0.42, -0.03], [0.49, -0.03], [0.5, -0.02], [0.5, 0.03], [0.48, 0.03]], 0.006);
  const cylinderGeo = new THREE.CylinderGeometry(0.03, 0.03, 0.02, 6);
  const extrudeGeo9 = extrude([[0, 0], [0.2, -0.2], [0.2, -0.28], [0, -0.08], [-0.2, -0.28], [-0.2, -0.2]], 0.014);

  // Parts
  const springBouncer = new THREE.Group();
  springBouncer.name = 'springBouncer';
  root.add(springBouncer);
  const baseBand = new THREE.Mesh(new THREE.BoxGeometry(1, 0.06, 1), hazardMat);
  baseBand.name = 'baseBand';
  baseBand.position.set(0, 0.03, 0);
  springBouncer.add(baseBand);
  const base = new THREE.Mesh(new THREE.BoxGeometry(0.96, 0.08, 0.96), baseMat);
  base.name = 'base';
  base.position.set(0, 0.1, 0);
  springBouncer.add(base);
  const baseStripesFront = new THREE.Group();
  baseStripesFront.name = 'baseStripesFront';
  baseStripesFront.position.set(0, 0.03, 0.5);
  springBouncer.add(baseStripesFront);
  const extrude5 = new THREE.Mesh(extrudeGeo, stripeMat);
  extrude5.position.set(0, 0, 0.003);
  baseStripesFront.add(extrude5);
  const extrude6 = new THREE.Mesh(extrudeGeo2, stripeMat);
  extrude6.position.set(0, 0, 0.003);
  baseStripesFront.add(extrude6);
  const extrude7 = new THREE.Mesh(extrudeGeo3, stripeMat);
  extrude7.position.set(0, 0, 0.003);
  baseStripesFront.add(extrude7);
  const extrude8 = new THREE.Mesh(extrudeGeo4, stripeMat);
  extrude8.position.set(0, 0, 0.003);
  baseStripesFront.add(extrude8);
  const extrude9 = new THREE.Mesh(extrudeGeo5, stripeMat);
  extrude9.position.set(0, 0, 0.003);
  baseStripesFront.add(extrude9);
  const extrude10 = new THREE.Mesh(extrudeGeo6, stripeMat);
  extrude10.position.set(0, 0, 0.003);
  baseStripesFront.add(extrude10);
  const extrude11 = new THREE.Mesh(extrudeGeo7, stripeMat);
  extrude11.position.set(0, 0, 0.003);
  baseStripesFront.add(extrude11);
  const extrude12 = new THREE.Mesh(extrudeGeo8, stripeMat);
  extrude12.position.set(0, 0, 0.003);
  baseStripesFront.add(extrude12);
  const baseStripesRight = new THREE.Group();
  baseStripesRight.name = 'baseStripesRight';
  baseStripesRight.position.set(0.5, 0.03, 0);
  baseStripesRight.rotation.set(0, deg(90), 0);
  springBouncer.add(baseStripesRight);
  const extrude14 = new THREE.Mesh(extrudeGeo, stripeMat);
  extrude14.position.set(0, 0, 0.003);
  baseStripesRight.add(extrude14);
  const extrude15 = new THREE.Mesh(extrudeGeo2, stripeMat);
  extrude15.position.set(0, 0, 0.003);
  baseStripesRight.add(extrude15);
  const extrude16 = new THREE.Mesh(extrudeGeo3, stripeMat);
  extrude16.position.set(0, 0, 0.003);
  baseStripesRight.add(extrude16);
  const extrude17 = new THREE.Mesh(extrudeGeo4, stripeMat);
  extrude17.position.set(0, 0, 0.003);
  baseStripesRight.add(extrude17);
  const extrude18 = new THREE.Mesh(extrudeGeo5, stripeMat);
  extrude18.position.set(0, 0, 0.003);
  baseStripesRight.add(extrude18);
  const extrude19 = new THREE.Mesh(extrudeGeo6, stripeMat);
  extrude19.position.set(0, 0, 0.003);
  baseStripesRight.add(extrude19);
  const extrude20 = new THREE.Mesh(extrudeGeo7, stripeMat);
  extrude20.position.set(0, 0, 0.003);
  baseStripesRight.add(extrude20);
  const extrude21 = new THREE.Mesh(extrudeGeo8, stripeMat);
  extrude21.position.set(0, 0, 0.003);
  baseStripesRight.add(extrude21);
  const baseStripesBack = new THREE.Group();
  baseStripesBack.name = 'baseStripesBack';
  baseStripesBack.position.set(0, 0.03, -0.5);
  baseStripesBack.rotation.set(0, deg(180), 0);
  springBouncer.add(baseStripesBack);
  const extrude23 = new THREE.Mesh(extrudeGeo, stripeMat);
  extrude23.position.set(0, 0, 0.003);
  baseStripesBack.add(extrude23);
  const extrude24 = new THREE.Mesh(extrudeGeo2, stripeMat);
  extrude24.position.set(0, 0, 0.003);
  baseStripesBack.add(extrude24);
  const extrude25 = new THREE.Mesh(extrudeGeo3, stripeMat);
  extrude25.position.set(0, 0, 0.003);
  baseStripesBack.add(extrude25);
  const extrude26 = new THREE.Mesh(extrudeGeo4, stripeMat);
  extrude26.position.set(0, 0, 0.003);
  baseStripesBack.add(extrude26);
  const extrude27 = new THREE.Mesh(extrudeGeo5, stripeMat);
  extrude27.position.set(0, 0, 0.003);
  baseStripesBack.add(extrude27);
  const extrude28 = new THREE.Mesh(extrudeGeo6, stripeMat);
  extrude28.position.set(0, 0, 0.003);
  baseStripesBack.add(extrude28);
  const extrude29 = new THREE.Mesh(extrudeGeo7, stripeMat);
  extrude29.position.set(0, 0, 0.003);
  baseStripesBack.add(extrude29);
  const extrude30 = new THREE.Mesh(extrudeGeo8, stripeMat);
  extrude30.position.set(0, 0, 0.003);
  baseStripesBack.add(extrude30);
  const baseStripesLeft = new THREE.Group();
  baseStripesLeft.name = 'baseStripesLeft';
  baseStripesLeft.position.set(-0.5, 0.03, 0);
  baseStripesLeft.rotation.set(0, deg(-90), 0);
  springBouncer.add(baseStripesLeft);
  const extrude32 = new THREE.Mesh(extrudeGeo, stripeMat);
  extrude32.position.set(0, 0, 0.003);
  baseStripesLeft.add(extrude32);
  const extrude33 = new THREE.Mesh(extrudeGeo2, stripeMat);
  extrude33.position.set(0, 0, 0.003);
  baseStripesLeft.add(extrude33);
  const extrude34 = new THREE.Mesh(extrudeGeo3, stripeMat);
  extrude34.position.set(0, 0, 0.003);
  baseStripesLeft.add(extrude34);
  const extrude35 = new THREE.Mesh(extrudeGeo4, stripeMat);
  extrude35.position.set(0, 0, 0.003);
  baseStripesLeft.add(extrude35);
  const extrude36 = new THREE.Mesh(extrudeGeo5, stripeMat);
  extrude36.position.set(0, 0, 0.003);
  baseStripesLeft.add(extrude36);
  const extrude37 = new THREE.Mesh(extrudeGeo6, stripeMat);
  extrude37.position.set(0, 0, 0.003);
  baseStripesLeft.add(extrude37);
  const extrude38 = new THREE.Mesh(extrudeGeo7, stripeMat);
  extrude38.position.set(0, 0, 0.003);
  baseStripesLeft.add(extrude38);
  const extrude39 = new THREE.Mesh(extrudeGeo8, stripeMat);
  extrude39.position.set(0, 0, 0.003);
  baseStripesLeft.add(extrude39);
  const cylinder40 = new THREE.Mesh(cylinderGeo, coilMat);
  cylinder40.position.set(-0.4, 0.15, -0.4);
  springBouncer.add(cylinder40);
  const cylinder41 = new THREE.Mesh(cylinderGeo, coilMat);
  cylinder41.position.set(0.4, 0.15, -0.4);
  springBouncer.add(cylinder41);
  const cylinder42 = new THREE.Mesh(cylinderGeo, coilMat);
  cylinder42.position.set(0.4, 0.15, 0.4);
  springBouncer.add(cylinder42);
  const cylinder43 = new THREE.Mesh(cylinderGeo, coilMat);
  cylinder43.position.set(-0.4, 0.15, 0.4);
  springBouncer.add(cylinder43);
  const seat = new THREE.Mesh(new THREE.CylinderGeometry(0.36, 0.38, 0.04, 12), darkMat);
  seat.name = 'seat';
  seat.position.set(0, 0.16, 0);
  springBouncer.add(seat);
  const coil = new THREE.Group();
  coil.name = 'coil';
  coil.position.set(0, 0.14, 0);
  springBouncer.add(coil);
  const wire = new THREE.Mesh(tube([[0.3, 0.06, 0], [0.2427, 0.0692, 0.1763], [0.0927, 0.0783, 0.2853], [-0.0927, 0.0875, 0.2853], [-0.2427, 0.0966, 0.1763], [-0.3, 0.1058, 0], [-0.2427, 0.1149, -0.1763], [-0.0927, 0.1241, -0.2853], [0.0927, 0.1332, -0.2853], [0.2427, 0.1424, -0.1763], [0.3, 0.1516, 0], [0.2427, 0.1607, 0.1763], [0.0927, 0.1699, 0.2853], [-0.0927, 0.179, 0.2853], [-0.2427, 0.1882, 0.1763], [-0.3, 0.1973, 0], [-0.2427, 0.2065, -0.1763], [-0.0927, 0.2156, -0.2853], [0.0927, 0.2248, -0.2853], [0.2427, 0.234, -0.1763], [0.3, 0.2431, 0], [0.2427, 0.2523, 0.1763], [0.0927, 0.2614, 0.2853], [-0.0927, 0.2706, 0.2853], [-0.2427, 0.2797, 0.1763], [-0.3, 0.2889, 0], [-0.2427, 0.298, -0.1763], [-0.0927, 0.3072, -0.2853], [0.0927, 0.3164, -0.2853], [0.2427, 0.3255, -0.1763], [0.3, 0.3347, 0], [0.2427, 0.3438, 0.1763], [0.0927, 0.353, 0.2853], [-0.0927, 0.3621, 0.2853], [-0.2427, 0.3713, 0.1763], [-0.3, 0.3804, 0], [-0.2427, 0.3896, -0.1763], [-0.0927, 0.3988, -0.2853], [0.0927, 0.4079, -0.2853], [0.2427, 0.4171, -0.1763], [0.3, 0.4262, 0], [0.2427, 0.4354, 0.1763], [0.0927, 0.4445, 0.2853], [-0.0927, 0.4537, 0.2853], [-0.2427, 0.4628, 0.1763], [-0.3, 0.472, 0]], 0.045, 63, 6), coilMat);
  wire.name = 'wire';
  coil.add(wire);
  const plate = new THREE.Group();
  plate.name = 'plate';
  plate.position.set(0, 0.672, 0);
  springBouncer.add(plate);
  const plateCap = new THREE.Mesh(new THREE.CylinderGeometry(0.36, 0.36, 0.05, 12), darkMat);
  plateCap.name = 'plateCap';
  plateCap.position.set(0, -0.005, 0);
  plate.add(plateCap);
  const plateBody = new THREE.Mesh(new THREE.BoxGeometry(0.9, 0.12, 0.9), plateMat);
  plateBody.name = 'plateBody';
  plateBody.position.set(0, 0.08, 0);
  plate.add(plateBody);
  const plateLip = new THREE.Mesh(new THREE.BoxGeometry(0.94, 0.04, 0.94), plateMat);
  plateLip.name = 'plateLip';
  plateLip.position.set(0, 0.08, 0);
  plate.add(plateLip);
  const plateTop = new THREE.Mesh(new THREE.BoxGeometry(0.78, 0.02, 0.78), plateTopMat);
  plateTop.name = 'plateTop';
  plateTop.position.set(0, 0.15, 0);
  plate.add(plateTop);
  const chevron1 = new THREE.Mesh(extrudeGeo9, arrowMat);
  chevron1.name = 'chevron1';
  chevron1.position.set(0, 0.167, -0.04);
  chevron1.rotation.set(deg(-90), 0, 0);
  plate.add(chevron1);
  const chevron2 = new THREE.Mesh(extrudeGeo9, arrowMat);
  chevron2.name = 'chevron2';
  chevron2.position.set(0, 0.167, -0.24);
  chevron2.rotation.set(deg(-90), 0, 0);
  plate.add(chevron2);

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

export default createSpring;

评分与评论

—
暂无评分,快来抢先评分吧。
5
0
4
0
3
0
2
0
1
0

登录后即可评分和评论。

0 条评论

暂无评论。分享一下你是如何使用这个模型的,或者有哪些可以改进的地方。

相关模型

同一分类或相似标签