2
votes

I'm attempting to create a basic „starry sky“ experience, and need to project points from a sphere's surface to a 2D viewport. I've been trying to do some research, but the topic of 3D projections is fairly complicated; on the other hand, using a full-fledged 3D library seems like an overkill.

The sky is represented as a (hemi)sphere, the stars are located on its surface, and the viewer "sits" in the sphere's center. I have the coordinates of the stars, and the view direction (all in 3D, as points on the sphere's surface [declination: 0-90 = horizon-north pole, azimuth: 0-360]). I also have the size of the viewport (2D). When the view direction equals to a star's coordinates, the star projects to the center of the viewport, but for all other points there'll be some "deformation" given they're on a spherical surface.

What is the formula for computing the position of a star in the viewport from its coordinates on the sphere and the direction of the view? (I suppose there're gonna be some additional parameters involved, too…)

1
IMHO, the math for this is hard enough that you might as well use a 3D library, particularly if you're going to allow the camera to rotate around its own axis. It does get somewhat simpler if the horizontal axis of the screen is parallel to the ground (or the celestial equator) - whichever is your frame of reference.Alnitak
It's the latter, camera goes just up/down, left/right, staying parallel to the ground. Also, it stops at looking straight up, not going upside down.XenoPheX

1 Answers

2
votes

One way to look at this is that your viewport is fixed in position, and we rotate the sky so that the central star in your view is directly in front of you. Say you are looking north, then that means rotating the sky first by the negative of the central star’s azimuth to put it directly in front of you. Then rotating the sky down (around the east-west axis) to place the central star on the horizon in front of you.

By applying these two rotations to all of the stars in the sky, we get new positions for them all, and you can simply calculate where they fall on the viewport.

So how? Lets put some coordinates in place. For the 3D space, lets say you are facing “north” which we will say is the positive x direction. They the y-axis points east, and the z-axis points straight up. Your eye is at (0,0,0). For the 2D viewport, we will say that the centre of the viewport is at (0,0), the s-axis points right and the t-axis points up. I could have called these the 3D viewports x and y axes, but with the 3D space have x,y and z axes, the reusing of axis names gets confusing really fast. So just think of the 3D space as (x,y,z) and the 2D space as (s,t).

The viewport itself is placed parallel to the 3D space’s yz plane, so perpendicular to its x axis, and it intersects the x-axis at say (e,0,0), so basically e is the distance of the viewport from your eye.

Projecting a star at (x,y,z) onto the 2D plane is then very simple:

viewport coords = (-ey/x,ez/x).

Since you only can see stars in front of you, (x > 0), only project stars with x > 0. “e” is just a scale factor now; increasing it “zooms in”.

If you are mapping this to a computer screen, you probably need to:

  • Scale so the width and height of your viewport match the pixel width and height.
  • Add half the pixel width and height to the (s,t) coords. That way the centre of the viewport (0,0) maps to the centre of the screen (width / 2, height / 2).
  • Flip the y coordinate (since screen have (0,0) at the top left, not the bottom left). this is just y = height - y;

So this is simple, right ;).

The hard part is figuring out each star’s coordinates and what they map to when you rotate that central star in front of you.

Suppose:

  • the central star “c" has
    • azimuth = azc
    • declination = dec
  • the star to project “p” onto the 2D viewport has
    • azimuth = azp
    • declination = dep

Then, the (x,y,z) coords of the star “p” on the unit sphere are:

  • x = cos(dec)cos(azp - azc)cos(dep) + sin(dec)sin(dep)
  • y = sin(azp - azc)cos(dep)
  • z = -sin(dec)cos(azp - azc)cos(dep) + cos(dec)sin(dep)

I derived this using 3D matrices. I could show it if you are interested, and I might add it later. Once you have (x,y,z), then you can use the formula above to project on the 2D viewport.

Also, this got me curious about trying to use 3d transforms in CSS. I set up star web page that demonstrates how it might work. No 3d math!