Codels
912 三角面2.52 × 2.32 × 1.06 m

在代码中使用

在编辑器中改编
自包含的 ES 模块,仅依赖 three。调用工厂函数,然后把返回的 group 添加到场景中。
/**
 * Stone Golem — Codels 3D model library
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 912 · Size (W × H × D): 2.52 × 2.32 × 1.06 m
 *
 * Usage:
 *   import { createGolem } from './golem.js';
 *   
 *   const model = createGolem();
 *   model.position.set(0, 0, 0);
 *   scene.add(model);
 */
import * as THREE from 'three';

const deg = THREE.MathUtils.degToRad;

// Deterministic vertex displacement (organic low-poly look).
function jitter(geometry, amount, seed) {
  const pos = geometry.attributes.position;
  const h = (a, b, c, s) => {
    let x = Math.imul(a, 73856093) ^ Math.imul(b, 19349663) ^ Math.imul(c, 83492791) ^ Math.imul(s, 2654435761);
    x = Math.imul(x ^ (x >>> 16), 2246822507);
    x = Math.imul(x ^ (x >>> 13), 3266489909);
    return ((x ^ (x >>> 16)) >>> 0) / 4294967295 - 0.5;
  };
  for (let i = 0; i < pos.count; i++) {
    const x = pos.getX(i), y = pos.getY(i), z = pos.getZ(i);
    const qx = Math.round(x * 1000), qy = Math.round(y * 1000), qz = Math.round(z * 1000);
    pos.setXYZ(i, x + h(qx, qy, qz, seed) * 2 * amount, y + h(qx, qy, qz, seed + 1) * 2 * amount, z + h(qx, qy, qz, seed + 2) * 2 * amount);
  }
  pos.needsUpdate = true;
  geometry.computeVertexNormals();
  return geometry;
}

export function createGolem() {
  const root = new THREE.Group();
  root.name = 'Golem';

  // Materials
  const stoneMat = new THREE.MeshStandardMaterial({ name: 'stone', color: 0x858a93, roughness: 0.95, flatShading: true });
  const stoneDarkMat = new THREE.MeshStandardMaterial({ name: 'stoneDark', color: 0x686c73, roughness: 0.95, flatShading: true });
  const stoneLightMat = new THREE.MeshStandardMaterial({ name: 'stoneLight', color: 0x9498a0, roughness: 0.95, flatShading: true });
  const glowMat = new THREE.MeshStandardMaterial({ name: 'glow', color: 0x46dcff, roughness: 0.3, emissive: 0x46dcff, emissiveIntensity: 1.1, flatShading: true });
  const mossMat = new THREE.MeshStandardMaterial({ name: 'moss', color: 0x6b9a3e, roughness: 1, flatShading: true });

  // Shared geometries
  const boxGeo = new THREE.BoxGeometry(0.2016, 0.0364, 0.02);
  const octahedronGeo = new THREE.OctahedronGeometry(0.085, 0);
  const boxGeo2 = new THREE.BoxGeometry(0.0648, 0.018, 0.02);
  const boxGeo3 = new THREE.BoxGeometry(0.018, 0.135, 0.02);
  const boxGeo4 = new THREE.BoxGeometry(0.045, 0.018, 0.02);
  const boxGeo5 = new THREE.BoxGeometry(0.11, 0.055, 0.03);

  // Parts
  const legL = new THREE.Group();
  legL.name = 'legL';
  legL.position.set(0.3, 0.72, 0);
  root.add(legL);
  const thighL = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.25, 0), 0.035, 3), stoneDarkMat);
  thighL.name = 'thighL';
  thighL.position.set(0, -0.14, 0);
  legL.add(thighL);
  const footL = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3, 0), 0.03, 5), stoneMat);
  footL.name = 'footL';
  footL.position.set(0, -0.5313, 0.06);
  footL.scale.set(1.05, 0.62, 1.25);
  legL.add(footL);
  const legR = new THREE.Group();
  legR.name = 'legR';
  legR.position.set(-0.3, 0.72, 0);
  root.add(legR);
  const thighR = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.25, 0), 0.035, 4), stoneDarkMat);
  thighR.name = 'thighR';
  thighR.position.set(0, -0.14, 0);
  legR.add(thighR);
  const footR = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.3, 0), 0.03, 6), stoneMat);
  footR.name = 'footR';
  footR.position.set(0, -0.5445, 0.06);
  footR.scale.set(1.05, 0.62, 1.25);
  legR.add(footR);
  const body = new THREE.Group();
  body.name = 'body';
  root.add(body);
  const pelvis = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.4, 0), 0.04, 8), stoneDarkMat);
  pelvis.name = 'pelvis';
  pelvis.position.set(0, 0.84, 0);
  pelvis.scale.set(1.25, 0.7, 0.9);
  body.add(pelvis);
  const torso = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.62, 0), 0.06, 2), stoneMat);
  torso.name = 'torso';
  torso.position.set(0, 1.4, 0);
  torso.scale.set(1.2, 0.95, 0.85);
  body.add(torso);
  const chestRune = new THREE.Group();
  chestRune.name = 'chestRune';
  chestRune.position.set(-0.0045, 1.4814, 0.4943);
  chestRune.rotation.set(deg(-7.2582), deg(-22.2077), deg(-1.4263));
  body.add(chestRune);
  const runeEdge = new THREE.Mesh(boxGeo, glowMat);
  runeEdge.name = 'runeEdge';
  runeEdge.position.set(-0.07, 0.07, 0);
  runeEdge.rotation.set(0, 0, deg(45));
  chestRune.add(runeEdge);
  const runeEdge2 = new THREE.Mesh(boxGeo, glowMat);
  runeEdge2.name = 'runeEdge';
  runeEdge2.position.set(0.07, 0.07, 0);
  runeEdge2.rotation.set(0, 0, deg(-45));
  chestRune.add(runeEdge2);
  const runeEdge3 = new THREE.Mesh(boxGeo, glowMat);
  runeEdge3.name = 'runeEdge';
  runeEdge3.position.set(-0.07, -0.07, 0);
  runeEdge3.rotation.set(0, 0, deg(-45));
  chestRune.add(runeEdge3);
  const runeEdge4 = new THREE.Mesh(boxGeo, glowMat);
  runeEdge4.name = 'runeEdge';
  runeEdge4.position.set(0.07, -0.07, 0);
  runeEdge4.rotation.set(0, 0, deg(45));
  chestRune.add(runeEdge4);
  const runeStroke = new THREE.Mesh(new THREE.BoxGeometry(0.0364, 0.42, 0.02), glowMat);
  runeStroke.name = 'runeStroke';
  chestRune.add(runeStroke);
  const runeBar = new THREE.Mesh(new THREE.BoxGeometry(0.14, 0.0364, 0.02), glowMat);
  runeBar.name = 'runeBar';
  runeBar.position.set(0, -0.07, 0);
  chestRune.add(runeBar);
  const mossBack = new THREE.Mesh(jitter(new THREE.IcosahedronGeometry(0.26, 0), 0.03, 21), mossMat);
  mossBack.name = 'mossBack';
  mossBack.position.set(-0.22, 1.9532, -0.05);
  mossBack.scale.set(1.1, 0.28, 0.9);
  body.add(mossBack);
  const backCrystal1 = new THREE.Mesh(octahedronGeo, glowMat);
  backCrystal1.name = 'backCrystal1';
  backCrystal1.position.set(-0.25, 1.62, -0.3526);
  backCrystal1.rotation.set(deg(-43.8302), deg(-10.4646), deg(25.6471));
  backCrystal1.scale.set(0.8, 2.2, 0.8);
  body.add(backCrystal1);
  const backCrystal2 = new THREE.Mesh(octahedronGeo, glowMat);
  backCrystal2.name = 'backCrystal2';
  backCrystal2.position.set(0.05, 1.72, -0.2488);
  backCrystal2.rotation.set(deg(-38.5378), deg(1.5622), deg(-4.4667));
  backCrystal2.scale.set(0.8, 2.2, 0.8);
  body.add(backCrystal2);
  const backCrystal3 = new THREE.Mesh(octahedronGeo, glowMat);
  backCrystal3.name = 'backCrystal3';
  backCrystal3.position.set(0.3, 1.55, -0.2999);
  backCrystal3.rotation.set(deg(-44.8632), deg(13.4762), deg(-31.9421));
  backCrystal3.scale.set(0.8, 2.2, 0.8);
  body.add(backCrystal3);
  const armL = new THREE.Group();
  armL.name = 'armL';
  armL.position.set(0.74, 1.74, 0);
  armL.rotation.set(deg(-6), 0, deg(9));
  root.add(armL);
  const shoulderL = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.35, 0), 0.04, 31), stoneLightMat);
  shoulderL.name = 'shoulderL';
  armL.add(shoulderL);
  const upperArmL = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.21, 0), 0.025, 33), stoneDarkMat);
  upperArmL.name = 'upperArmL';
  upperArmL.position.set(0, -0.4, 0);
  armL.add(upperArmL);
  const forearmL = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.25, 0), 0.03, 35), stoneMat);
  forearmL.name = 'forearmL';
  forearmL.position.set(0, -0.76, 0.04);
  forearmL.scale.set(1, 1.25, 1);
  armL.add(forearmL);
  const fistL = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.33, 0), 0.04, 37), stoneLightMat);
  fistL.name = 'fistL';
  fistL.position.set(0, -1.18, 0.07);
  armL.add(fistL);
  const forearmRuneL = new THREE.Group();
  forearmRuneL.name = 'forearmRuneL';
  forearmRuneL.position.set(0.0579, -0.7793, 0.2378);
  forearmRuneL.rotation.set(deg(-4.3648), deg(41.2508), deg(1.6435));
  armL.add(forearmRuneL);
  const runeEdge5 = new THREE.Mesh(boxGeo2, glowMat);
  runeEdge5.name = 'runeEdge';
  runeEdge5.position.set(-0.0225, 0.0225, 0);
  runeEdge5.rotation.set(0, 0, deg(45));
  forearmRuneL.add(runeEdge5);
  const runeEdge6 = new THREE.Mesh(boxGeo2, glowMat);
  runeEdge6.name = 'runeEdge';
  runeEdge6.position.set(0.0225, 0.0225, 0);
  runeEdge6.rotation.set(0, 0, deg(-45));
  forearmRuneL.add(runeEdge6);
  const runeEdge7 = new THREE.Mesh(boxGeo2, glowMat);
  runeEdge7.name = 'runeEdge';
  runeEdge7.position.set(-0.0225, -0.0225, 0);
  runeEdge7.rotation.set(0, 0, deg(-45));
  forearmRuneL.add(runeEdge7);
  const runeEdge8 = new THREE.Mesh(boxGeo2, glowMat);
  runeEdge8.name = 'runeEdge';
  runeEdge8.position.set(0.0225, -0.0225, 0);
  runeEdge8.rotation.set(0, 0, deg(45));
  forearmRuneL.add(runeEdge8);
  const runeStroke2 = new THREE.Mesh(boxGeo3, glowMat);
  runeStroke2.name = 'runeStroke';
  forearmRuneL.add(runeStroke2);
  const runeBar2 = new THREE.Mesh(boxGeo4, glowMat);
  runeBar2.name = 'runeBar';
  runeBar2.position.set(0, -0.0225, 0);
  forearmRuneL.add(runeBar2);
  const mossShoulder = new THREE.Mesh(jitter(new THREE.IcosahedronGeometry(0.2, 0), 0.025, 41), mossMat);
  mossShoulder.name = 'mossShoulder';
  mossShoulder.position.set(0.02, 0.31, -0.02);
  mossShoulder.scale.set(1, 0.3, 1);
  armL.add(mossShoulder);
  const armR = new THREE.Group();
  armR.name = 'armR';
  armR.position.set(-0.74, 1.74, 0);
  armR.rotation.set(deg(-6), 0, deg(-9));
  root.add(armR);
  const shoulderR = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.35, 0), 0.04, 32), stoneLightMat);
  shoulderR.name = 'shoulderR';
  armR.add(shoulderR);
  const upperArmR = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.21, 0), 0.025, 34), stoneDarkMat);
  upperArmR.name = 'upperArmR';
  upperArmR.position.set(0, -0.4, 0);
  armR.add(upperArmR);
  const forearmR = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.25, 0), 0.03, 36), stoneMat);
  forearmR.name = 'forearmR';
  forearmR.position.set(0, -0.76, 0.04);
  forearmR.scale.set(1, 1.25, 1);
  armR.add(forearmR);
  const fistR = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.33, 0), 0.04, 38), stoneLightMat);
  fistR.name = 'fistR';
  fistR.position.set(0, -1.18, 0.07);
  armR.add(fistR);
  const forearmRuneR = new THREE.Group();
  forearmRuneR.name = 'forearmRuneR';
  forearmRuneR.position.set(-0.0569, -0.7806, 0.2372);
  forearmRuneR.rotation.set(deg(3.4854), deg(-35.3884), deg(1.1123));
  armR.add(forearmRuneR);
  const runeEdge9 = new THREE.Mesh(boxGeo2, glowMat);
  runeEdge9.name = 'runeEdge';
  runeEdge9.position.set(-0.0225, 0.0225, 0);
  runeEdge9.rotation.set(0, 0, deg(45));
  forearmRuneR.add(runeEdge9);
  const runeEdge10 = new THREE.Mesh(boxGeo2, glowMat);
  runeEdge10.name = 'runeEdge';
  runeEdge10.position.set(0.0225, 0.0225, 0);
  runeEdge10.rotation.set(0, 0, deg(-45));
  forearmRuneR.add(runeEdge10);
  const runeEdge11 = new THREE.Mesh(boxGeo2, glowMat);
  runeEdge11.name = 'runeEdge';
  runeEdge11.position.set(-0.0225, -0.0225, 0);
  runeEdge11.rotation.set(0, 0, deg(-45));
  forearmRuneR.add(runeEdge11);
  const runeEdge12 = new THREE.Mesh(boxGeo2, glowMat);
  runeEdge12.name = 'runeEdge';
  runeEdge12.position.set(0.0225, -0.0225, 0);
  runeEdge12.rotation.set(0, 0, deg(45));
  forearmRuneR.add(runeEdge12);
  const runeStroke3 = new THREE.Mesh(boxGeo3, glowMat);
  runeStroke3.name = 'runeStroke';
  forearmRuneR.add(runeStroke3);
  const runeBar3 = new THREE.Mesh(boxGeo4, glowMat);
  runeBar3.name = 'runeBar';
  runeBar3.position.set(0, -0.0225, 0);
  forearmRuneR.add(runeBar3);
  const head = new THREE.Group();
  head.name = 'head';
  head.position.set(0, 1.92, 0.12);
  root.add(head);
  const skull = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.31, 0), 0.03, 51), stoneMat);
  skull.name = 'skull';
  skull.position.set(0, 0.15, 0.06);
  skull.scale.set(1.12, 0.85, 1);
  head.add(skull);
  const brow = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(0.17, 0), 0.015, 52), stoneDarkMat);
  brow.name = 'brow';
  brow.position.set(0, 0.25, 0.2);
  brow.scale.set(1.75, 0.42, 0.7);
  head.add(brow);
  const eyeL = new THREE.Mesh(boxGeo5, glowMat);
  eyeL.name = 'eyeL';
  eyeL.position.set(0.11, 0.15, 0.2711);
  eyeL.rotation.set(deg(8.2871), deg(18.1187), deg(-13.3236));
  head.add(eyeL);
  const eyeR = new THREE.Mesh(boxGeo5, glowMat);
  eyeR.name = 'eyeR';
  eyeR.position.set(-0.11, 0.15, 0.2782);
  eyeR.rotation.set(deg(4.8602), deg(-28.7519), deg(13.2464));
  head.add(eyeR);
  const mouth = new THREE.Mesh(new THREE.BoxGeometry(0.16, 0.035, 0.03), stoneDarkMat);
  mouth.name = 'mouth';
  mouth.position.set(0, 0.03, 0.2563);
  mouth.rotation.set(deg(53.6954), deg(-1.8448), deg(0.9339));
  head.add(mouth);
  const mossHead = new THREE.Mesh(jitter(new THREE.IcosahedronGeometry(0.17, 0), 0.02, 61), mossMat);
  mossHead.name = 'mossHead';
  mossHead.position.set(-0.05, 0.35, 0);
  mossHead.scale.set(1, 0.3, 1);
  head.add(mossHead);

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

export default createGolem;

评分与评论

—
暂无评分,快来抢先评分吧。
5
0
4
0
3
0
2
0
1
0

登录后即可评分和评论。

0 条评论

暂无评论。分享一下你是如何使用这个模型的,或者有哪些可以改进的地方。

相关模型

同一分类或相似标签