Okay - so let''s try to keep it simple then.
The basic idea is to create all structures as 3d coordinates on a sphere, then project everything into 2d space dependent on vehicle attitude (aka your 'view vector') and post-process the resulting 2d data set and pass the final array to a drawing routine.
If we sit in the center of a sphere such that x forward, y right and z upward, the projection into 2d space is easy as long as we look forward:
* we test whether something has a negative x
-> if so, we drop the point because we can't see it, it's behind us
-> if not, we take the point with x set to zero and create a 2d point (xy)_2d = (y_3d, z_3d)
If we're not looking forward, we need to transform everything into the coordinate system where we do. So we start with a set of 3 base vectors (1,0,0), (0,1,0), (0,0,1) and do a Tait-Bryan rotation to get the base vector set for the current attitude:
Code:
var orientTaitBryan = func (v, h, p, r) {
var heading_rad = h * math.pi/180.0;
var pitch_rad = p * math.pi/180.0;
var roll_rad = r * math.pi/180.0;
var c1 = math.cos(heading_rad);
var s1 = math.sin(heading_rad);
var c2 = math.cos(pitch_rad);
var s2 = math.sin(pitch_rad);
var c3 = math.cos(roll_rad);
var s3 = math.sin(roll_rad);
var x = v[0];
var y = v[1];
var z = v[2];
var x1 = x * (c1 * c2) + y * (c1 * s2 * s3 - c3 * s1) + z * (-s1 * s3 - c1 * c3 * s2);
var y1 = x * (c2 * s1) + y * (c1 * c3 + s1 * s2 * s3) + z * (-c3 * s1 * s2 + c1 * s3);
var z1 = x * s2 + y * (-c2 * s3) + z * c2 * c3;
var out = [];
append(out, x1);
append(out, y1);
append(out, z1);
return out;
}
(just look up the rotation matrix for the (yaw/pitch/roll) convention on Wikipedia, )
Now assume we dump ex', ey' and ez' into an array of vectors p_vecs - so we have the view_vec (along which we project) and x_proj and y_proj. If we have a sphere point in the original coordinates, we just dot it into each of the new base vectors to get the point into the rotated coordinates (and afterwards do the above flattening in the depth coordinate).
Code:
var projection = func (point_coords, view_vec, x_proj, y_proj) {
var projected_point = [0.0, 0.0, 0.0];
projected_point[0] = SpaceShuttle.dot_product(point_coords, x_proj);
projected_point[1] = SpaceShuttle.dot_product(point_coords, y_proj);
var hemisphere = SpaceShuttle.dot_product(point_coords, view_vec);
if (hemisphere < -0.2)
{projected_point[2] = -1;}
else if (hemisphere < 0.0)
{projected_point[2] = 0;}
else
{projected_point[2] = 1;}
return projected_point;
}
Afterwards we can clip in a circular area
Code:
var circle_clipping = func (projected_point, radius) {
var length = math.sqrt(projected_point[0] * projected_point[0] + projected_point[1] * projected_point[1]);
if (length > 1.2 * radius)
{
projected_point[2] = -1;
}
else if (length > radius)
{
projected_point[2] = 0;
}
return projected_point;
}
The draw call for, say, a meridian then sets longitude to a value and varies latitude of the point, computes the 3d position based on (lat, lon, radius) in the original coordinates, transforms into the new coordinates and then does projection and clipping
Code:
var draw_meridian = func (lon, npoints, p_vecs) {
var dlat = 170.0 / (npoints-1);
var lon_rad = lon * math.pi/180.0;
var shape_data = [];
for (var i = 0; i < npoints; i=i+1)
{
var lat_rad = (-85.0 + i * dlat) * math.pi/180.0;
var x = math.sin(lon_rad) * math.cos(lat_rad);
var y = math.cos(lon_rad) * math.cos(lat_rad);
var z = math.sin(lat_rad);
var projected_point = projection ([x,y,z], p_vecs[0], p_vecs[1], p_vecs[2]);
projected_point = circle_clipping(projected_point, 0.75);
if (projected_point[2] > -1)
{append(shape_data, projected_point);}
}
return shape_data;
}
and only once a point passes the depth test and the clipping, it is appended to the shape data array and passed onward to drawing.
So a call to draw_meridian returns an array of the projection of the meridian in 2d space dependent on the current vehicle attitude.
Many of these steps are what the graphics card does during the rasterizer stage between vertex shader and fragment shader processing (rotation into eye space, projection into screen space, view frustrum culling,...) which is why I mentioned it helps to know some 3d rendering.