r2d2starwars/cosmic-vortex-simulator
0
1document.addEventListener('DOMContentLoaded', () => {2 // Scene setup3 const scene = new THREE.Scene();4 const camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);5 const renderer = new THREE.WebGLRenderer({ canvas: document.getElementById('spaceCanvas'), antialias: true });6 renderer.setSize(window.innerWidth, window.innerHeight);7 renderer.setClearColor(0x000000);8 9 // Black hole parameters10 const blackHole = {11 radius: 1,12 position: new THREE.Vector3(0, 0, 0),13 gravity: 0.514 };15 16 // Create black hole17 const blackHoleGeometry = new THREE.SphereGeometry(blackHole.radius, 32, 32);18 const blackHoleMaterial = new THREE.MeshBasicMaterial({ 19 color: 0x000000,20 transparent: true,21 opacity: 0.922 });23 const blackHoleMesh = new THREE.Mesh(blackHoleGeometry, blackHoleMaterial);24 scene.add(blackHoleMesh);25 26 // Create accretion disk27 const diskGeometry = new THREE.RingGeometry(blackHole.radius * 1.5, blackHole.radius * 3, 64);28 const diskMaterial = new THREE.MeshBasicMaterial({ 29 color: 0x9933ff,30 side: THREE.DoubleSide,31 transparent: true,32 opacity: 0.833 });34 const diskMesh = new THREE.Mesh(diskGeometry, diskMaterial);35 diskMesh.rotation.x = Math.PI / 2;36 scene.add(diskMesh);37 38 // Create lensing effect39 const lensingGeometry = new THREE.SphereGeometry(blackHole.radius * 2, 32, 32);40 const lensingMaterial = new THREE.ShaderMaterial({41 uniforms: {42 time: { value: 0 }43 },44 vertexShader: `45 varying vec2 vUv;46 void main() {47 vUv = uv;48 gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);49 }50 `,51 fragmentShader: `52 uniform float time;53 varying vec2 vUv;54 void main() {55 vec2 p = vUv * 2.0 - 1.0;56 float len = length(p);57 vec2 distorted = p;58 distorted *= len;59 float a = atan(0.0, 1.0) + time * 0.2;60 distorted = vec2(distorted.x * cos(a) - distorted.y * sin(a), 61 distorted.x * sin(a) + distorted.y * cos(a));62 vec3 color = mix(vec3(0.2, 0.2, 0.4), vec3(0.4, 0.2, 0.6), 0.5 + 0.5 * sin(len + time));63 color = mix(color, vec3(0.8, 0.4, 0.9), 0.5 + 0.5 * sin(time * 0.5));64 gl_FragColor = vec4(color, 0.2 * (1.0 - len));65 }66 `,67 transparent: true,68 side: THREE.BackSide69 });70 const lensingMesh = new THREE.Mesh(lensingGeometry, lensingMaterial);71 scene.add(lensingMesh);72 73 // Create stars and particles74 const particlesGeometry = new THREE.BufferGeometry();75 const particlesCount = 1000;76 const particlesPositions = new Float32Array(particlesCount * 3);77 const particlesSizes = new Float32Array(particlesCount);78 79 for (let i = 0; i < particlesCount; i++) {80 const theta = Math.random() * Math.PI * 2;81 const phi = Math.random() * Math.PI;82 const radius = 5 + Math.random() * 15;83 84 particlesPositions[i * 3] = radius * Math.sin(phi) * Math.cos(theta);85 particlesPositions[i * 3 + 1] = radius * Math.sin(phi) * Math.sin(theta);86 particlesPositions[i * 3 + 2] = radius * Math.cos(phi);87 88 particlesSizes[i] = 0.05 + Math.random() * 0.2;89 }90 91 particlesGeometry.setAttribute('position', new THREE.BufferAttribute(particlesPositions, 3));92 particlesGeometry.setAttribute('size', new THREE.BufferAttribute(particlesSizes, 1));93 94 const particlesMaterial = new THREE.PointsMaterial({95 color: 0xffffff,96 size: 0.1,97 sizeAttenuation: true,98 transparent: true,99 opacity: 0.8100 });101 102 const particles = new THREE.Points(particlesGeometry, particlesMaterial);103 scene.add(particles);104 105 // Camera position106 camera.position.z = 10;107 108 // Controls109 const controls = new THREE.OrbitControls(camera, renderer.domElement);110 controls.enablePan = false;111 controls.minDistance = 5;112 controls.maxDistance = 30;113 114 // Animation loop115 function animate() {116 requestAnimationFrame(animate);117 118 // Rotate black hole and disk119 blackHoleMesh.rotation.y += 0.005;120 diskMesh.rotation.y += 0.002;121 lensingMaterial.uniforms.time.value += 0.01;122 123 // Animate particles towards black hole124 const positions = particlesGeometry.attributes.position.array;125 126 for (let i = 0; i < particlesCount; i++) {127 const x = positions[i * 3];128 const y = positions[i * 3 + 1];129 const z = positions[i * 3 + 2];130 131 const distance = Math.sqrt(x * x + y * y + z * z);132 133 if (distance < blackHole.radius * 1.2) {134 // Reset particle position when it gets too close135 const theta = Math.random() * Math.PI * 2;136 const phi = Math.random() * Math.PI;137 const radius = 10 + Math.random() * 10;138 139 positions[i * 3] = radius * Math.sin(phi) * Math.cos(theta);140 positions[i * 3 + 1] = radius * Math.sin(phi) * Math.sin(theta);141 positions[i * 3 + 2] = radius * Math.cos(phi);142 } else {143 // Pull particle towards black hole144 const dx = -x * blackHole.gravity * 0.01;145 const dy = -y * blackHole.gravity * 0.01;146 const dz = -z * blackHole.gravity * 0.01;147 148 positions[i * 3] += dx;149 positions[i * 3 + 1] += dy;150 positions[i * 3 + 2] += dz;151 }152 }153 154 particlesGeometry.attributes.position.needsUpdate = true;155 156 renderer.render(scene, camera);157 }158 159 // Handle window resize160 window.addEventListener('resize', () => {161 camera.aspect = window.innerWidth / window.innerHeight;162 camera.updateProjectionMatrix();163 renderer.setSize(window.innerWidth, window.innerHeight);164 });165 166 animate();167});