|
Orrery
A GPU-accelerated N-body gravitational simulator
|
Drawing a few hundred thousand point masses as a field of stars. More...
#include <cstddef>#include <memory>#include <span>#include <string>#include "orrery/core/types.hpp"#include "orrery/core/vec3_span.hpp"#include "orrery/viz/gl_api.hpp"#include "orrery/viz/matrix4.hpp"#include "orrery/viz/tone_map.hpp"Go to the source code of this file.
Classes | |
| struct | orrery::viz::Colour |
| A colour in linear light, before tone mapping. More... | |
| struct | orrery::viz::RenderSettings |
| Everything about how the picture looks that is not the camera. More... | |
| class | orrery::viz::PointRenderer |
| The two-pass point renderer described above. More... | |
Drawing a few hundred thousand point masses as a field of stars.
The whole renderer is two passes. The first draws every particle as a small round sprite with additive blending into a floating-point target, so that where many particles overlap the light adds up rather than the nearest one winning. The second reads that target, compresses its range with the curve in tone_map.hpp and writes the result to the screen.
A galaxy is not a set of opaque objects. Each particle in this simulation stands for many millions of stars, and what a picture of it should show is how much light comes from each direction: a sum along the line of sight, not the nearest contributor to it. Additive blending is that sum, and it is why there is no depth test here. Turning one on would make the picture depend on the order the particles happen to be stored in.
A sum has no upper bound, so the target it accumulates into must not either. Rendering to the usual 8-bit-per-channel buffer would saturate the middle of a galaxy after a few dozen particles, and every particle after that would be added to a value that was already at the maximum, so the brightest structure in the image would carry no information at all. A half-float target holds the sum with room to spare and lets the tone curve decide afterwards what counts as white.
The simulation stores positions as three separate arrays (ADR-0004) and a vertex attribute is a strided read of one array, so the natural thing is three attributes of one float each, assembled into a vector by the vertex shader. No interleaving pass, no gather, and in a single-precision build the upload is a copy of exactly the bytes the solver wrote.
It does not own a window, create a context, or read the keyboard. It is given a function that resolves OpenGL entry points and assumes a context is current on the calling thread. That is what lets the same class serve both the interactive viewer and the offline export, which differ only in whether anything is ever presented to a screen.