@ -102,23 +102,115 @@ void render_body(CelestialBody* body, RenderState* render_state) {
DrawSphereWires ( position , radius , 16 , 16 , color ) ;
DrawSphereWires ( position , radius , 16 , 16 , color ) ;
}
}
struct OrbitalBasis {
Vec3 periapsis_dir ;
Vec3 normal ;
Vec3 q_vec ;
} ;
static OrbitalBasis calculate_orbital_basis ( Vec3 r_vec , Vec3 velocity , Vec3 e_vec ) {
OrbitalBasis basis ;
basis . periapsis_dir = vec3_normalize ( e_vec ) ;
Vec3 h_vec = {
r_vec . y * velocity . z - r_vec . z * velocity . y ,
r_vec . z * velocity . x - r_vec . x * velocity . z ,
r_vec . x * velocity . y - r_vec . y * velocity . x
} ;
basis . normal = vec3_normalize ( h_vec ) ;
basis . q_vec = {
basis . normal . y * basis . periapsis_dir . z - basis . normal . z * basis . periapsis_dir . y ,
basis . normal . z * basis . periapsis_dir . x - basis . normal . x * basis . periapsis_dir . z ,
basis . normal . x * basis . periapsis_dir . y - basis . normal . y * basis . periapsis_dir . x
} ;
return basis ;
}
static Vec3 orbital_to_cartesian ( double x , double y , OrbitalBasis basis , Vec3 parent_pos ) {
return {
basis . periapsis_dir . x * x + basis . q_vec . x * y + parent_pos . x ,
basis . periapsis_dir . y * x + basis . q_vec . y * y + parent_pos . y ,
basis . periapsis_dir . z * x + basis . q_vec . z * y + parent_pos . z
} ;
}
static void draw_orbit_segment ( double x1 , double y1 , double x2 , double y2 ,
OrbitalBasis basis , Vec3 parent_pos ,
RenderState * render_state , Color color ) {
Vec3 p1_sim = orbital_to_cartesian ( x1 , y1 , basis , parent_pos ) ;
Vec3 p2_sim = orbital_to_cartesian ( x2 , y2 , basis , parent_pos ) ;
Vector3 p1 = sim_to_render ( p1_sim , render_state - > distance_scale ) ;
Vector3 p2 = sim_to_render ( p2_sim , render_state - > distance_scale ) ;
DrawLine3D ( p1 , p2 , color ) ;
}
static void render_elliptical_orbit ( double a , double e , OrbitalBasis basis ,
Vec3 parent_pos , RenderState * render_state , Color color ) {
double b = a * sqrt ( 1.0 - e * e ) ;
double c = a * e ;
int segments = 100 ;
for ( int i = 0 ; i < segments ; i + + ) {
float theta1 = ( float ) i / segments * 2.0f * PI ;
float theta2 = ( float ) ( i + 1 ) / segments * 2.0f * PI ;
double x1 = a * cos ( theta1 ) - c ;
double y1 = b * sin ( theta1 ) ;
double x2 = a * cos ( theta2 ) - c ;
double y2 = b * sin ( theta2 ) ;
draw_orbit_segment ( x1 , y1 , x2 , y2 , basis , parent_pos , render_state , color ) ;
}
}
static void render_hyperbolic_orbit ( double p , double e , OrbitalBasis basis ,
Vec3 parent_pos , RenderState * render_state , Color color ) {
double max_true_anomaly = ( e > 1.01 ) ? acos ( - 1.0 / e ) * 0.95 : PI * 0.48 ;
int segments = 60 ;
for ( int i = 0 ; i < segments ; i + + ) {
float theta1 = - max_true_anomaly + ( float ) i / segments * 2.0f * max_true_anomaly ;
float theta2 = - max_true_anomaly + ( float ) ( i + 1 ) / segments * 2.0f * max_true_anomaly ;
double r1 = p / ( 1.0 + e * cos ( theta1 ) ) ;
double r2 = p / ( 1.0 + e * cos ( theta2 ) ) ;
double x1 = r1 * cos ( theta1 ) ;
double y1 = r1 * sin ( theta1 ) ;
double x2 = r2 * cos ( theta2 ) ;
double y2 = r2 * sin ( theta2 ) ;
draw_orbit_segment ( x1 , y1 , x2 , y2 , basis , parent_pos , render_state , color ) ;
}
}
// Render orbit path for a body
// Render orbit path for a body
void render_orbit ( CelestialBody * body , CelestialBody * parent , RenderState * render_state ) {
void render_orbit ( CelestialBody * body , CelestialBody * parent , RenderState * render_state ) {
if ( body - > parent_index = = - 1 | | parent = = NULL ) {
if ( body - > parent_index = = - 1 | | parent = = NULL ) {
return ;
return ;
}
}
double a = body - > semi_major_axis ;
Vec3 r_vec = vec3_sub ( body - > position , parent - > position ) ;
double e = body - > eccentricity ;
double r = vec3_magnitude ( r_vec ) ;
double v = vec3_magnitude ( body - > velocity ) ;
if ( a < = 0.0 ) {
if ( r < 1.0 ) return ;
return ;
}
double b = a * sqrt ( 1.0 - e * e ) ;
double mu = G * parent - > mass ;
double c = a * e ;
double specific_energy = ( v * v ) / 2.0 - mu / r ;
Vector3 parent_pos = sim_to_render ( parent - > position , render_state - > distance_scale ) ;
double v_squared = v * v ;
double r_dot_v = r_vec . x * body - > velocity . x + r_vec . y * body - > velocity . y + r_vec . z * body - > velocity . z ;
Vec3 e_vec = {
( v_squared - mu / r ) * r_vec . x - r_dot_v * body - > velocity . x ,
( v_squared - mu / r ) * r_vec . y - r_dot_v * body - > velocity . y ,
( v_squared - mu / r ) * r_vec . z - r_dot_v * body - > velocity . z
} ;
double e = vec3_magnitude ( e_vec ) / mu ;
Color orbit_color = {
Color orbit_color = {
( unsigned char ) ( body - > color [ 0 ] * 128 ) ,
( unsigned char ) ( body - > color [ 0 ] * 128 ) ,
@ -127,28 +219,20 @@ void render_orbit(CelestialBody* body, CelestialBody* parent, RenderState* rende
128
128
} ;
} ;
int segments = 100 ;
OrbitalBasis basis = calculate_orbital_basis ( r_vec , body - > velocity , e_vec ) ;
for ( int i = 0 ; i < segments ; i + + ) {
float theta1 = ( float ) i / segments * 2.0f * PI ;
float theta2 = ( float ) ( i + 1 ) / segments * 2.0f * PI ;
float x1 = ( float ) ( a * cos ( theta1 ) - c ) ;
if ( e < 0.98 ) {
float y1 = ( float ) ( b * sin ( theta1 ) ) ;
double a = - mu / ( 2.0 * specific_energy ) ;
float x2 = ( float ) ( a * cos ( theta2 ) - c ) ;
if ( a < = 0.0 ) return ;
float y2 = ( float ) ( b * sin ( theta2 ) ) ;
Vector3 p1 = {
render_elliptical_orbit ( a , e , basis , parent - > position , render_state , orbit_color ) ;
parent_pos . x + x1 * ( float ) render_state - > distance_scale ,
} else {
parent_pos . y ,
double a = ( e > 1.01 ) ? mu / ( 2.0 * ( - specific_energy ) ) : r / ( 1.0 + e ) ;
parent_pos . z + y1 * ( float ) render_state - > distance_scale
double p = a * ( 1.0 - e * e ) ;
} ;
Vector3 p2 = {
if ( p < = 0.0 ) return ;
parent_pos . x + x2 * ( float ) render_state - > distance_scale ,
parent_pos . y ,
parent_pos . z + y2 * ( float ) render_state - > distance_scale
} ;
DrawLine3D ( p1 , p2 , orbit_color ) ;
render_hyperbolic_orbit ( p , e , basis , parent - > position , render_state , orbit_color ) ;
}
}
}
}