WebGL N-body Galaxy Formation Simulation

Note: This is a modified version of my final project report for CS184: Computer Graphics at UC Berkeley in Spring 2019, developed by me and two other collaborators.

Live Demo | Source Code | Project Video

Abstract

Cosmological simulations are important tools in astronomy for modeling how complex structures form. However, most simulations require days or even weeks of supercomputer time. We desired to make a galaxy formation visualization accessible to anyone. To that end, we built a real-time N-body particle simulator for the browser in WebGL. Our simulation depicts gas clouds coalescing into stars orbiting around a black hole in the center of a disk galaxy. The user can customize the number of galaxies and opacity of materials; adjust the gravitational strength; choose from various cubemap backgrounds; and control a camera to pan and zoom across the scene. To allow for real time rendering, we valued visual appearance and speed over physical reality.

Technical Approach

Our starting point was a toy galaxy simulation using WebGL. Our work for this project involved rewriting the physics, adding formation/coalescence code, supporting multiple galaxy collisions, implementing camera controls, and adding an interactive control panel to customize appearance and behaviors.

Physics Model

This project involved a particle simulation with a very large number of objects. With around 25,000 stars and our primary goal of having a real time simulation within a browser, some optimizations and simplifications had to be made.

In our particle simulation, we update the positions of each of the stars at each time step. For an accurate physics simulation, we must compute the net force on each of the stars. As a simplification, we disregard all forces other than gravity including dark forces and gas interactions. Even with this however, computing pairwise forces requires work at each time step, which made a smooth rendering very difficult.

After considering optimizations such as a tree data structure, which is infeasible for a dynamic scene where construction is expensive, and a uniform binning scheme, which faces the canonical teapot in the stadium issue, we realized another simplification must be made. One key observation was that the majority of the force on a star is with interactions with high mass objects such as the black holes. Thus, we can split up the calculation of the pairwise forces, updating those of a few stars every time step, while retaining an accurate force with respect to the black holes. That is, any particular pairwise force is computed only every 60 time steps. This method gave suitable results. We then used Verlet integration to update the positions.

Initial Conditions & Coalescence

A major goal of our project was to show the formation process of a galaxy. We initialize each galaxy with a black hole (essentially a very large point mass) in the center. In order to reflect the real mechanisms of galaxy formation, we randomly distribute gas clouds in a roughly sphere-like volume around the black hole. In the real world, the flat planar shape of a spiral galaxy results from the tendency of colliding particles to collapse into a disk in order to conserve net angular momentum and to minimize gravitational potential energy. However, to avoid writing explicit collision code, which would be prohibitively slow and complicated, we instead achieved the visual effect of flattening by applying a damping force to outward velocities above a certain threshold from the plane of rotation. Over time, the vertical velocities are suppressed until all particles orbit along a relatively flat plane.

The initial velocities of the particles are chosen in order to converge to a proper rotation curve. That is, particles farthest from the central black hole have the lowest initial orbital velocity and particles closest to the central black hole gave the largest initial orbital velocity.

In addition to flattening, the coalescence effect is achieved by slightly increasing the gravitational constant over time. This accelerates the rate at which gas clouds fall into the center of the galaxy and heightens the visual appearance of collapse.

This part of the project was a challenge because achieving a decent-looking final galaxy shape was very difficult from random initial conditions. We realized we needed to work backwards, by setting the parameters for what we wanted to final result to look like, then slowly make the particles move into these roles.

Of course, none of these implementation decisions, which may appropriately be called hacks, can be justified by real physics. For real-time performance, we had to sacrifice physical accuracy to achieve computational simplicity.

Multiple Galaxy Collisions

A feature we wanted to support was multiple galaxies. This is done by randomly generating locations for each black hole, which serve as the center of each galaxy. To retain the spiral and coalescence behavior described above, we randomly assign stars to each galaxy, and randomly generate their location, with the original angular distribution, except with the mean moved to the center of their chosen galaxy.

Due to the method in which we calculate forces, stars (and black holes) also interact with stars from other galaxies, although the effect of gravity is lessened due to the great distance. This allows the formation of galaxies to begin as before, but then gives a stunning effect as they begin to draw towards each other and collide.

Visual Effects

One of the first things we added to our scene was an orbit camera using the Three.js OrbitControls library. The user can rotate around a central point (which is the black hole in the single galaxy case) while keeping a particular axis locked. Users can orbit, zoom, and pan with the left, middle, and right mouse buttons, respectively.

The background is a simple cubemap texture (skybox). We used the THREE.CubeTextureLoader() to handle the setup. There are four cubemaps to choose from, shown below.

There are three particle types, each representing a different stellar object. By default, there are 20,000 small stars, 500 large stars, and 450 gas clouds. The texture images used for each are shown below.

These textures are handled by the Three.js texture loader - we use additive blending for the stars and normal blending for the gas clouds. A visual effect used alongside the coalescence code is that the stars are initially invisible and the opacity is slowly increased as the final shape of the galaxy emerges. This is done to simulate the birth of stars from gas cloud collapse. The opacities for each material can be overridden in the control panel in the live demo.

Results

The video below shows the (default) single galaxy coalescence process sped up 8 times.


The video below shows two galaxies colliding in real-time.


The video below shows the effect of adjusting the gravitational strength in the GUI panel.


Live Demo Keyboard controls

In addition to the control panel, the live demo has the following keyboard controls:

Key Action
1 Switch to free orbit camera (default)
2 Switch to guided camera
r Toggle autorotation in orbit camera
l Increase pixel display ratio (will appear sharper on high-resolution displays)
SPACE Play/Pause
h Hide/show controls panel
a A surprise 🤔

Lessons Learned

  • Don’t reinvent the wheel: Three.js is a powerful 3D graphics library that takes advantage of WebGL’s GPU acceleration.
  • Sometimes it’s okay to use hacky code as long as the result looks good and speed is the priority.
  • JavaScript is fast to develop in but its easy to shoot yourself in the foot. Typed languages nearly always provide a better experience.

References


© Andrew Campbell. All Rights Reserved.