Many Spheres MP

In this MP you will

  1. Redo your Spheres MP to run much more quickly

This MP is elective, with no core components. It assumes you have already completed the Spheres MP.

1 Overview

You will submit a webpage that has

Submit an HTML file and any number of js, css, and glsl files. No json or image files are permitted for this assignment. Do not include spaces in file names as the submission server does not process them well.

You are welcome to use a JavaScript math library, such as the one used in in-class examples or others you might know.

2 Specification

2.1 An input and an frames per second (FPS) display

Add the following to your HTML after the canvas element but still inside the body.

<div id="fps" style="position:fixed; bottom:1ex; right:1ex; display:table;"></div>
<form class="controls" action="javascript:void(0);" style="position:fixed; top:1ex; left:1ex; display:table;">
    <label>Spheres: <input id="spheres" type="number" value="50" style="width:5em;"/></label>
    <input id="submit" type="submit" value="Restart simulation"/>
</form>

Every frame, set document.querySelector('#fps').innerHTML = fps.toFixed(1), where fps is the current frame rate (i.e., 1/dt if dt is the number of seconds since the last frame).

Listen for clicks of the submit button and restart the simulation with the requested number of spheres. Also restart the simulation every 15 seconds, as you did for the Spheres MP.

2.2 Variable size and number of spheres

Let the user specify the number of spheres to use in the animation.

Randomly allocate sphere sizes so that the largest has 5× the radius of the smallest and the full set of spheres when at rest will fill the bottom of the cube several spheres deep. One way to do this is

radius = (Math.random()+.25) * (0.75/n**(1/3))

where n is the number of spheres.

Have sphere mass be proportional to volume, which is proportional to the cube of radius. Thus, when a large and small sphere collide the small one should usually do most of the moving out of the way.

2.3 Efficient rendering

One major source of inefficiency in the Spheres MP is the number of times the CPU speaks to the GPU. In my reference implementation, that was 3n+53n+5 calls per frame. Each such call requires the GPU to wait for the last one to complete, meaning most of the GPU’s possible parallelism is ineffective.

To fix this, change how spheres are drawn.

If done correctly, this should result in a fixed number of GPU invocations per frame (1010 in my reference implementation) with much better runtime efficiency. It should also create perfectly-circular, perfectly-smooth spheres with no polygonal approximation.

2.4 Collision detection

Another major source of inefficiency is collision detection. Most implementations of the Spheres MP detects collisions by checking every pair of spheres every frame, for a O(n2)O(n^2) runtime. We need to do much better to scale up to thousands of spheres.

Because our spheres are relatively similar in size and spread out so as not to overlap, we achieve O(n)O(n) instead using the following method:

  1. Divide the simulation space into a grid of cells, where cell dimension ≥ largest sphere diameter
  2. Put a pointer to each sphere in the cell where its center lies
  3. Check for collisions with sphere ss with the spheres in the same cell as ss and in all neighboring cells

There are other tricks that can make this even faster, but it provides a significant asymptotic speedup as-is.

If done correctly, doubling the number of spheres should halve the frames per second.

3 Evaluating your results

On both your development machine and when submitted to the submission server and then viewed by clicking the HTML link, the resulting animation should show perfectly circular spheres moving within an invisible cube and colliding with one another. Frames per second should scale linearly with number of spheres and be able to render 1000 spheres at reasonable speed. One example motion might be the following:

A video of an example result, on a machine with a fairly fast CPU and an 88Hz refresh rate; on a slower computer it would have a lower FPS. Note that the frame rate for 2000 spheres is about half that for 1000 spheres.