Codels
1.7K tris7.13 × 3.10 × 6.85 m

Use it in code

Remix in the editor
Self-contained ES module — only depends on three. Call the factory and add the group to your scene.
/**
 * Black Hole — Codels 3D model library
 * License: CC0-1.0 · Units: meters · Y-up · Front: +Z · Origin: center of the model (it floats — pickups, planets)
 * Triangles: 1,736 · Size (W × H × D): 7.13 × 3.10 × 6.85 m
 *
 * Usage:
 *   import { createBlackHole } from './black-hole.js';
 *   
 *   const model = createBlackHole();
 *   model.position.set(0, 0, 0);
 *   scene.add(model);
 */
import * as THREE from 'three';

const deg = THREE.MathUtils.degToRad;

export function createBlackHole() {
  const root = new THREE.Group();
  root.name = 'BlackHole';

  // Materials
  const horizonMat = new THREE.MeshStandardMaterial({ name: 'horizon', color: 0x040306, roughness: 1 });
  const photonMat = new THREE.MeshStandardMaterial({ name: 'photon', color: 0xffe2ca, roughness: 0.4, emissive: 0xffca95, emissiveIntensity: 1.3, flatShading: true });
  const hotMat = new THREE.MeshStandardMaterial({ name: 'hot', color: 0xffc991, roughness: 0.5, emissive: 0xffc281, emissiveIntensity: 1.2, flatShading: true, side: THREE.DoubleSide });
  const midMat = new THREE.MeshStandardMaterial({ name: 'mid', color: 0xff8a2a, roughness: 0.6, emissive: 0xff8a2a, flatShading: true, side: THREE.DoubleSide });
  const outerMat = new THREE.MeshStandardMaterial({ name: 'outer', color: 0xdf471e, roughness: 0.7, emissive: 0xf62d00, emissiveIntensity: 0.8, flatShading: true, side: THREE.DoubleSide });
  const faintMat = new THREE.MeshStandardMaterial({ name: 'faint', color: 0xb32a1d, roughness: 0.8, emissive: 0xc31000, emissiveIntensity: 0.6, transparent: true, opacity: 0.45, flatShading: true, side: THREE.DoubleSide });
  const lensMat = new THREE.MeshStandardMaterial({ name: 'lens', color: 0xffb975, roughness: 0.8, emissive: 0xff8a2a, emissiveIntensity: 0.8, transparent: true, opacity: 0.35, side: THREE.DoubleSide });
  const debrisMat = new THREE.MeshStandardMaterial({ name: 'debris', color: 0x3b3436, roughness: 0.9, flatShading: true });

  // Parts
  const blackHole = new THREE.Group();
  blackHole.name = 'blackHole';
  blackHole.scale.setScalar(2);
  root.add(blackHole);
  const horizon = new THREE.Mesh(new THREE.SphereGeometry(0.5, 18, 12), horizonMat);
  horizon.name = 'horizon';
  blackHole.add(horizon);
  const photonRing = new THREE.Mesh(new THREE.TorusGeometry(0.53, 0.0175, 4, 40), photonMat);
  photonRing.name = 'photonRing';
  blackHole.add(photonRing);
  const lensHalo = new THREE.Mesh(new THREE.RingGeometry(0.56, 0.775, 48), lensMat);
  lensHalo.name = 'lensHalo';
  lensHalo.position.set(0, 0, -0.025);
  blackHole.add(lensHalo);
  const accretionDisk = new THREE.Group();
  accretionDisk.name = 'accretionDisk';
  accretionDisk.rotation.set(deg(17.836), deg(-2.4649), deg(-7.6132));
  blackHole.add(accretionDisk);
  const diskBand1 = new THREE.Mesh(new THREE.RingGeometry(0.725, 0.9615, 48), hotMat);
  diskBand1.name = 'diskBand1';
  diskBand1.rotation.set(deg(-90), 0, 0);
  accretionDisk.add(diskBand1);
  const diskBand2 = new THREE.Mesh(new THREE.RingGeometry(0.9615, 1.2625, 48), midMat);
  diskBand2.name = 'diskBand2';
  diskBand2.rotation.set(deg(-90), 0, 0);
  accretionDisk.add(diskBand2);
  const diskBand3 = new THREE.Mesh(new THREE.RingGeometry(1.2625, 1.5635, 48), outerMat);
  diskBand3.name = 'diskBand3';
  diskBand3.rotation.set(deg(-90), 0, 0);
  accretionDisk.add(diskBand3);
  const diskBand4 = new THREE.Mesh(new THREE.RingGeometry(1.5635, 1.8, 48), faintMat);
  diskBand4.name = 'diskBand4';
  diskBand4.rotation.set(deg(-90), 0, 0);
  accretionDisk.add(diskBand4);
  const streak1 = new THREE.Mesh(new THREE.TorusGeometry(0.9579, 0.009, 3, 12, 0.671), photonMat);
  streak1.name = 'streak1';
  streak1.position.set(0, -0.006, 0);
  streak1.rotation.set(deg(90), 0, deg(68.2301));
  accretionDisk.add(streak1);
  const streak2 = new THREE.Mesh(new THREE.TorusGeometry(1.351, 0.009, 3, 12, 0.8877), hotMat);
  streak2.name = 'streak2';
  streak2.position.set(0, 0.006, 0);
  streak2.rotation.set(deg(90), 0, deg(-137.1765));
  accretionDisk.add(streak2);
  const streak3 = new THREE.Mesh(new THREE.TorusGeometry(1.2507, 0.009, 3, 12, 0.9937), hotMat);
  streak3.name = 'streak3';
  streak3.position.set(0, -0.006, 0);
  streak3.rotation.set(deg(90), 0, deg(164.1582));
  accretionDisk.add(streak3);
  const streak4 = new THREE.Mesh(new THREE.TorusGeometry(1.2653, 0.009, 3, 12, 1.0945), hotMat);
  streak4.name = 'streak4';
  streak4.position.set(0, 0.006, 0);
  streak4.rotation.set(deg(90), 0, deg(-68.6498));
  accretionDisk.add(streak4);
  const streak5 = new THREE.Mesh(new THREE.TorusGeometry(1.1896, 0.009, 3, 12, 0.8556), hotMat);
  streak5.name = 'streak5';
  streak5.position.set(0, -0.006, 0);
  streak5.rotation.set(deg(90), 0, deg(-72.9002));
  accretionDisk.add(streak5);
  const streak6 = new THREE.Mesh(new THREE.TorusGeometry(1.4832, 0.009, 3, 12, 1.0087), hotMat);
  streak6.name = 'streak6';
  streak6.position.set(0, 0.006, 0);
  streak6.rotation.set(deg(90), 0, deg(25.9576));
  accretionDisk.add(streak6);
  const streak7 = new THREE.Mesh(new THREE.TorusGeometry(1.3401, 0.009, 3, 12, 0.5769), hotMat);
  streak7.name = 'streak7';
  streak7.position.set(0, -0.006, 0);
  streak7.rotation.set(deg(90), 0, deg(-71.7019));
  accretionDisk.add(streak7);
  const debris1 = new THREE.Mesh(new THREE.TetrahedronGeometry(0.0208, 0), debrisMat);
  debris1.name = 'debris1';
  debris1.position.set(0.3311, -0.0044, 1.2527);
  debris1.rotation.set(deg(131.6926), deg(130.7967), 0);
  accretionDisk.add(debris1);
  const debris2 = new THREE.Mesh(new THREE.TetrahedronGeometry(0.0285, 0), debrisMat);
  debris2.name = 'debris2';
  debris2.position.set(0.3513, -0.0159, 0.9049);
  debris2.rotation.set(deg(134.0097), deg(36.1713), 0);
  accretionDisk.add(debris2);
  const debris3 = new THREE.Mesh(new THREE.TetrahedronGeometry(0.0263, 0), debrisMat);
  debris3.name = 'debris3';
  debris3.position.set(0.2872, -0.0032, -0.8358);
  debris3.rotation.set(deg(69.6493), deg(49.1531), 0);
  accretionDisk.add(debris3);
  const debris4 = new THREE.Mesh(new THREE.TetrahedronGeometry(0.0201, 0), debrisMat);
  debris4.name = 'debris4';
  debris4.position.set(0.9883, -0.0087, 0.0657);
  debris4.rotation.set(deg(102.5571), deg(52.7074), 0);
  accretionDisk.add(debris4);
  const debris5 = new THREE.Mesh(new THREE.TetrahedronGeometry(0.0244, 0), debrisMat);
  debris5.name = 'debris5';
  debris5.position.set(-1.1614, 0.018, -0.5562);
  debris5.rotation.set(deg(172.3157), deg(123.3965), 0);
  accretionDisk.add(debris5);
  const debris6 = new THREE.Mesh(new THREE.TetrahedronGeometry(0.0202, 0), debrisMat);
  debris6.name = 'debris6';
  debris6.position.set(0.9696, -0.0187, 0.2732);
  debris6.rotation.set(deg(23.45), deg(46.7199), 0);
  accretionDisk.add(debris6);
  const debris7 = new THREE.Mesh(new THREE.TetrahedronGeometry(0.0181, 0), debrisMat);
  debris7.name = 'debris7';
  debris7.position.set(-0.5103, -0.0171, 0.947);
  debris7.rotation.set(deg(132.0361), deg(96.9321), 0);
  accretionDisk.add(debris7);
  const debris8 = new THREE.Mesh(new THREE.TetrahedronGeometry(0.0264, 0), debrisMat);
  debris8.name = 'debris8';
  debris8.position.set(-1.4236, -0.0223, -0.2183);
  debris8.rotation.set(deg(31.7963), deg(47.7217), 0);
  accretionDisk.add(debris8);
  const debris9 = new THREE.Mesh(new THREE.TetrahedronGeometry(0.0206, 0), debrisMat);
  debris9.name = 'debris9';
  debris9.position.set(0.5377, 0.0013, -0.9263);
  debris9.rotation.set(deg(108.8581), deg(107.8193), 0);
  accretionDisk.add(debris9);

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

export default createBlackHole;

Ratings & comments

—
No ratings yet — be the first.
5
0
4
0
3
0
2
0
1
0

Sign in to rate and comment.

0 comments

No comments yet. Share how you used this model or what could be better.

Related models

Same category or similar tags