In today’s post I will model a galaxy (in a very free way) on Java and represent it in JS with THREE.js. As usual, architecture will be that JS client, on browser, will call an API method to retrieve starts information, as a real microservices architecture on production should work. That method will return all stars, as each one will be not more than its phi, z and radius position (as it’s easier for this snippet to use cilindrical coordinates). So, then, we model our Star class derived from CilindricalPoint. With this modelling, then we will think how to distribute them. As an easy first approximation, we can say that a star position will be less probable existing far away from core; we know too about the two characteristic spiral arms. So then, we must build a distribution function to put each star position randomly, but according certain probability constraints.
One of the most easier algorithms to create distributed probabilites (good enough for our drawing) is the following one:
- We got a probabilistic function P(X), that for an event X will return probability that it occurs between 0 and 1.
- We got total T events (in this case stars) we need to fill.
- We got certain extra constraints (maximus M and minimus m possible X values)
- With that, we proceed to generate an event X: a random number between m and M
- Pair with it, we calculate a full random Y number between 0 and 1.
- We obtain probability of our X, using P(X)
- Then, if our Y is less than P(X), we accept that X
- We push it to array and continue until we got T valid X events.
So, it is as an non-equal contest: with each X there’s an Y lottery number. But depending on X value, probability of Y number is valid or not varies.
We, then, construct a general RawDistribution class: when we ask for getDistributedPoints method, it will return to us the total X events we asked for, distributed randomly using an implemented DistributionFunction.
In our case, we want that probability of existence of star decreases when increases distance from nucleus. We implement then RadiusDistribution class. With it, we will got randomly radius positions, but all distributed depending on its absolute value. That’s it, there will be a lot more stars density near core than far away. In fact, due gravity force depends on 1/r^2, our aproximation is not so far away from reality.
NOTE: This RadiusDistribution is not normalized, that’s it, sum of probabilities of all events will not give 1. But anyway, it’s enough for our experiment. As well, this algorithm is not complete: it depends for finishing that we can get all asked total points: if distribution function is too restrictive that nevers accept events, or if random values getted for pair Y are always over probability returned, getDistributedPoints can never end. Of course, in our case this can’t happen.
Ok. We got our star distances distributed. Now, we want to calculate its phi, angulus, that should create both spiral arms. A spiral in cilindrical coordinates is no more than phi(r) = Kr, that it’s, phi increases when radius increases. As we got our radius right now, we can calculate both arms with no problem from it value. If we do, but, exact formula, we will find that our galaxy follows too strictly both arms, and result will be seen too much artificial. So, we will add some random deviation, to both sides, begin our formula then phi(r) = Kr + d.
With this, we can draw a galaxy from top perfectly. But, as we want to draw it on 3D, we should calculate its z component as well.
Z component range will depend as well on radius: when more far away, more probable that star is in then horizontal plane, but when more near the core, range available of possible possitions increases. As we see in photographies and similar, z positions follow an 1/x (or 1/x^2) distribution. We got, from previous radius calculus, a distribution function enough to represent then z distribution as well. We then calculate z using again RadiusDistribution function, and adjusting it’s values (and adding a deviation too) so it appears more real.
In fact, it’s supossed that near the core stars are surrounding it, and (all as it is known right now) as it is a black hole, that applies it attraction force independent of the direction (isotrop), then, we can consider stars near the core makes an sphere, until they are so near it that black hole eat them.
So, to represent core blackhole, we modify our RadiusDistribution class, not allowing nothing (probability 0) between a certain distance of center. That’s it, if a random event value it’s too much near the core, that event will be not
With all the ways to calculate positions, we create or Galaxy class, and then publish our constructor method on an API resource GalaxyResource, making it public to anyone.
To represent them it’s just to put on a canvas points depending on each star position.
We then obtain this when representing to 2D
And this when representing to 3D.
From here, with THREE.js, possibilities are infinite. We can change materials for the core to obtain astouning results,
And of course to add more realism applying nebulas, shadows, different star sizes, backgrounds, etc…(Added 20190924)
Hope you like it! As always, code is in my github and here live examples