삼각형 500개2.84 × 1.38 × 3.94 m
코드에서 사용하기
에디터에서 리믹스tent.js · 238줄
독립형 ES 모듈이에요 — three에만 의존해요. 팩토리 함수를 호출하고 그룹을 씬에 추가하세요.
/**
* Camping Tent — Codels 3D model library
* License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
* Triangles: 500 · Size (W × H × D): 2.83 × 1.38 × 3.94 m
*
* Usage:
* import { createTent } from './tent.js';
*
* const model = createTent();
* 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 createTent() {
const root = new THREE.Group();
root.name = 'Tent';
// Materials
const fabricMat = new THREE.MeshStandardMaterial({ name: 'fabric', color: 0xe07b2c, roughness: 0.85, flatShading: true });
const trimMat = new THREE.MeshStandardMaterial({ name: 'trim', color: 0x3c434b, roughness: 0.85, flatShading: true });
const insideMat = new THREE.MeshStandardMaterial({ name: 'inside', color: 0x2a2622, roughness: 1, flatShading: true });
const floorMat = new THREE.MeshStandardMaterial({ name: 'floor', color: 0x55634a, roughness: 0.95, flatShading: true });
const poleMat = new THREE.MeshStandardMaterial({ name: 'pole', color: 0xa9aeb3, roughness: 0.35, metalness: 0.6, flatShading: true });
const ropeMat = new THREE.MeshStandardMaterial({ name: 'rope', color: 0xe3d6b4, roughness: 0.9, flatShading: true });
// Shared geometries
const boxGeo = new THREE.BoxGeometry(1.5005, 0.025, 2.4);
const boxGeo2 = new THREE.BoxGeometry(0.2, 0.012, 2.41);
const capsuleGeo = new THREE.CapsuleGeometry(0.05, 0.8508, 2, 6);
const boxGeo3 = new THREE.BoxGeometry(0.03, 0.03, 0.12);
const cylinderGeo = new THREE.CylinderGeometry(0.02, 0.02, 1.34, 5);
const sphereGeo = new THREE.SphereGeometry(0.03, 5, 3);
const cylinderGeo2 = new THREE.CylinderGeometry(0.008, 0.008, 1.4872, 4);
const boxGeo4 = new THREE.BoxGeometry(0.035, 0.14, 0.035);
const cylinderGeo3 = new THREE.CylinderGeometry(0.008, 0.008, 1.1933, 4);
// Parts
const groundSheet = new THREE.Mesh(new THREE.BoxGeometry(1.95, 0.02, 2.36), floorMat);
groundSheet.name = 'groundSheet';
groundSheet.position.set(0, 0.01, 0);
root.add(groundSheet);
const panelLeft = new THREE.Mesh(boxGeo, fabricMat);
panelLeft.name = 'panelLeft';
panelLeft.position.set(-0.425, 0.616, 0);
panelLeft.rotation.set(0, 0, deg(54.6888));
root.add(panelLeft);
const band = new THREE.Mesh(boxGeo2, trimMat);
band.name = 'band';
band.position.set(-0.8053, 0.1069, 0);
band.rotation.set(0, 0, deg(54.6888));
root.add(band);
const panelRight = new THREE.Mesh(boxGeo, fabricMat);
panelRight.name = 'panelRight';
panelRight.position.set(0.425, 0.616, 0);
panelRight.rotation.set(0, 0, deg(-54.6888));
root.add(panelRight);
const band2 = new THREE.Mesh(boxGeo2, trimMat);
band2.name = 'band';
band2.position.set(0.8053, 0.1069, 0);
band2.rotation.set(0, 0, deg(-54.6888));
root.add(band2);
const ridgeSeam = new THREE.Mesh(new THREE.BoxGeometry(0.06, 0.05, 2.42), trimMat);
ridgeSeam.name = 'ridgeSeam';
ridgeSeam.position.set(0, 1.228, 0);
ridgeSeam.rotation.set(0, 0, deg(45));
root.add(ridgeSeam);
const frontPanel = new THREE.Mesh(extrude([[-0.82, 0], [-0.36, 0], [0, 0.88], [0.36, 0], [0.82, 0], [0, 1.16]], 0.02), fabricMat);
frontPanel.name = 'frontPanel';
frontPanel.position.set(0, 0.016, 1.08);
root.add(frontPanel);
const backPanel = new THREE.Mesh(extrude([[-0.82, 0], [0.82, 0], [0, 1.16]], 0.02), fabricMat);
backPanel.name = 'backPanel';
backPanel.position.set(0, 0.016, -1.08);
root.add(backPanel);
const interior = new THREE.Mesh(extrude([[-0.8, 0], [0.8, 0], [0, 1.13]], 0.01), insideMat);
interior.name = 'interior';
interior.position.set(0, 0.016, -1.05);
root.add(interior);
const rolledFlap = new THREE.Mesh(capsuleGeo, fabricMat);
rolledFlap.name = 'rolledFlap';
rolledFlap.position.set(-0.23, 0.44, 1.12);
rolledFlap.rotation.set(0, 0, deg(-22.249));
root.add(rolledFlap);
const tie = new THREE.Mesh(boxGeo3, trimMat);
tie.name = 'tie';
tie.position.set(-0.24, 0.44, 1.13);
root.add(tie);
const rolledFlap2 = new THREE.Mesh(capsuleGeo, fabricMat);
rolledFlap2.name = 'rolledFlap';
rolledFlap2.position.set(0.23, 0.44, 1.12);
rolledFlap2.rotation.set(0, 0, deg(22.249));
root.add(rolledFlap2);
const tie2 = new THREE.Mesh(boxGeo3, trimMat);
tie2.name = 'tie';
tie2.position.set(0.24, 0.44, 1.13);
root.add(tie2);
const pole = new THREE.Mesh(cylinderGeo, poleMat);
pole.name = 'pole';
pole.position.set(0, 0.67, -1.16);
root.add(pole);
const poleTip = new THREE.Mesh(sphereGeo, poleMat);
poleTip.name = 'poleTip';
poleTip.position.set(0, 1.35, -1.16);
root.add(poleTip);
const guyRope = new THREE.Group();
guyRope.name = 'guyRope';
guyRope.position.set(0, 0.04, -1.95);
root.add(guyRope);
const tilt = new THREE.Group();
tilt.name = 'tilt';
tilt.rotation.set(deg(32.0871), 0, 0);
guyRope.add(tilt);
const rope = new THREE.Mesh(cylinderGeo2, ropeMat);
rope.name = 'rope';
rope.position.set(0, 0.7436, 0);
tilt.add(rope);
const stake = new THREE.Mesh(boxGeo4, trimMat);
stake.name = 'stake';
stake.position.set(0, 0.07, -1.95);
root.add(stake);
const guyRope2 = new THREE.Group();
guyRope2.name = 'guyRope';
guyRope2.position.set(-1.4, 0.04, -0.9);
guyRope2.rotation.set(0, deg(81.8161), 0);
root.add(guyRope2);
const tilt2 = new THREE.Group();
tilt2.name = 'tilt';
tilt2.rotation.set(deg(62.0118), 0, 0);
guyRope2.add(tilt2);
const rope2 = new THREE.Mesh(cylinderGeo3, ropeMat);
rope2.name = 'rope';
rope2.position.set(0, 0.5966, 0);
tilt2.add(rope2);
const stake2 = new THREE.Mesh(boxGeo4, trimMat);
stake2.name = 'stake';
stake2.position.set(-1.4, 0.07, -0.9);
root.add(stake2);
const guyRope3 = new THREE.Group();
guyRope3.name = 'guyRope';
guyRope3.position.set(1.4, 0.04, -0.9);
guyRope3.rotation.set(0, deg(-81.8161), 0);
root.add(guyRope3);
const tilt3 = new THREE.Group();
tilt3.name = 'tilt';
tilt3.rotation.set(deg(62.0118), 0, 0);
guyRope3.add(tilt3);
const rope3 = new THREE.Mesh(cylinderGeo3, ropeMat);
rope3.name = 'rope';
rope3.position.set(0, 0.5966, 0);
tilt3.add(rope3);
const stake3 = new THREE.Mesh(boxGeo4, trimMat);
stake3.name = 'stake';
stake3.position.set(1.4, 0.07, -0.9);
root.add(stake3);
const pole2 = new THREE.Mesh(cylinderGeo, poleMat);
pole2.name = 'pole';
pole2.position.set(0, 0.67, 1.16);
root.add(pole2);
const poleTip2 = new THREE.Mesh(sphereGeo, poleMat);
poleTip2.name = 'poleTip';
poleTip2.position.set(0, 1.35, 1.16);
root.add(poleTip2);
const guyRope4 = new THREE.Group();
guyRope4.name = 'guyRope';
guyRope4.position.set(0, 0.04, 1.95);
guyRope4.rotation.set(0, deg(180), 0);
root.add(guyRope4);
const tilt4 = new THREE.Group();
tilt4.name = 'tilt';
tilt4.rotation.set(deg(32.0871), 0, 0);
guyRope4.add(tilt4);
const rope4 = new THREE.Mesh(cylinderGeo2, ropeMat);
rope4.name = 'rope';
rope4.position.set(0, 0.7436, 0);
tilt4.add(rope4);
const stake4 = new THREE.Mesh(boxGeo4, trimMat);
stake4.name = 'stake';
stake4.position.set(0, 0.07, 1.95);
root.add(stake4);
const guyRope5 = new THREE.Group();
guyRope5.name = 'guyRope';
guyRope5.position.set(-1.4, 0.04, 0.9);
guyRope5.rotation.set(0, deg(98.1839), 0);
root.add(guyRope5);
const tilt5 = new THREE.Group();
tilt5.name = 'tilt';
tilt5.rotation.set(deg(62.0118), 0, 0);
guyRope5.add(tilt5);
const rope5 = new THREE.Mesh(cylinderGeo3, ropeMat);
rope5.name = 'rope';
rope5.position.set(0, 0.5966, 0);
tilt5.add(rope5);
const stake5 = new THREE.Mesh(boxGeo4, trimMat);
stake5.name = 'stake';
stake5.position.set(-1.4, 0.07, 0.9);
root.add(stake5);
const guyRope6 = new THREE.Group();
guyRope6.name = 'guyRope';
guyRope6.position.set(1.4, 0.04, 0.9);
guyRope6.rotation.set(0, deg(-98.1839), 0);
root.add(guyRope6);
const tilt6 = new THREE.Group();
tilt6.name = 'tilt';
tilt6.rotation.set(deg(62.0118), 0, 0);
guyRope6.add(tilt6);
const rope6 = new THREE.Mesh(cylinderGeo3, ropeMat);
rope6.name = 'rope';
rope6.position.set(0, 0.5966, 0);
tilt6.add(rope6);
const stake6 = new THREE.Mesh(boxGeo4, trimMat);
stake6.name = 'stake';
stake6.position.set(1.4, 0.07, 0.9);
root.add(stake6);
root.traverse((o) => {
if (o.isMesh) {
o.castShadow = true;
o.receiveShadow = true;
}
});
return root;
}
export default createTent;
평점 및 댓글
댓글 0개
아직 댓글이 없어요. 이 모델을 어떻게 사용했는지, 어떤 점이 더 나아질 수 있을지 공유해 주세요.
관련 모델
같은 카테고리 또는 비슷한 태그









