Solar System Simulator

Solar-SystemI made a solar system simulator…! It’s not the most polished thing and it does not have the nicest application-specific code, but it works decently for 12 hours work on the solar system simulation part. Though I spent a significant chunk of time (probably > 30 hours) just setting up a new engine for experimenting with graphics stuff.

Part of this time just went toward implementing templated vector and matrix structs to handle all my math. In my previous engine work I had been using DirectXMath’s XMVECTOR and XMMATRIX which worked well enough, but had some things with their syntax that made longer mathematical operations harder to read especially when you needed to copy between XMVECTOR and XMFLOAT3 or 4 a lot.  I decided to template everything since it is easier to just have Vector3 and Vector3i automatically compile to handles floats and ints respectively. It also seems a lot cleaner than doing something like typedef real float/typedef real double. The major downside to this switch is that I lose the SIMD processing speed that DirectXMath gives. I ended up comparing some common operations on vectors and matrix multiplication/inverse. The performance loss for vectors was pretty marginal and I did not see any real difference when I timed them. The matrices were where the performance took a hit. On multiplication and inverse operations on 4×4 matrices between my matrix struct and the DirectXMath XMMATRIX, mine performed about one third as well; taking about 0.4 seconds to perform 10,000,000 multiplications or inverses whereas the XMMATRIX operations took about 0.14 seconds in a release build with /O2 under MSVC. It’s not so bad that I see it being a massive bottleneck, but if I were to have time I might implement specialized multiply and inverse operations for float typed versions of my Matrix4x4. The SIMD instructions are abstracted into some C functions that I should be able to call if I actually have to time to do an implementation. One of my friends recently informed me of Intel’s plans to start putting 512 bit registers in CPUs starting this year so it’s likely that we could soon have entire matrix multiplications execute as a single instruction which should give a massive boost in performance.

On a side note, I was browsing the code of some other implementations of matrices. Some people elected to use a class that could handle any NxM matrix by taking the number of rows and columns in the constructor. The multiplications and inverse are handled by nested for loops. I was curious how bad for performance this would be. I benchmarked the operations and found that they take about 100 times longer than my Matrix4x4 class and 300 times longer than XMMATRIX clocking in at around 40 seconds for 10,000,000 operations. I was pretty surprised at how significant this difference was. As far as I’m aware, there’s also not really any need to NxM matrices in computer graphics and physics unless you are using Jacobian matrices for stuff like contact resolution or inverse kinematics. I wanted to test a templated NxM matrix also to see if the MSVC compiler would know to unroll the for loops, but have not had time to yet.

This simulation uses Newton’s law of universal gravitation to determine the acceleration of planetary bodies due to gravity. The actual gravity part was pretty simple to implement in itself, it just took some time to find how to get the speed of the planets at their perihelion’s and work it out for each planet. I ended up finding http://en.wikipedia.org/wiki/Orbital_speed#Precise_orbital_speed which helped me derive the speed, though it did not specify that the input mass was supposed to be the mass of the body the satellite was orbiting so I was getting slightly skewed velocities since I was putting in the mass of the planets themselves instead of the mass of the sun. I ended up putting everything into an Excel sheet just to keep it all organized and automate the perihelion speed calculations. I made an XML file that stores the information about the planets that need to be loaded in.

Once I had the speed all I had to do was place the planets along the X axis at their perihelions and give them an initial velocity on the Z axis. Then I just let the gravity generator take care of the rest.

I integrate the physics system 2000 times every frame in attempt to make up for the inaccuracy of Euler integration. This works well enough and I’m kind of surprised it can maintain 60 fps since it means that the program is updating the forces on each planet about 17,000,000 times a second.

There are two interesting cases with the moon and with Pluto. The moon was not maintaining its orbit around the earth at higher simulation speeds before I switched to double precision Vector3′s. Secondly, Pluto kind of orbits Neptune in the current simulation. It seems to actually stay in a somewhat stable orbit for a while. This is because Pluto’s orbit axis is normally pretty skewed off of the average axis so while it does pass near by Neptune on a flat plane like my simulation has it on, it would normally be somewhat farther away.

For text rendering I’m using a text renderer that I implemented over the summer break. It still needs a lot of work before I can say it’s “done,” but it works decently for the moment. The text renderer takes a set of points and expands them into quads using a geometry shader. Each quad samples from a texture atlas that contains come cached letters that I rasterize using FreeType. I pack them into the texture using a binary tree for easy, efficient packing. This is what the atlas looks like with various glyph sizes and fonts.

Font Packing

This allows me to render several hundred thousand characters at a time without much performance hit. In this application I’m using a deferred rendering path, but hacked in a forward rendering path to render the GUI text and planet names after all the deferred rendering.

I kind of want to implement signed distance field text rendering if I have the time, but it seems to have trouble with sharp corners and will tend to smooth them out.

The trail rendering is using a geometry shader-based system that takes in a list of points and expands them into quads that face the camera and attempt to maintain contiguity without seams between the quads. This has a benefit over the native line rendering in that I can control the width of the lines.

A lot of the extra stuff such as the camera controls are kind of hacked together since I was pressed for time. You can select planets using the number keys. When you select a planet, it will find a point around the planet that takes the planet’s radius and the camera’s orientation into account. It will get the forward vector from the camera in world space and just subtract that from the planet’s position, then lerp the camera’s position to the new position. This has the nice side effect that the user can orbit around the planet with the camera while dragging the left mouse button.

Here’s a short video of it in action.

Leave a Reply

Your email address will not be published.

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>