삼각형 1.5천개1.20 × 2.28 × 1.25 m
코드에서 사용하기
에디터에서 리믹스cryo-pod.js · 257줄
독립형 ES 모듈이에요 — three에만 의존해요. 팩토리 함수를 호출하고 그룹을 씬에 추가하세요.
/**
* Cryo Pod — Codels 3D model library
* License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
* Triangles: 1,478 · Size (W × H × D): 1.20 × 2.28 × 1.25 m
*
* Usage:
* import { createCryoPod } from './cryo-pod.js';
*
* const model = createCryoPod();
* 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 createCryoPod() {
const root = new THREE.Group();
root.name = 'CryoPod';
// Materials
const shellMat = new THREE.MeshStandardMaterial({ name: 'shell', color: 0xd4dae1, roughness: 0.45, metalness: 0.3, flatShading: true });
const darkMat = new THREE.MeshStandardMaterial({ name: 'dark', color: 0x2f343c, roughness: 0.6, metalness: 0.35, flatShading: true });
const metalMat = new THREE.MeshStandardMaterial({ name: 'metal', color: 0x8a929c, roughness: 0.4, metalness: 0.6, flatShading: true });
const glowMat = new THREE.MeshStandardMaterial({ name: 'glow', color: 0x5ee2ff, roughness: 0.4, emissive: 0x5ee2ff, emissiveIntensity: 1.2, flatShading: true });
const innerMat = new THREE.MeshStandardMaterial({ name: 'inner', color: 0x2a3a46, roughness: 0.7, emissive: 0x5ee2ff, emissiveIntensity: 0.25, flatShading: true });
const glassMat = new THREE.MeshStandardMaterial({ name: 'glass', color: 0xdcf5ff, roughness: 0.15, metalness: 0.1, transparent: true, opacity: 0.55, side: THREE.DoubleSide });
const sleeperMat = new THREE.MeshStandardMaterial({ name: 'sleeper', color: 0xa9c4d2, roughness: 0.75, flatShading: true });
const redMat = new THREE.MeshStandardMaterial({ name: 'red', color: 0xff5a4a, roughness: 0.4, emissive: 0xff3b2f, emissiveIntensity: 1.2, flatShading: true });
const greenMat = new THREE.MeshStandardMaterial({ name: 'green', color: 0x8cff6a, roughness: 0.4, emissive: 0x66ff3c, emissiveIntensity: 1.1, flatShading: true });
// Shared geometries
const boxGeo = new THREE.BoxGeometry(0.04, 0.04, 0.02);
const boxGeo2 = new THREE.BoxGeometry(0.03, 1.2, 0.03);
const boxGeo3 = new THREE.BoxGeometry(0.1, 1.5, 0.14);
const boxGeo4 = new THREE.BoxGeometry(0.12, 0.12, 0.17);
const cylinderGeo = new THREE.CylinderGeometry(0.055, 0.055, 0.06, 6);
const capsuleGeo = new THREE.CapsuleGeometry(0.07, 0.62, 2, 5);
const capsuleGeo2 = new THREE.CapsuleGeometry(0.055, 0.5, 2, 5);
// Parts
const plinth = new THREE.Mesh(extrude([[-0.44, -0.56], [0.44, -0.56], [0.6, -0.4], [0.6, 0.4], [0.44, 0.56], [-0.44, 0.56], [-0.6, 0.4], [-0.6, -0.4]], 0.18), shellMat);
plinth.name = 'plinth';
plinth.position.set(0, 0.09, 0);
plinth.rotation.set(deg(90), 0, 0);
root.add(plinth);
const plinthTop = new THREE.Mesh(extrude([[-0.396, -0.504], [0.396, -0.504], [0.54, -0.36], [0.54, 0.36], [0.396, 0.504], [-0.396, 0.504], [-0.54, 0.36], [-0.54, -0.36]], 0.06), darkMat);
plinthTop.name = 'plinthTop';
plinthTop.position.set(0, 0.21, 0);
plinthTop.rotation.set(deg(90), 0, 0);
root.add(plinthTop);
const collar = new THREE.Mesh(new THREE.CylinderGeometry(0.52, 0.54, 0.12, 10), darkMat);
collar.name = 'collar';
collar.position.set(0, 0.3, 0);
root.add(collar);
const collarLight = new THREE.Mesh(new THREE.TorusGeometry(0.53, 0.014, 3, 10), glowMat);
collarLight.name = 'collarLight';
collarLight.position.set(0, 0.33, 0);
collarLight.rotation.set(deg(90), 0, 0);
root.add(collarLight);
const statusPanel = new THREE.Mesh(new THREE.BoxGeometry(0.5, 0.11, 0.03), darkMat);
statusPanel.name = 'statusPanel';
statusPanel.position.set(0, 0.1, 0.565);
root.add(statusPanel);
const statusDisplay = new THREE.Mesh(new THREE.BoxGeometry(0.16, 0.06, 0.02), glowMat);
statusDisplay.name = 'statusDisplay';
statusDisplay.position.set(-0.12, 0.1, 0.58);
root.add(statusDisplay);
const statusLight1 = new THREE.Mesh(boxGeo, greenMat);
statusLight1.name = 'statusLight1';
statusLight1.position.set(0.06, 0.1, 0.58);
root.add(statusLight1);
const statusLight2 = new THREE.Mesh(boxGeo, glowMat);
statusLight2.name = 'statusLight2';
statusLight2.position.set(0.125, 0.1, 0.58);
root.add(statusLight2);
const statusLight3 = new THREE.Mesh(boxGeo, redMat);
statusLight3.name = 'statusLight3';
statusLight3.position.set(0.19, 0.1, 0.58);
root.add(statusLight3);
const backShell = new THREE.Mesh(lathe([[0.46, 0.36], [0.46, 1.78], [0.4048, 2], [0.2392, 2.15], [0.001, 2.2], [0.001, 2.15], [0.1892, 2.1], [0.3548, 1.95], [0.41, 1.73], [0.41, 0.36]], 8, Math.PI / 2, Math.PI), shellMat);
backShell.name = 'backShell';
root.add(backShell);
const innerLining = new THREE.Mesh(lathe([[0.001, 2.15], [0.1792, 2.1], [0.3448, 1.95], [0.4, 1.73], [0.4, 0.36]], 8, Math.PI / 2, Math.PI), innerMat);
innerLining.name = 'innerLining';
root.add(innerLining);
const innerStripL = new THREE.Mesh(boxGeo2, glowMat);
innerStripL.name = 'innerStripL';
innerStripL.position.set(-0.2, 1.15, -0.33);
innerStripL.rotation.set(0, deg(-25), 0);
root.add(innerStripL);
const innerStripR = new THREE.Mesh(boxGeo2, glowMat);
innerStripR.name = 'innerStripR';
innerStripR.position.set(0.2, 1.15, -0.33);
innerStripR.rotation.set(0, deg(25), 0);
root.add(innerStripR);
const headRest = new THREE.Mesh(new THREE.BoxGeometry(0.3, 0.06, 0.1), darkMat);
headRest.name = 'headRest';
headRest.position.set(0, 1.96, -0.33);
root.add(headRest);
const railL = new THREE.Mesh(boxGeo3, shellMat);
railL.name = 'railL';
railL.position.set(-0.48, 1.11, 0);
root.add(railL);
const railLightL = new THREE.Mesh(boxGeo2, glowMat);
railLightL.name = 'railLightL';
railLightL.position.set(-0.535, 1.11, 0);
root.add(railLightL);
const hingeTopL = new THREE.Mesh(boxGeo4, darkMat);
hingeTopL.name = 'hingeTopL';
hingeTopL.position.set(-0.48, 1.84, 0);
root.add(hingeTopL);
const railR = new THREE.Mesh(boxGeo3, shellMat);
railR.name = 'railR';
railR.position.set(0.48, 1.11, 0);
root.add(railR);
const railLightR = new THREE.Mesh(boxGeo2, glowMat);
railLightR.name = 'railLightR';
railLightR.position.set(0.535, 1.11, 0);
root.add(railLightR);
const hingeTopR = new THREE.Mesh(boxGeo4, darkMat);
hingeTopR.name = 'hingeTopR';
hingeTopR.position.set(0.48, 1.84, 0);
root.add(hingeTopR);
const sideScreenFrame = new THREE.Mesh(new THREE.BoxGeometry(0.2, 0.26, 0.03), darkMat);
sideScreenFrame.name = 'sideScreenFrame';
sideScreenFrame.position.set(-0.2573, 1.2, -0.3851);
sideScreenFrame.rotation.set(deg(-180), deg(-33.75), deg(-180));
root.add(sideScreenFrame);
const sideScreen = new THREE.Mesh(new THREE.BoxGeometry(0.15, 0.2, 0.02), glowMat);
sideScreen.name = 'sideScreen';
sideScreen.position.set(-0.2651, 1.2, -0.3967);
sideScreen.rotation.set(deg(-180), deg(-33.75), deg(-180));
root.add(sideScreen);
const topVent = new THREE.Mesh(new THREE.CylinderGeometry(0.16, 0.2, 0.08, 8), darkMat);
topVent.name = 'topVent';
topVent.position.set(0, 2.21, -0.05);
root.add(topVent);
const topLight = new THREE.Mesh(new THREE.CylinderGeometry(0.1, 0.1, 0.03, 8), glowMat);
topLight.name = 'topLight';
topLight.position.set(0, 2.265, -0.05);
root.add(topLight);
const pipeL = new THREE.Mesh(tube([[-0.14, 2, -0.3], [-0.2, 1.9, -0.58], [-0.22, 1.2, -0.6], [-0.22, 0.45, -0.6], [-0.2, 0.2, -0.5]], 0.035, 8, 5), metalMat);
pipeL.name = 'pipeL';
root.add(pipeL);
const pipeClampL = new THREE.Mesh(cylinderGeo, darkMat);
pipeClampL.name = 'pipeClampL';
pipeClampL.position.set(-0.22, 1.2, -0.6);
root.add(pipeClampL);
const pipeR = new THREE.Mesh(tube([[0.14, 2, -0.3], [0.2, 1.9, -0.58], [0.22, 1.2, -0.6], [0.22, 0.45, -0.6], [0.2, 0.2, -0.5]], 0.035, 8, 5), metalMat);
pipeR.name = 'pipeR';
root.add(pipeR);
const pipeClampR = new THREE.Mesh(cylinderGeo, darkMat);
pipeClampR.name = 'pipeClampR';
pipeClampR.position.set(0.22, 1.2, -0.6);
root.add(pipeClampR);
const coolantBox = new THREE.Mesh(new THREE.BoxGeometry(0.34, 0.5, 0.12), darkMat);
coolantBox.name = 'coolantBox';
coolantBox.position.set(0, 1, -0.5);
root.add(coolantBox);
const coolantLight = new THREE.Mesh(new THREE.BoxGeometry(0.22, 0.04, 0.02), glowMat);
coolantLight.name = 'coolantLight';
coolantLight.position.set(0, 1.12, -0.565);
coolantLight.rotation.set(0, deg(180), 0);
root.add(coolantLight);
const sleeper = new THREE.Group();
sleeper.name = 'sleeper';
sleeper.position.set(0, 0, -0.08);
root.add(sleeper);
const legL = new THREE.Mesh(capsuleGeo, sleeperMat);
legL.name = 'legL';
legL.position.set(-0.09, 0.79, 0);
sleeper.add(legL);
const armL = new THREE.Mesh(capsuleGeo2, sleeperMat);
armL.name = 'armL';
armL.position.set(-0.23, 1.35, 0.02);
armL.rotation.set(0, 0, deg(-6));
sleeper.add(armL);
const legR = new THREE.Mesh(capsuleGeo, sleeperMat);
legR.name = 'legR';
legR.position.set(0.09, 0.79, 0);
sleeper.add(legR);
const armR = new THREE.Mesh(capsuleGeo2, sleeperMat);
armR.name = 'armR';
armR.position.set(0.23, 1.35, 0.02);
armR.rotation.set(0, 0, deg(6));
sleeper.add(armR);
const torso = new THREE.Mesh(new THREE.CapsuleGeometry(0.15, 0.32, 2, 7), sleeperMat);
torso.name = 'torso';
torso.position.set(0, 1.42, 0);
torso.scale.set(1, 1, 0.7);
sleeper.add(torso);
const neck = new THREE.Mesh(new THREE.CylinderGeometry(0.05, 0.06, 0.08, 6), sleeperMat);
neck.name = 'neck';
neck.position.set(0, 1.74, 0);
sleeper.add(neck);
const head = new THREE.Mesh(new THREE.SphereGeometry(0.11, 6, 5), sleeperMat);
head.name = 'head';
head.position.set(0, 1.86, 0.01);
sleeper.add(head);
const door = new THREE.Group();
door.name = 'door';
door.position.set(0.46, 0, 0);
root.add(door);
const glassDoor = new THREE.Mesh(lathe([[0.44, 0.4], [0.44, 1.76], [0.3848, 1.98], [0.2192, 2.13], [0.001, 2.18]], 8, -Math.PI / 2, Math.PI), glassMat);
glassDoor.name = 'glassDoor';
glassDoor.position.set(-0.46, 0, 0);
door.add(glassDoor);
const doorFrame = new THREE.Mesh(tube([[-0.02, 0.4, 0], [-0.02, 1.76, 0], [-0.0752, 1.98, 0], [-0.2408, 2.13, 0], [-0.459, 2.18, 0], [-0.6792, 2.13, 0], [-0.8448, 1.98, 0], [-0.9, 1.76, 0], [-0.9, 0.4, 0]], 0.025, 16, 4), darkMat);
doorFrame.name = 'doorFrame';
door.add(doorFrame);
const frostBand = new THREE.Mesh(lathe([[0.448, 0.41], [0.448, 0.62], [0.448, 0.8]], 8, -Math.PI / 2, Math.PI), glassMat);
frostBand.name = 'frostBand';
frostBand.position.set(-0.46, 0, 0);
door.add(frostBand);
const doorSill = new THREE.Mesh(new THREE.TorusGeometry(0.44, 0.03, 3, 8, Math.PI), darkMat);
doorSill.name = 'doorSill';
doorSill.position.set(-0.46, 0.4, 0);
doorSill.rotation.set(deg(90), 0, 0);
door.add(doorSill);
const handle = new THREE.Mesh(new THREE.BoxGeometry(0.04, 0.32, 0.05), metalMat);
handle.name = 'handle';
handle.position.set(-0.76, 1.2, 0.34);
door.add(handle);
root.traverse((o) => {
if (o.isMesh) {
o.castShadow = true;
o.receiveShadow = true;
}
});
return root;
}
export default createCryoPod;
평점 및 댓글
댓글 0개
아직 댓글이 없어요. 이 모델을 어떻게 사용했는지, 어떤 점이 더 나아질 수 있을지 공유해 주세요.
관련 모델
같은 카테고리 또는 비슷한 태그









