삼각형 1.4천개0.31 × 0.30 × 0.20 m
코드에서 사용하기
에디터에서 리믹스trophy-cup.js · 105줄
독립형 ES 모듈이에요 — three에만 의존해요. 팩토리 함수를 호출하고 그룹을 씬에 추가하세요.
/**
* Trophy Cup — Codels 3D model library
* License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the model (it floats — pickups, planets)
* Triangles: 1,388 · Size (W × H × D): 0.31 × 0.30 × 0.20 m
*
* Usage:
* import { createTrophyCup } from './trophy-cup.js';
*
* const model = createTrophyCup();
* 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);
}
// 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 createTrophyCup() {
const root = new THREE.Group();
root.name = 'TrophyCup';
// Materials
const goldMat = new THREE.MeshStandardMaterial({ name: 'gold', color: 0xf4bf3a, roughness: 0.28, metalness: 0.85, flatShading: true });
const embossMat = new THREE.MeshStandardMaterial({ name: 'emboss', color: 0xf7d275, roughness: 0.25, metalness: 0.8, flatShading: true });
const insideMat = new THREE.MeshStandardMaterial({ name: 'inside', color: 0xb78f2c, roughness: 0.35, metalness: 0.85, flatShading: true });
const plinthMat = new THREE.MeshStandardMaterial({ name: 'plinth', color: 0x2f2a33, roughness: 0.55, metalness: 0.1, flatShading: true });
// Parts
const trophy = new THREE.Group();
trophy.name = 'trophy';
trophy.position.set(0, -0.15, 0);
trophy.scale.setScalar(1.3636);
root.add(trophy);
const plinth = new THREE.Mesh(new THREE.BoxGeometry(0.12, 0.034, 0.12), plinthMat);
plinth.name = 'plinth';
plinth.position.set(0, 0.017, 0);
trophy.add(plinth);
const plinthStep = new THREE.Mesh(new THREE.BoxGeometry(0.1, 0.016, 0.1), plinthMat);
plinthStep.name = 'plinthStep';
plinthStep.position.set(0, 0.042, 0);
trophy.add(plinthStep);
const plaque = new THREE.Mesh(new THREE.BoxGeometry(0.07, 0.02, 0.003), goldMat);
plaque.name = 'plaque';
plaque.position.set(0, 0.017, 0.061);
trophy.add(plaque);
const plaqueText = new THREE.Mesh(new THREE.BoxGeometry(0.05, 0.004, 0.002), embossMat);
plaqueText.name = 'plaqueText';
plaqueText.position.set(0, 0.019, 0.0625);
trophy.add(plaqueText);
const stem = new THREE.Mesh(lathe([[0, 0.05], [0.046, 0.05], [0.048, 0.056], [0.04, 0.062], [0.02, 0.068], [0.012, 0.076], [0.011, 0.086], [0.02, 0.092], [0.011, 0.098], [0.012, 0.108], [0, 0.11]], 16), goldMat);
stem.name = 'stem';
trophy.add(stem);
const bowl = new THREE.Mesh(lathe([[0, 0.106], [0.016, 0.106], [0.032, 0.118], [0.05, 0.14], [0.063, 0.171], [0.069, 0.2], [0.074, 0.212], [0.073, 0.218], [0.066, 0.216], [0.061, 0.202], [0.056, 0.174], [0.044, 0.146], [0.024, 0.13], [0, 0.126]], 16), goldMat);
bowl.name = 'bowl';
trophy.add(bowl);
const bowlInside = new THREE.Mesh(new THREE.CylinderGeometry(0.04, 0.04, 0.002, 16), insideMat);
bowlInside.name = 'bowlInside';
bowlInside.position.set(0, 0.132, 0);
trophy.add(bowlInside);
const band = new THREE.Mesh(lathe([[0.0618, 0.17], [0.0668, 0.171], [0.0683, 0.176], [0.0668, 0.181], [0.0618, 0.182]], 16), embossMat);
band.name = 'band';
trophy.add(band);
const handleR = new THREE.Mesh(tube([[0.064, 0.194, 0], [0.094, 0.2, 0], [0.108, 0.176, 0], [0.094, 0.146, 0], [0.062, 0.136, 0], [0.045, 0.136, 0]], 0.0065, 14, 6), goldMat);
handleR.name = 'handleR';
trophy.add(handleR);
const handleL = new THREE.Mesh(tube([[-0.064, 0.194, 0], [-0.094, 0.2, 0], [-0.108, 0.176, 0], [-0.094, 0.146, 0], [-0.062, 0.136, 0], [-0.045, 0.136, 0]], 0.0065, 14, 6), goldMat);
handleL.name = 'handleL';
trophy.add(handleL);
const star = new THREE.Mesh(extrude([[0, 0.02], [-0.0047, 0.0065], [-0.019, 0.0062], [-0.0076, -0.0025], [-0.0118, -0.0162], [0, -0.008], [0.0118, -0.0162], [0.0076, -0.0025], [0.019, 0.0062], [0.0047, 0.0065]], 0.004, [], [0.0012, 0.0012, 1]), embossMat);
star.name = 'star';
star.position.set(0, 0.156, 0.058);
star.rotation.set(deg(22.751), 0, 0);
trophy.add(star);
root.traverse((o) => {
if (o.isMesh) {
o.castShadow = true;
o.receiveShadow = true;
}
});
return root;
}
export default createTrophyCup;
평점 및 댓글
댓글 0개
아직 댓글이 없어요. 이 모델을 어떻게 사용했는지, 어떤 점이 더 나아질 수 있을지 공유해 주세요.
관련 모델
같은 카테고리 또는 비슷한 태그









