Blackhole is a high-performance, real-time visualization of gravitational lensing caused by a black hole. This Rust-based application demonstrates the physics of how massive objects bend spacetime and alter the paths of light rays passing nearby. The simulation includes realistic accretion disk physics, planetary orbital dynamics, and ray-tracing techniques to visualize the complex light paths around a black hole.
- Features
- Visual Assets
- Technical Architecture
- Physics Concepts
- Mathematical Foundations
- Implementation Details
- Performance Optimizations
- Dependencies
- Building and Running
- Controls
- Contributing
- Real-time visualization of gravitational lensing effects
- Interactive camera navigation around the black hole
- Accurate simulation of accretion disk physics
- Orbital planet visualization
- Space fabric grid representation
- Physics-based ray tracing with Verlet integration
- Parallel rendering using Rayon
Check out these visual representations of the black hole simulation:
A video demonstration of the simulation is available in the assets folder: blackhole.mov
These visual assets demonstrate the gravitational lensing effects around the black hole, the accretion disk, and the orbital planet in the simulated environment.
The application is built with a modular architecture designed for performance and clarity:
- Rendering: Minifb provides cross-platform windowing and pixel drawing capabilities
- Mathematics: Glam offers vector math operations optimized for graphics applications
- Parallelism: Rayon enables efficient parallelization of ray tracing calculations
- Physics: Custom implementation of gravitational physics with adaptive time stopping
Camera: Handles user input and 3D camera transformationsPhysics Engine: Implements relativistic physics and particle trajectoriesRay Tracer: Simulates light paths around the black holeRenderer: Parallel computation of pixel colors
The simulation models the gravitational field around a non-rotating black hole using the Schwarzschild metric. The acceleration experienced by particles near the black hole follows an inverse cube law rather than the inverse square law typically seen in Newtonian gravity. This arises from the conservation of angular momentum in curved spacetime:
a = -1.5 * h² * Rs / r⁵
Where:
ais the acceleration vectorhis the specific angular momentumRsis the Schwarzschild radius (event horizon size)ris the distance from the black hole
The event horizon represents the boundary beyond which nothing, including light, can escape. In the simulation, any ray that enters this region is rendered as pure black.
The accretion disk consists of matter spiraling into the black hole. The material heats up due to friction and gravitational energy conversion, emitting light. The simulation models the disk as a ring in the y=0 plane between minimum and maximum radii.
Light rays passing near the black hole follow curved paths due to spacetime curvature. The simulation traces these paths using numerical integration to show how the black hole acts as a gravitational lens, bending light from background objects.
The simulation includes optimized mathematical functions for real-time performance:
#[inline(always)]
fn fast_sqrt(x: f32) -> f32 {
let i = x.to_bits();
let i = 0x1fbd1df5 + (i >> 1);
let y = f32::from_bits(i);
0.5 * (y + x / y)
}This uses bit manipulation to estimate the square root, similar to the famous Quake III fast inverse square root algorithm, followed by a Newton-Raphson refinement.
#[inline(always)]
fn fast_inv_sqrt(x: f32) -> f32 {
let i = x.to_bits();
let i = 0x5f375a86 - (i >> 1);
let y = f32::from_bits(i);
y * (1.5 - 0.5 * x * y * y)
}This is a direct implementation of the Quake III algorithm, providing a fast approximation of 1/√x.
The simulation uses ray-sphere intersection to detect collisions with planets:
// Quadratic coefficients: at² + bt + c = 0
let a = ray_len_sq;
let b = 2.0 * oc.dot(ray_dir);
let c = oc.length_squared() - sphere_radius_sq;
let discriminant = b * b - 4.0 * a * c;This solves the equation (o + td - c)² = r² where o is ray origin, d is direction, c is sphere center, and r is radius.
The simulation uses Verlet integration to numerically solve the equations of motion:
#[inline(always)]
fn verlet_step(pos: &mut Vec3, vel: &mut Vec3, h_sq: f32, dt: f32) {
let accel = get_accel_fast(*pos, h_sq);
let half_dt = dt * 0.5;
*vel += accel * half_dt;
*pos += *vel * dt;
let new_accel = get_accel_fast(*pos, h_sq);
*vel += new_accel * half_dt;
}This is a velocity-Verlet algorithm variant that maintains accuracy while conserving energy in the system.
Angular momentum is conserved in the gravitational system, calculated as:
let h_sq = pos.cross(vel).length_squared();This value remains constant throughout the particle's trajectory and affects the gravitational acceleration.
The simulation adjusts time steps based on proximity to the black hole:
let dt = if dist_sq > 400.0 {
BASE_STEP * 3.0 // Larger steps when far away
} else if dist_sq > 100.0 {
BASE_STEP * 2.0 // Medium steps at medium distances
} else if dist_sq < CLOSE_THRESHOLD_SQ {
BASE_STEP * 0.4 // Small steps when close to improve accuracy
} else {
BASE_STEP // Standard step size
};This optimization balances performance and accuracy by using larger steps when particles are far from strong gravitational fields.
The renderer checks for intersections with multiple objects in this priority order:
- Event horizon (black hole)
- Planets
- Accretion disk
- Space fabric grid
- Escape conditions
Different objects are rendered with physically-inspired color mappings:
- Accretion disk colors vary based on distance from the center
- Planet shading depends on position relative to light sources
- Grid colors alternate to provide depth perception
The renderer uses Rayon's parallel iterator to distribute pixel calculations across CPU cores:
buffer
.par_chunks_mut(WIDTH)
.enumerate()
.for_each(|(y, row)| {
// Process each row in parallel
});Performance-critical functions are marked with #[inline(always)] to eliminate function call overhead.
Buffers are allocated once at startup to avoid allocation overhead during rendering.
- minifb: Cross-platform windowing and input handling
- glam: Fast linear algebra library for 3D graphics
- rayon: Data parallelism library for Rust
- Rust 1.75+ (with edition 2024 support)
- Cargo package manager
-
Clone the repository:
git clone <repository-url> cd blackhole
-
Build the project:
cargo build --release
-
Run the application:
cargo run
For faster compilation during development:
cargo runFor optimal performance:
cargo run --release- WASD: Move camera horizontally
- Arrow Keys: Rotate camera view
- Space: Move camera upward
- Left Shift: Move camera downward
- Left Ctrl: Accelerate movement speed
- ESC: Exit the application
We welcome contributions! Please follow these steps:
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Write clear, descriptive commit messages
- Ensure all tests pass before submitting
- Update documentation for new features
- Follow Rust community best practices
This project is licensed under the MIT License - see the LICENSE file for details.
- Inspired by astronomical visualization techniques
- Based on theoretical physics principles from general relativity
- Special thanks to the Rust community for excellent libraries
