Skip to content

cannellegrdt/Interstonar

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

6 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Interstonar

Physics simulation for rock trajectory - global N-body gravity and local ray marching - EPITECH G-CNA-400 Project


Table of contents

  1. Overview
  2. Compilation
  3. Usage
  4. The TOML configuration file
  5. Output format
  6. Bonus: RK4 integrator
  7. Bonus: Real-time viewer
  8. Project architecture
  9. Exploration: Non-Euclidean raymarching in H³

Overview

Interstonar simulates the trajectory of a thrown rock in two distinct modes:

  • Global mode - computes the rock's path through a planetary scene under Newtonian gravity, using Euler integration. Celestial bodies can collide and merge during the simulation.
  • Local mode - determines which shape (if any) the rock intersects in a local scene, using sphere-assisted ray marching and Signed Distance Functions (SDF).

Subject is in G-CNA-400_interstonar.pdf.


Compilation

# Compile in release mode
cargo build --release

# Run unit tests
cargo test

# The binary will be at
./target/release/interstonar

Usage

./interstonar [--global | --local] CONFIG_FILE [-d TIME | --delta=TIME] Px Py Pz Vx Vy Vz
Argument Description
--global Launch in global scene mode (massive moving bodies)
--local Launch in local scene mode (massless motionless shapes)
CONFIG_FILE TOML configuration file describing the scene
-d TIME, --delta=TIME Delta time in seconds - global mode only
Px Py Pz Initial position of the rock (SI units)
Vx Vy Vz Initial velocity vector of the rock

Examples:

# Global: rock collides the Sun after 3 steps
./interstonar --global scene.toml --delta=3600 1 2 3 4 5 6

# Local: find which shape the rock hits
./interstonar --local shapes.toml 10 0 35 -1 0 -2

The TOML configuration file

All entries use [[body]] tables. Every value is in SI base units.

Global mode

Each body requires: name, position, direction, mass, radius.

[[body]]
name = "Sun"
position = {x = 1.81899E+8, y = 9.83630E+8, z = -1.58778E+8}
direction = {x = -1.12474E+1, y = 7.54876E+0, z = 2.68723E-1}
mass = 1.98854e30
radius = 696_342_000

[[body]]
name = "Earth"
position = {x = 0, y = 1.496E+11, z = 0}
direction = {x = -2.978E+4, y = 0, z = 0}
mass = 5.972E+24
radius = 6_371_000

Simulation rules:

  • Gravitation follows Newton's law: F = G·m₁·m₂/r², with G = 6.674×10⁻¹¹ m³·kg⁻¹·s⁻²
  • Rock mass is fixed at 1,000 kg
  • Positions updated via Euler integration
  • Stops after a collision or 1,000 deltas
  • If two bodies (not the rock) collide, they merge: masses sum, radius from combined volume, position/velocity are mass-weighted means, name is ASCII-sorted concatenation with -

Local mode

Each body requires: type, position, and shape-specific properties. name is optional (defaults to TYPE_N).

[[body]]
name = "s1"
type = "sphere"
position = {x = 0, y = 0, z = 0}
radius = 1

[[body]]
type = "cylinder"
position = {x = 0, y = 0, z = 0}
radius = 1
height = 100   # optional - infinite if omitted

[[body]]
type = "box"
position = {x = 0, y = 0, z = 0}
sides = {x = 10, y = 10, z = 10}

[[body]]
name = "t1"
type = "torus"
position = {x = 0, y = 0, z = 0}
inner_radius = 3
outer_radius = 1

Supported shapes: sphere, cylinder, box, torus.

Ray marching rules:

  • Intersection when SDF ≤ 0.1
  • No intersection if > 1,000 steps or distance to closest object > 1,000

Output format

Global

Rock coordinates (x y z) are:
t = 0: (Px Py Pz)
t = 1: (...)
...
Collision between rock and <name>   ← if collision
Mission success                     ← collision occurred
Mission failure                     ← 1000 steps reached without collision

Local

Rock thrown at the point (Px, Py, Pz) and parallel to the vector (Vx, Vy, Vz)
<shape description line per shape>
Step 1: (x, y, z)
...
Result: Intersection with <NAME>    ← hit
Result: Out of scene                ← diverged
Result: Steps limit reached         ← 1000 steps, no hit

Bonus: RK4 integrator

The --rk4 flag replaces the default Euler integrator with a 4th-order Runge-Kutta integrator in global mode.

./interstonar --global scene.toml --delta=3600 --rk4 1 2 3 4 5 6

--rk4 is only available in --global mode.

Why RK4?

Integrator Derivative evaluations / step Error per step
Euler 1 O(Δt²)
RK4 4 O(Δt⁵)

Euler accumulates O(Δt) global error and visibly drifts on orbital trajectories (spiralling inward or outward). RK4 keeps orbits stable over the same number of steps.

How it works

For each step RK4 computes four slope estimates and combines them:

k1 = f(t,       y)
k2 = f(t + h/2, y + h/2 · k1)
k3 = f(t + h/2, y + h/2 · k2)
k4 = f(t + h,   y + h   · k3)

y(t+h) = y + h/6 · (k1 + 2·k2 + 2·k3 + k4)

where y = (position, velocity) and f = gravitational accelerations. Both the rock and all celestial bodies are integrated simultaneously so each intermediate evaluation uses a coherent snapshot of all positions.


Bonus: Real-time viewer

The --view flag activates a real-time 3D viewer for local scenes rendered with CPU sphere-traced ray marching.

./interstonar --local shapes.toml --view Px Py Pz Vx Vy Vz

--view is only available in --local mode. The rock position and velocity arguments are still required but are ignored when the viewer is active.

The viewer renders the scene once into a 1920 × 1080 framebuffer, then enters an event loop until the window is closed.

Camera

Property Value
Position (0, 2, -8)
Direction +Z
Field of view 60°
Max ray distance 200
Max ray steps 256

Shape colours

Each shape type is assigned a fixed base colour, then shaded with an ambient + diffuse lighting model (ambient = 0.15, light at (0.5, 1.0, -0.5) normalised). Surface normals are estimated by central differences on the scene SDF.

Shape RGB (normalised) Appearance
Sphere (0.20, 0.60, 1.00) Blue
Box (1.00, 0.50, 0.20) Orange
Cylinder (0.30, 0.90, 0.40) Green
Torus (0.90, 0.30, 0.60) Pink

Controls

Action Effect
Escape Close the viewer
Click window × Close the viewer

Makefile shortcut

make view CONFIG=shapes.toml PX=0 PY=0 PZ=0 VX=0 VY=0 VZ=1

Exploration: Non-Euclidean raymarching in H³

The current ray marching operates in flat Euclidean space: rays travel in straight lines and distances are the standard Euclidean norm. It is possible to extend this to hyperbolic space H³, where space has a constant negative curvature — objects in the distance shrink exponentially, parallel lines diverge, and the angles of a triangle sum to less than 180°.

The core idea

H³ is modelled as a surface in ℝ⁴ with the Minkowski metric:

H³ = { x ∈ ℝ⁴  |  ⟨x, x⟩_M = -1,  x₀ > 0 }
⟨u, v⟩_M = -u₀v₀ + u₁v₁ + u₂v₂ + u₃v₃

Three Euclidean operations are replaced:

Operation Euclidean Hyperbolic H³
Ray step p + t·d cosh(t)·p + sinh(t)·d
Distance ‖p − q‖ acosh(-⟨p, q⟩_M)
SDF sphere ‖p − c‖ − r acosh(-⟨p, c⟩_M) − r

The direction vector is also parallel-transported at each step (it rotates as the ray follows the curved geodesic) and both position and direction are periodically renormalized to prevent numerical drift off the H³ surface.

What changes in the code

  • src/vec3.rs — add a Vec4 type with mink() (Minkowski dot product), lift_to_h3(), lift_direction(), and hyp_dist().
  • src/local/shape.rs — add sdf_sphere_h3 and sdf_cylinder_h3 using hyperbolic distances, plus a sdf_scene_h3 dispatcher.
  • src/local/raymarching.rs — add raymarching_h3 replacing the linear step with the geodesic formula and transport.

Project architecture

.
├── src/
│   ├── main.rs           # Entry point, mode dispatch
│   ├── args.rs           # CLI argument parsing (clap)
│   ├── config.rs         # TOML deserialization
│   ├── vec3.rs           # 3D vector math
│   ├── global/
│   │   ├── body.rs       # Celestial body struct + merging logic
│   │   └── simulation.rs # Euler integration, collision detection
│   └── local/
│       ├── shape.rs      # Shape types + SDF implementations
│       ├── raymarching.rs# Sphere-assisted ray marching
│       └── viewer.rs     # Real-time ray marching viewer (bonus)
├── tests/
│   └── unit_tests/       # Unit tests per module
├── Cargo.toml
└── G-CNA-400_interstonar.pdf