236 三角面0.07 × 0.76 × 0.05 m
在代码中使用
在编辑器中改编arrow.js · 99 行
自包含的 ES 模块,仅依赖 three。调用工厂函数,然后把返回的 group 添加到场景中。
/**
* Arrow — Codels 3D model library
* License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
* Triangles: 236 · Size (W × H × D): 0.07 × 0.76 × 0.05 m
*
* Usage:
* import { createArrow } from './arrow.js';
*
* const model = createArrow();
* 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);
}
export function createArrow() {
const root = new THREE.Group();
root.name = 'Arrow';
// Materials
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 });
const cockMat = new THREE.MeshStandardMaterial({ name: 'cock', color: 0xf1ece0, roughness: 0.9, flatShading: true, side: THREE.DoubleSide });
const threadMat = new THREE.MeshStandardMaterial({ name: 'thread', color: 0x3d2a1c, roughness: 0.9, flatShading: true });
// Shared geometries
const boxGeo = new THREE.BoxGeometry(0.004, 0.012, 0.012);
const extrudeGeo = extrude([[0.0038, 0.04], [0.03, 0.052], [0.034, 0.1308], [0.022, 0.1803], [0.0038, 0.205]], 0.0025);
const cylinderGeo = new THREE.CylinderGeometry(0.0093, 0.0093, 0.012, 6);
// Parts
const nock = new THREE.Mesh(new THREE.CylinderGeometry(0.0095, 0.0085, 0.022, 6), threadMat);
nock.name = 'nock';
nock.position.set(0, 0.011, 0);
root.add(nock);
const nockProngR = new THREE.Mesh(boxGeo, threadMat);
nockProngR.name = 'nockProngR';
nockProngR.position.set(0.0052, 0.022, 0);
root.add(nockProngR);
const nockProngL = new THREE.Mesh(boxGeo, threadMat);
nockProngL.name = 'nockProngL';
nockProngL.position.set(-0.0052, 0.022, 0);
root.add(nockProngL);
const shaft = new THREE.Mesh(new THREE.CylinderGeometry(0.0075, 0.0075, 0.64, 6), shaftMat);
shaft.name = 'shaft';
shaft.position.set(0, 0.34, 0);
root.add(shaft);
const vane1 = new THREE.Mesh(extrudeGeo, cockMat);
vane1.name = 'vane1';
vane1.rotation.set(0, deg(90), 0);
root.add(vane1);
const vane2 = new THREE.Mesh(extrudeGeo, featherMat);
vane2.name = 'vane2';
vane2.rotation.set(0, deg(210), 0);
root.add(vane2);
const vane3 = new THREE.Mesh(extrudeGeo, featherMat);
vane3.name = 'vane3';
vane3.rotation.set(0, deg(330), 0);
root.add(vane3);
const binding1 = new THREE.Mesh(cylinderGeo, threadMat);
binding1.name = 'binding1';
binding1.position.set(0, 0.034, 0);
root.add(binding1);
const binding2 = new THREE.Mesh(cylinderGeo, threadMat);
binding2.name = 'binding2';
binding2.position.set(0, 0.211, 0);
root.add(binding2);
const socket = new THREE.Mesh(new THREE.CylinderGeometry(0.0105, 0.0085, 0.035, 6), steelMat);
socket.name = 'socket';
socket.position.set(0, 0.6455, 0);
root.add(socket);
const head = new THREE.Mesh(extrude([[0, 0], [0.03, 0.025], [0.026, 0.055], [0, 0.11], [-0.026, 0.055], [-0.03, 0.025]], 0.002, [], [0.004, 0.003, 1]), steelMat);
head.name = 'head';
head.position.set(0, 0.65, 0);
root.add(head);
root.traverse((o) => {
if (o.isMesh) {
o.castShadow = true;
o.receiveShadow = true;
}
});
return root;
}
export default createArrow;
评分与评论
0 条评论
暂无评论。分享一下你是如何使用这个模型的,或者有哪些可以改进的地方。
相关模型
同一分类或相似标签









