Codels
1476 三角面0.19 × 0.09 × 0.23 m

在代码中使用

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

// 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 createGoggles() {
  const root = new THREE.Group();
  root.name = 'Goggles';

  // Materials
  const frameMat = new THREE.MeshStandardMaterial({ name: 'frame', color: 0xc99a3c, roughness: 0.32, metalness: 0.8, flatShading: true });
  const strapMat = new THREE.MeshStandardMaterial({ name: 'strap', color: 0x6b4527, roughness: 0.85, flatShading: true });
  const padMat = new THREE.MeshStandardMaterial({ name: 'pad', color: 0x3b2615, roughness: 0.9, flatShading: true });
  const lensMat = new THREE.MeshStandardMaterial({ name: 'lens', color: 0xe8762c, roughness: 0.08, metalness: 0.3, emissive: 0xe8762c, emissiveIntensity: 0.22 });
  const glintMat = new THREE.MeshStandardMaterial({ name: 'glint', color: 0xffffff, roughness: 0.2, emissive: 0xffffff, emissiveIntensity: 0.6, flatShading: true });
  const darkMat = new THREE.MeshStandardMaterial({ name: 'dark', color: 0x1d1a17, roughness: 0.9, flatShading: true });

  // Shared geometries
  const cylinderGeo = new THREE.CylinderGeometry(0.032, 0.036, 0.03, 12);
  const torusGeo = new THREE.TorusGeometry(0.032, 0.007, 4, 12);
  const cylinderGeo2 = new THREE.CylinderGeometry(0.037, 0.037, 0.014, 14);
  const torusGeo2 = new THREE.TorusGeometry(0.03, 0.0055, 4, 14);
  const sphereGeo = new THREE.SphereGeometry(0.028, 14, 3, 0, Math.PI * 2, 0, Math.PI / 2);
  const boxGeo = new THREE.BoxGeometry(0.016, 0.004, 0.002);
  const octahedronGeo = new THREE.OctahedronGeometry(0.0035, 0);
  const cylinderGeo3 = new THREE.CylinderGeometry(0.012, 0.012, 0.008, 8);
  const cylinderGeo4 = new THREE.CylinderGeometry(0.007, 0.007, 0.004, 8);
  const boxGeo2 = new THREE.BoxGeometry(0.008, 0.026, 0.016);

  // Parts
  const goggles = new THREE.Group();
  goggles.name = 'goggles';
  goggles.position.set(0, 0.0443, 0);
  root.add(goggles);
  const cupR = new THREE.Mesh(cylinderGeo, padMat);
  cupR.name = 'cupR';
  cupR.position.set(0.043, 0, 0.052);
  cupR.rotation.set(deg(90), 0, 0);
  goggles.add(cupR);
  const paddingR = new THREE.Mesh(torusGeo, padMat);
  paddingR.name = 'paddingR';
  paddingR.position.set(0.043, 0, 0.038);
  goggles.add(paddingR);
  const bezelR = new THREE.Mesh(cylinderGeo2, frameMat);
  bezelR.name = 'bezelR';
  bezelR.position.set(0.043, 0, 0.07);
  bezelR.rotation.set(deg(90), 0, 0);
  goggles.add(bezelR);
  const rimR = new THREE.Mesh(torusGeo2, frameMat);
  rimR.name = 'rimR';
  rimR.position.set(0.043, 0, 0.077);
  goggles.add(rimR);
  const lensR = new THREE.Mesh(sphereGeo, lensMat);
  lensR.name = 'lensR';
  lensR.position.set(0.043, 0, 0.075);
  lensR.rotation.set(deg(90), 0, 0);
  lensR.scale.set(1, 0.32, 1);
  goggles.add(lensR);
  const glintR = new THREE.Mesh(boxGeo, glintMat);
  glintR.name = 'glintR';
  glintR.position.set(0.033, 0.012, 0.0835);
  glintR.rotation.set(deg(-18), deg(16), deg(40));
  goggles.add(glintR);
  const rivetR1 = new THREE.Mesh(octahedronGeo, frameMat);
  rivetR1.name = 'rivetR1';
  rivetR1.position.set(0.0759, 0.019, 0.07);
  goggles.add(rivetR1);
  const rivetR2 = new THREE.Mesh(octahedronGeo, frameMat);
  rivetR2.name = 'rivetR2';
  rivetR2.position.set(0.043, 0.038, 0.07);
  goggles.add(rivetR2);
  const rivetR3 = new THREE.Mesh(octahedronGeo, frameMat);
  rivetR3.name = 'rivetR3';
  rivetR3.position.set(0.0101, 0.019, 0.07);
  goggles.add(rivetR3);
  const rivetR4 = new THREE.Mesh(octahedronGeo, frameMat);
  rivetR4.name = 'rivetR4';
  rivetR4.position.set(0.0101, -0.019, 0.07);
  goggles.add(rivetR4);
  const rivetR5 = new THREE.Mesh(octahedronGeo, frameMat);
  rivetR5.name = 'rivetR5';
  rivetR5.position.set(0.043, -0.038, 0.07);
  goggles.add(rivetR5);
  const rivetR6 = new THREE.Mesh(octahedronGeo, frameMat);
  rivetR6.name = 'rivetR6';
  rivetR6.position.set(0.0759, -0.019, 0.07);
  goggles.add(rivetR6);
  const ventR = new THREE.Mesh(cylinderGeo3, frameMat);
  ventR.name = 'ventR';
  ventR.position.set(0.08, 0, 0.054);
  ventR.rotation.set(0, 0, deg(90));
  goggles.add(ventR);
  const ventGrilleR = new THREE.Mesh(cylinderGeo4, darkMat);
  ventGrilleR.name = 'ventGrilleR';
  ventGrilleR.position.set(0.084, 0, 0.054);
  ventGrilleR.rotation.set(0, 0, deg(90));
  goggles.add(ventGrilleR);
  const cupL = new THREE.Mesh(cylinderGeo, padMat);
  cupL.name = 'cupL';
  cupL.position.set(-0.043, 0, 0.052);
  cupL.rotation.set(deg(90), 0, 0);
  goggles.add(cupL);
  const paddingL = new THREE.Mesh(torusGeo, padMat);
  paddingL.name = 'paddingL';
  paddingL.position.set(-0.043, 0, 0.038);
  goggles.add(paddingL);
  const bezelL = new THREE.Mesh(cylinderGeo2, frameMat);
  bezelL.name = 'bezelL';
  bezelL.position.set(-0.043, 0, 0.07);
  bezelL.rotation.set(deg(90), 0, 0);
  goggles.add(bezelL);
  const rimL = new THREE.Mesh(torusGeo2, frameMat);
  rimL.name = 'rimL';
  rimL.position.set(-0.043, 0, 0.077);
  goggles.add(rimL);
  const lensL = new THREE.Mesh(sphereGeo, lensMat);
  lensL.name = 'lensL';
  lensL.position.set(-0.043, 0, 0.075);
  lensL.rotation.set(deg(90), 0, 0);
  lensL.scale.set(1, 0.32, 1);
  goggles.add(lensL);
  const glintL = new THREE.Mesh(boxGeo, glintMat);
  glintL.name = 'glintL';
  glintL.position.set(-0.053, 0.012, 0.0835);
  glintL.rotation.set(deg(-18), deg(16), deg(40));
  goggles.add(glintL);
  const rivetL1 = new THREE.Mesh(octahedronGeo, frameMat);
  rivetL1.name = 'rivetL1';
  rivetL1.position.set(-0.0101, 0.019, 0.07);
  goggles.add(rivetL1);
  const rivetL2 = new THREE.Mesh(octahedronGeo, frameMat);
  rivetL2.name = 'rivetL2';
  rivetL2.position.set(-0.043, 0.038, 0.07);
  goggles.add(rivetL2);
  const rivetL3 = new THREE.Mesh(octahedronGeo, frameMat);
  rivetL3.name = 'rivetL3';
  rivetL3.position.set(-0.0759, 0.019, 0.07);
  goggles.add(rivetL3);
  const rivetL4 = new THREE.Mesh(octahedronGeo, frameMat);
  rivetL4.name = 'rivetL4';
  rivetL4.position.set(-0.0759, -0.019, 0.07);
  goggles.add(rivetL4);
  const rivetL5 = new THREE.Mesh(octahedronGeo, frameMat);
  rivetL5.name = 'rivetL5';
  rivetL5.position.set(-0.043, -0.038, 0.07);
  goggles.add(rivetL5);
  const rivetL6 = new THREE.Mesh(octahedronGeo, frameMat);
  rivetL6.name = 'rivetL6';
  rivetL6.position.set(-0.0101, -0.019, 0.07);
  goggles.add(rivetL6);
  const ventL = new THREE.Mesh(cylinderGeo3, frameMat);
  ventL.name = 'ventL';
  ventL.position.set(-0.08, 0, 0.054);
  ventL.rotation.set(0, 0, deg(90));
  goggles.add(ventL);
  const ventGrilleL = new THREE.Mesh(cylinderGeo4, darkMat);
  ventGrilleL.name = 'ventGrilleL';
  ventGrilleL.position.set(-0.084, 0, 0.054);
  ventGrilleL.rotation.set(0, 0, deg(90));
  goggles.add(ventGrilleL);
  const bridge = new THREE.Mesh(tube([[-0.015, 0.006, 0.07], [-0.012, 0.014, 0.074], [0.012, 0.014, 0.074], [0.015, 0.006, 0.07]], 0.0045, 8, 5), frameMat);
  bridge.name = 'bridge';
  goggles.add(bridge);
  const loupeHinge = new THREE.Mesh(new THREE.SphereGeometry(0.006, 6, 4), frameMat);
  loupeHinge.name = 'loupeHinge';
  loupeHinge.position.set(0.0675, 0.0245, 0.074);
  goggles.add(loupeHinge);
  const loupe = new THREE.Group();
  loupe.name = 'loupe';
  loupe.position.set(0.0675, 0.0245, 0.076);
  loupe.rotation.set(deg(-22), 0, deg(28));
  goggles.add(loupe);
  const loupeArm = new THREE.Mesh(new THREE.BoxGeometry(0.005, 0.034, 0.004), frameMat);
  loupeArm.name = 'loupeArm';
  loupeArm.position.set(0, -0.017, 0.006);
  loupe.add(loupeArm);
  const loupeRim = new THREE.Mesh(new THREE.TorusGeometry(0.015, 0.003, 4, 12), frameMat);
  loupeRim.name = 'loupeRim';
  loupeRim.position.set(-0.004, -0.036, 0.008);
  loupe.add(loupeRim);
  const loupeLens = new THREE.Mesh(new THREE.CylinderGeometry(0.0125, 0.0125, 0.002, 12), lensMat);
  loupeLens.name = 'loupeLens';
  loupeLens.position.set(-0.004, -0.036, 0.008);
  loupeLens.rotation.set(deg(90), 0, 0);
  loupe.add(loupeLens);
  const strapPivot = new THREE.Group();
  strapPivot.name = 'strapPivot';
  strapPivot.position.set(0, 0, 0.052);
  strapPivot.rotation.set(deg(-8), 0, 0);
  goggles.add(strapPivot);
  const strap = new THREE.Mesh(lathe([[0.088, -0.016], [0.092, -0.016], [0.092, 0.016], [0.088, 0.016], [0.088, -0.016]], 18, 0.9076, 4.468), strapMat);
  strap.name = 'strap';
  strap.position.set(0, 0, -0.065);
  strap.scale.set(1, 1, 1.15);
  strapPivot.add(strap);
  const buckle = new THREE.Mesh(new THREE.BoxGeometry(0.03, 0.04, 0.006), frameMat);
  buckle.name = 'buckle';
  buckle.position.set(0, 0, -0.1728);
  strapPivot.add(buckle);
  const buckleTongue = new THREE.Mesh(new THREE.BoxGeometry(0.018, 0.026, 0.008), strapMat);
  buckleTongue.name = 'buckleTongue';
  buckleTongue.position.set(0, 0, -0.1738);
  strapPivot.add(buckleTongue);
  const bracketR = new THREE.Mesh(boxGeo2, frameMat);
  bracketR.name = 'bracketR';
  bracketR.position.set(0.075, 0, 0.048);
  goggles.add(bracketR);
  const bracketL = new THREE.Mesh(boxGeo2, frameMat);
  bracketL.name = 'bracketL';
  bracketL.position.set(-0.075, 0, 0.048);
  goggles.add(bracketL);

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

export default createGoggles;

评分与评论

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

登录后即可评分和评论。

0 条评论

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

相关模型

同一分类或相似标签