Codels
삼각형 664개0.86 × 1.50 × 0.64 m

코드에서 사용하기

에디터에서 리믹스
독립형 ES 모듈이에요 — three에만 의존해요. 팩토리 함수를 호출하고 그룹을 씬에 추가하세요.
/**
 * Skeleton Warrior — Codels 3D model library
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 664 · Size (W × H × D): 0.86 × 1.50 × 0.64 m
 *
 * Usage:
 *   import { createSkeletonWarrior } from './skeleton-warrior.js';
 *   
 *   const model = createSkeletonWarrior();
 *   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 createSkeletonWarrior() {
  const root = new THREE.Group();
  root.name = 'SkeletonWarrior';

  // Materials
  const boneMat = new THREE.MeshStandardMaterial({ name: 'bone', color: 0xebe3cf, roughness: 0.75, flatShading: true });
  const jointMat = new THREE.MeshStandardMaterial({ name: 'joint', color: 0xcac3b2, roughness: 0.8, flatShading: true });
  const socketMat = new THREE.MeshStandardMaterial({ name: 'socket', color: 0x2b2329, roughness: 0.9, flatShading: true });
  const glowMat = new THREE.MeshStandardMaterial({ name: 'glow', color: 0xff5a3c, roughness: 0.4, emissive: 0xff5a3c, emissiveIntensity: 1.6, flatShading: true });
  const steelMat = new THREE.MeshStandardMaterial({ name: 'steel', color: 0xb4bcc6, roughness: 0.3, metalness: 0.7, flatShading: true });
  const ironMat = new THREE.MeshStandardMaterial({ name: 'iron', color: 0x585c66, roughness: 0.55, metalness: 0.5, flatShading: true });
  const woodMat = new THREE.MeshStandardMaterial({ name: 'wood', color: 0x83582f, roughness: 0.85, flatShading: true });
  const leatherMat = new THREE.MeshStandardMaterial({ name: 'leather', color: 0x5b3a28, roughness: 0.8, flatShading: true });

  // Shared geometries
  const boxGeo = new THREE.BoxGeometry(0.075, 0.24, 0.075);
  const boxGeo2 = new THREE.BoxGeometry(0.11, 0.075, 0.11);
  const boxGeo3 = new THREE.BoxGeometry(0.07, 0.22, 0.07);
  const boxGeo4 = new THREE.BoxGeometry(0.13, 0.065, 0.2);
  const boxGeo5 = new THREE.BoxGeometry(0.11, 0.1, 0.11);
  const boxGeo6 = new THREE.BoxGeometry(0.065, 0.2, 0.065);
  const boxGeo7 = new THREE.BoxGeometry(0.09, 0.07, 0.09);
  const boxGeo8 = new THREE.BoxGeometry(0.06, 0.18, 0.06);
  const boxGeo9 = new THREE.BoxGeometry(0.1, 0.1, 0.1);
  const boxGeo10 = new THREE.BoxGeometry(0.008, 0.05, 0.008);
  const boxGeo11 = new THREE.BoxGeometry(0.1, 0.1, 0.02);
  const boxGeo12 = new THREE.BoxGeometry(0.04, 0.04, 0.01);

  // Parts
  const legL = new THREE.Group();
  legL.name = 'legL';
  legL.position.set(0.1, 0.6, 0);
  root.add(legL);
  const thighL = new THREE.Mesh(boxGeo, boneMat);
  thighL.name = 'thighL';
  thighL.position.set(0, -0.14, 0);
  legL.add(thighL);
  const kneeL = new THREE.Mesh(boxGeo2, jointMat);
  kneeL.name = 'kneeL';
  kneeL.position.set(0, -0.29, 0);
  legL.add(kneeL);
  const shinL = new THREE.Mesh(boxGeo3, boneMat);
  shinL.name = 'shinL';
  shinL.position.set(0, -0.43, 0);
  legL.add(shinL);
  const footL = new THREE.Mesh(boxGeo4, boneMat);
  footL.name = 'footL';
  footL.position.set(0, -0.5675, 0.035);
  legL.add(footL);
  const legR = new THREE.Group();
  legR.name = 'legR';
  legR.position.set(-0.1, 0.6, 0);
  root.add(legR);
  const thighR = new THREE.Mesh(boxGeo, boneMat);
  thighR.name = 'thighR';
  thighR.position.set(0, -0.14, 0);
  legR.add(thighR);
  const kneeR = new THREE.Mesh(boxGeo2, jointMat);
  kneeR.name = 'kneeR';
  kneeR.position.set(0, -0.29, 0);
  legR.add(kneeR);
  const shinR = new THREE.Mesh(boxGeo3, boneMat);
  shinR.name = 'shinR';
  shinR.position.set(0, -0.43, 0);
  legR.add(shinR);
  const footR = new THREE.Mesh(boxGeo4, boneMat);
  footR.name = 'footR';
  footR.position.set(0, -0.5675, 0.035);
  legR.add(footR);
  const body = new THREE.Group();
  body.name = 'body';
  root.add(body);
  const pelvis = new THREE.Mesh(new THREE.BoxGeometry(0.3, 0.1, 0.15), boneMat);
  pelvis.name = 'pelvis';
  pelvis.position.set(0, 0.62, 0);
  body.add(pelvis);
  const spine = new THREE.Mesh(new THREE.BoxGeometry(0.065, 0.42, 0.065), jointMat);
  spine.name = 'spine';
  spine.position.set(0, 0.85, -0.04);
  body.add(spine);
  const rib1 = new THREE.Mesh(new THREE.BoxGeometry(0.304, 0.04, 0.2), boneMat);
  rib1.name = 'rib1';
  rib1.position.set(0, 0.8, -0.005);
  body.add(rib1);
  const rib2 = new THREE.Mesh(new THREE.BoxGeometry(0.334, 0.04, 0.2), boneMat);
  rib2.name = 'rib2';
  rib2.position.set(0, 0.87, -0.005);
  body.add(rib2);
  const rib3 = new THREE.Mesh(new THREE.BoxGeometry(0.316, 0.04, 0.2), boneMat);
  rib3.name = 'rib3';
  rib3.position.set(0, 0.94, -0.005);
  body.add(rib3);
  const rib4 = new THREE.Mesh(new THREE.BoxGeometry(0.286, 0.04, 0.2), boneMat);
  rib4.name = 'rib4';
  rib4.position.set(0, 1.01, -0.005);
  body.add(rib4);
  const sternum = new THREE.Mesh(new THREE.BoxGeometry(0.05, 0.25, 0.03), boneMat);
  sternum.name = 'sternum';
  sternum.position.set(0, 0.91, 0.1);
  body.add(sternum);
  const collarbone = new THREE.Mesh(new THREE.BoxGeometry(0.44, 0.06, 0.12), boneMat);
  collarbone.name = 'collarbone';
  collarbone.position.set(0, 1.1, -0.01);
  body.add(collarbone);
  const belt = new THREE.Mesh(new THREE.BoxGeometry(0.32, 0.05, 0.17), leatherMat);
  belt.name = 'belt';
  belt.position.set(0, 0.675, 0);
  body.add(belt);
  const loincloth = new THREE.Mesh(new THREE.BoxGeometry(0.14, 0.16, 0.02), leatherMat);
  loincloth.name = 'loincloth';
  loincloth.position.set(0, 0.56, 0.085);
  body.add(loincloth);
  const armL = new THREE.Group();
  armL.name = 'armL';
  armL.position.set(0.25, 1.1, -0.01);
  armL.rotation.set(deg(6), 0, deg(8));
  root.add(armL);
  const shoulderL = new THREE.Mesh(boxGeo5, jointMat);
  shoulderL.name = 'shoulderL';
  armL.add(shoulderL);
  const upperArmL = new THREE.Mesh(boxGeo6, boneMat);
  upperArmL.name = 'upperArmL';
  upperArmL.position.set(0, -0.14, 0);
  armL.add(upperArmL);
  const forearmL = new THREE.Group();
  forearmL.name = 'forearmL';
  forearmL.position.set(0, -0.26, 0);
  forearmL.rotation.set(deg(-35), 0, 0);
  armL.add(forearmL);
  const elbowL = new THREE.Mesh(boxGeo7, jointMat);
  elbowL.name = 'elbowL';
  forearmL.add(elbowL);
  const lowerArmL = new THREE.Mesh(boxGeo8, boneMat);
  lowerArmL.name = 'lowerArmL';
  lowerArmL.position.set(0, -0.12, 0);
  forearmL.add(lowerArmL);
  const handL = new THREE.Mesh(boxGeo9, boneMat);
  handL.name = 'handL';
  handL.position.set(0, -0.25, 0);
  forearmL.add(handL);
  const shield = new THREE.Group();
  shield.name = 'shield';
  shield.position.set(0.08, -0.15, 0.02);
  forearmL.add(shield);
  const shieldBoard = new THREE.Mesh(new THREE.CylinderGeometry(0.21, 0.21, 0.045, 10), woodMat);
  shieldBoard.name = 'shieldBoard';
  shieldBoard.rotation.set(0, 0, deg(90));
  shield.add(shieldBoard);
  const shieldRim = new THREE.Mesh(new THREE.CylinderGeometry(0.215, 0.215, 0.03, 10, 1, false), ironMat);
  shieldRim.name = 'shieldRim';
  shieldRim.rotation.set(0, 0, deg(90));
  shieldRim.scale.set(1, 1.2, 1);
  shield.add(shieldRim);
  const shieldBoss = new THREE.Mesh(new THREE.CylinderGeometry(0.06, 0.07, 0.04, 8), ironMat);
  shieldBoss.name = 'shieldBoss';
  shieldBoss.position.set(0.04, 0, 0);
  shieldBoss.rotation.set(0, 0, deg(90));
  shield.add(shieldBoss);
  const shieldBand = new THREE.Mesh(new THREE.BoxGeometry(0.05, 0.4, 0.04), ironMat);
  shieldBand.name = 'shieldBand';
  shieldBand.position.set(0.025, 0, 0);
  shield.add(shieldBand);
  const armR = new THREE.Group();
  armR.name = 'armR';
  armR.position.set(-0.25, 1.1, -0.01);
  armR.rotation.set(deg(10), 0, deg(-8));
  root.add(armR);
  const shoulderR = new THREE.Mesh(boxGeo5, jointMat);
  shoulderR.name = 'shoulderR';
  armR.add(shoulderR);
  const upperArmR = new THREE.Mesh(boxGeo6, boneMat);
  upperArmR.name = 'upperArmR';
  upperArmR.position.set(0, -0.14, 0);
  armR.add(upperArmR);
  const forearmR = new THREE.Group();
  forearmR.name = 'forearmR';
  forearmR.position.set(0, -0.26, 0);
  forearmR.rotation.set(deg(-80), 0, 0);
  armR.add(forearmR);
  const elbowR = new THREE.Mesh(boxGeo7, jointMat);
  elbowR.name = 'elbowR';
  forearmR.add(elbowR);
  const lowerArmR = new THREE.Mesh(boxGeo8, boneMat);
  lowerArmR.name = 'lowerArmR';
  lowerArmR.position.set(0, -0.12, 0);
  forearmR.add(lowerArmR);
  const handR = new THREE.Mesh(boxGeo9, boneMat);
  handR.name = 'handR';
  handR.position.set(0, -0.25, 0);
  forearmR.add(handR);
  const weapon = new THREE.Group();
  weapon.name = 'weapon';
  weapon.position.set(0, -0.25, 0);
  weapon.rotation.set(deg(95), 0, 0);
  forearmR.add(weapon);
  const grip = new THREE.Mesh(new THREE.BoxGeometry(0.04, 0.16, 0.04), leatherMat);
  grip.name = 'grip';
  weapon.add(grip);
  const pommel = new THREE.Mesh(new THREE.BoxGeometry(0.055, 0.05, 0.055), ironMat);
  pommel.name = 'pommel';
  pommel.position.set(0, -0.1, 0);
  weapon.add(pommel);
  const crossguard = new THREE.Mesh(new THREE.BoxGeometry(0.24, 0.045, 0.06), ironMat);
  crossguard.name = 'crossguard';
  crossguard.position.set(0, 0.1, 0);
  weapon.add(crossguard);
  const blade = new THREE.Mesh(extrude([[-0.035, 0], [0.035, 0], [0.035, 0.5], [0, 0.58], [-0.035, 0.5]], 0.02), steelMat);
  blade.name = 'blade';
  blade.position.set(0, 0.12, 0);
  weapon.add(blade);
  const fuller = new THREE.Mesh(new THREE.BoxGeometry(0.012, 0.42, 0.024), ironMat);
  fuller.name = 'fuller';
  fuller.position.set(0, 0.36, 0);
  weapon.add(fuller);
  const head = new THREE.Group();
  head.name = 'head';
  head.position.set(0, 1.13, 0);
  root.add(head);
  const neck = new THREE.Mesh(new THREE.BoxGeometry(0.07, 0.1, 0.07), jointMat);
  neck.name = 'neck';
  neck.position.set(0, 0.03, -0.03);
  head.add(neck);
  const skull = new THREE.Mesh(new THREE.BoxGeometry(0.38, 0.3, 0.34), boneMat);
  skull.name = 'skull';
  skull.position.set(0, 0.22, 0.01);
  head.add(skull);
  const jaw = new THREE.Mesh(new THREE.BoxGeometry(0.32, 0.07, 0.28), boneMat);
  jaw.name = 'jaw';
  jaw.position.set(0, 0.03, 0.03);
  head.add(jaw);
  const mouthGap = new THREE.Mesh(new THREE.BoxGeometry(0.22, 0.035, 0.01), socketMat);
  mouthGap.name = 'mouthGap';
  mouthGap.position.set(0, 0.075, 0.176);
  head.add(mouthGap);
  const toothGap2 = new THREE.Mesh(boxGeo10, socketMat);
  toothGap2.name = 'toothGap2';
  toothGap2.position.set(-0.05, 0.04, 0.171);
  head.add(toothGap2);
  const toothGap3 = new THREE.Mesh(boxGeo10, socketMat);
  toothGap3.name = 'toothGap3';
  toothGap3.position.set(0, 0.04, 0.171);
  head.add(toothGap3);
  const toothGap4 = new THREE.Mesh(boxGeo10, socketMat);
  toothGap4.name = 'toothGap4';
  toothGap4.position.set(0.05, 0.04, 0.171);
  head.add(toothGap4);
  const socketL = new THREE.Mesh(boxGeo11, socketMat);
  socketL.name = 'socketL';
  socketL.position.set(0.085, 0.25, 0.175);
  head.add(socketL);
  const eyeGlowL = new THREE.Mesh(boxGeo12, glowMat);
  eyeGlowL.name = 'eyeGlowL';
  eyeGlowL.position.set(0.08, 0.245, 0.188);
  head.add(eyeGlowL);
  const socketR = new THREE.Mesh(boxGeo11, socketMat);
  socketR.name = 'socketR';
  socketR.position.set(-0.085, 0.25, 0.175);
  head.add(socketR);
  const eyeGlowR = new THREE.Mesh(boxGeo12, glowMat);
  eyeGlowR.name = 'eyeGlowR';
  eyeGlowR.position.set(-0.08, 0.245, 0.188);
  head.add(eyeGlowR);
  const noseHole = new THREE.Mesh(extrude([[-0.025, 0], [0.025, 0], [0, -0.04]], 0.02), socketMat);
  noseHole.name = 'noseHole';
  noseHole.position.set(0, 0.19, 0.175);
  head.add(noseHole);

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

export default createSkeletonWarrior;

평점 및 댓글

—
아직 평점이 없어요 — 첫 평점을 남겨 보세요.
5
0
4
0
3
0
2
0
1
0

평점과 댓글을 남기려면 로그인하세요.

댓글 0개

아직 댓글이 없어요. 이 모델을 어떻게 사용했는지, 어떤 점이 더 나아질 수 있을지 공유해 주세요.

관련 모델

같은 카테고리 또는 비슷한 태그