Codels
504 tris1,40 × 1,49 × 1,40 m

Úsalo en código

Hacer remix en el editor
Módulo ES autónomo — solo depende de three. Llama a la función factory y añade el grupo a tu escena.
/**
 * Crystal Cluster — Codels 3D model library
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the base (y = 0)
 * Triangles: 504 · Size (W × H × D): 1.40 × 1.49 × 1.40 m
 *
 * Usage:
 *   import { createCrystalCluster } from './crystal-cluster.js';
 *   
 *   const model = createCrystalCluster();
 *   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 createCrystalCluster() {
  const root = new THREE.Group();
  root.name = 'CrystalCluster';

  // Materials
  const crystalMat = new THREE.MeshStandardMaterial({ name: 'crystal', color: 0x7b4fff, roughness: 0.2, metalness: 0.1, emissive: 0x7b4fff, emissiveIntensity: 0.45, flatShading: true });
  const crystalLightMat = new THREE.MeshStandardMaterial({ name: 'crystalLight', color: 0xa98dff, roughness: 0.15, metalness: 0.1, emissive: 0x7b4fff, emissiveIntensity: 0.55, flatShading: true });
  const rockMat = new THREE.MeshStandardMaterial({ name: 'rock', color: 0x4a4652, roughness: 0.95, flatShading: true });

  // Parts
  const cluster = new THREE.Group();
  cluster.name = 'cluster';
  root.add(cluster);
  const base = new THREE.Mesh(jitter(new THREE.DodecahedronGeometry(1, 1), 0.14, 3), rockMat);
  base.name = 'base';
  base.position.set(0, 0.2092, 0);
  base.scale.set(0.5, 0.2, 0.44);
  cluster.add(base);
  const crystal1 = new THREE.Group();
  crystal1.name = 'crystal1';
  crystal1.position.set(0, 0.2514, 0);
  crystal1.rotation.set(deg(0.987), deg(6.923), deg(-2.9225));
  cluster.add(crystal1);
  const prism = new THREE.Mesh(new THREE.CylinderGeometry(0.13, 0.1196, 0.95, 6), crystalMat);
  prism.name = 'prism';
  prism.position.set(0, 0.475, 0);
  crystal1.add(prism);
  const tip = new THREE.Mesh(new THREE.ConeGeometry(0.13, 0.286, 6), crystalMat);
  tip.name = 'tip';
  tip.position.set(0, 1.093, 0);
  crystal1.add(tip);
  const crystal2 = new THREE.Group();
  crystal2.name = 'crystal2';
  crystal2.position.set(-0.1138, 0.2442, 0.125);
  crystal2.rotation.set(deg(9.0983), deg(33.2754), deg(17.4994));
  cluster.add(crystal2);
  const prism2 = new THREE.Mesh(new THREE.CylinderGeometry(0.1001, 0.0921, 0.6109, 6), crystalLightMat);
  prism2.name = 'prism';
  prism2.position.set(0, 0.3055, 0);
  crystal2.add(prism2);
  const tip2 = new THREE.Mesh(new THREE.ConeGeometry(0.1001, 0.2203, 6), crystalLightMat);
  tip2.name = 'tip';
  tip2.position.set(0, 0.7211, 0);
  crystal2.add(tip2);
  const crystal3 = new THREE.Group();
  crystal3.name = 'crystal3';
  crystal3.position.set(0.0467, 0.2403, -0.1931);
  crystal3.rotation.set(deg(-22.345), deg(57.0069), deg(-12.0242));
  cluster.add(crystal3);
  const prism3 = new THREE.Mesh(new THREE.CylinderGeometry(0.097, 0.0892, 0.5228, 6), crystalMat);
  prism3.name = 'prism';
  prism3.position.set(0, 0.2614, 0);
  crystal3.add(prism3);
  const tip3 = new THREE.Mesh(new THREE.ConeGeometry(0.097, 0.2133, 6), crystalMat);
  tip3.name = 'tip';
  tip3.position.set(0, 0.6294, 0);
  crystal3.add(tip3);
  const crystal4 = new THREE.Group();
  crystal4.name = 'crystal4';
  crystal4.position.set(0.1639, 0.2365, 0.174);
  crystal4.rotation.set(deg(25.7801), deg(6.4064), deg(-18.505));
  cluster.add(crystal4);
  const prism4 = new THREE.Mesh(new THREE.CylinderGeometry(0.0671, 0.0617, 0.4778, 6), crystalMat);
  prism4.name = 'prism';
  prism4.position.set(0, 0.2389, 0);
  crystal4.add(prism4);
  const tip4 = new THREE.Mesh(new THREE.ConeGeometry(0.0671, 0.1476, 6), crystalMat);
  tip4.name = 'tip';
  tip4.position.set(0, 0.5516, 0);
  crystal4.add(tip4);
  const crystal5 = new THREE.Group();
  crystal5.name = 'crystal5';
  crystal5.position.set(-0.2707, 0.2328, -0.076);
  crystal5.rotation.set(deg(-18.1232), deg(5.1112), deg(37.694));
  cluster.add(crystal5);
  const prism5 = new THREE.Mesh(new THREE.CylinderGeometry(0.08, 0.0736, 0.4863, 6), crystalLightMat);
  prism5.name = 'prism';
  prism5.position.set(0, 0.2432, 0);
  crystal5.add(prism5);
  const tip5 = new THREE.Mesh(new THREE.ConeGeometry(0.08, 0.1761, 6), crystalLightMat);
  tip5.name = 'tip';
  tip5.position.set(0, 0.5744, 0);
  crystal5.add(tip5);
  const crystal6 = new THREE.Group();
  crystal6.name = 'crystal6';
  crystal6.position.set(0.2725, 0.2291, -0.1268);
  crystal6.rotation.set(deg(-0.5359), deg(27.4831), deg(-51.3398));
  cluster.add(crystal6);
  const prism6 = new THREE.Mesh(new THREE.CylinderGeometry(0.071, 0.0653, 0.3969, 6), crystalMat);
  prism6.name = 'prism';
  prism6.position.set(0, 0.1984, 0);
  crystal6.add(prism6);
  const tip6 = new THREE.Mesh(new THREE.ConeGeometry(0.071, 0.1562, 6), crystalMat);
  tip6.name = 'tip';
  tip6.position.set(0, 0.475, 0);
  crystal6.add(tip6);
  const crystal7 = new THREE.Group();
  crystal7.name = 'crystal7';
  crystal7.position.set(-0.132, 0.2253, 0.2661);
  crystal7.rotation.set(deg(35.6281), deg(36.8381), deg(23.4026));
  cluster.add(crystal7);
  const prism7 = new THREE.Mesh(new THREE.CylinderGeometry(0.0694, 0.0639, 0.3539, 6), crystalMat);
  prism7.name = 'prism';
  prism7.position.set(0, 0.177, 0);
  crystal7.add(prism7);
  const tip7 = new THREE.Mesh(new THREE.ConeGeometry(0.0694, 0.1527, 6), crystalMat);
  tip7.name = 'tip';
  tip7.position.set(0, 0.4302, 0);
  crystal7.add(tip7);
  const shard1 = new THREE.Group();
  shard1.name = 'shard1';
  shard1.position.set(0.5844, 0.0321, -0.3957);
  shard1.rotation.set(deg(10.2125), deg(38.9111), deg(-62.7794));
  cluster.add(shard1);
  const prism8 = new THREE.Mesh(new THREE.CylinderGeometry(0.0446, 0.041, 0.1114, 6), crystalMat);
  prism8.name = 'prism';
  prism8.position.set(0, 0.0557, 0);
  shard1.add(prism8);
  const tip8 = new THREE.Mesh(new THREE.ConeGeometry(0.0446, 0.0981, 6), crystalMat);
  tip8.name = 'tip';
  tip8.position.set(0, 0.1604, 0);
  shard1.add(tip8);
  const shard2 = new THREE.Group();
  shard2.name = 'shard2';
  shard2.position.set(-0.2601, 0.03, 0.544);
  shard2.rotation.set(deg(25.6908), deg(49.7994), deg(33.2307));
  cluster.add(shard2);
  const prism9 = new THREE.Mesh(new THREE.CylinderGeometry(0.0404, 0.0372, 0.1795, 6), crystalLightMat);
  prism9.name = 'prism';
  prism9.position.set(0, 0.0898, 0);
  shard2.add(prism9);
  const tip9 = new THREE.Mesh(new THREE.ConeGeometry(0.0404, 0.089, 6), crystalLightMat);
  tip9.name = 'tip';
  tip9.position.set(0, 0.224, 0);
  shard2.add(tip9);
  const shard3 = new THREE.Group();
  shard3.name = 'shard3';
  shard3.position.set(-0.3582, 0.0289, -0.5171);
  shard3.rotation.set(deg(-78.5459), deg(29.2065), deg(35.8379));
  cluster.add(shard3);
  const prism10 = new THREE.Mesh(new THREE.CylinderGeometry(0.0368, 0.0338, 0.1077, 6), crystalMat);
  prism10.name = 'prism';
  prism10.position.set(0, 0.0539, 0);
  shard3.add(prism10);
  const tip10 = new THREE.Mesh(new THREE.ConeGeometry(0.0368, 0.0809, 6), crystalMat);
  tip10.name = 'tip';
  tip10.position.set(0, 0.1482, 0);
  shard3.add(tip10);

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

export default createCrystalCluster;

Valoraciones y comentarios

—
Aún no hay valoraciones — sé el primero.
5
0
4
0
3
0
2
0
1
0

Inicia sesión para valorar y comentar.

0 comentarios

Aún no hay comentarios. Cuenta cómo usaste este modelo o qué se podría mejorar.

Modelos relacionados

Misma categoría o etiquetas similares