aboutsummaryrefslogtreecommitdiff
path: root/docs
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-08-19 02:02:20 +0200
committerhachem <im@hachem.wtf>2026-08-19 02:02:20 +0200
commitf7e05555fb4ff6d8e51bdb5734db4dab1841d593 (patch)
tree353d350b19da7b84ca11e5801d33a921407a963e /docs
parent5c5fc10d8938fd2da1922f01c638d42e70eb1ab1 (diff)
[feat]: migrate to slang from glsl
Diffstat (limited to 'docs')
-rw-r--r--docs/configuration.md335
-rw-r--r--docs/mathematical-theory.md169
-rw-r--r--docs/numerical-methods.md50
-rw-r--r--docs/ray-tracing-implementation.md258
4 files changed, 0 insertions, 812 deletions
diff --git a/docs/configuration.md b/docs/configuration.md
deleted file mode 100644
index 293a4a6..0000000
--- a/docs/configuration.md
+++ /dev/null
@@ -1,335 +0,0 @@
-# Configuration
-## Configuration Files
-
-### Settings File Location
-
-The application uses TOML format for configuration files:
-
-- **Primary location**: `config/settings.toml`
-- **User settings**: Loaded at startup, saved on exit
-
-### TOML Format
-
-The configuration uses TOML format:
-
-```toml
-[simulation]
-max_steps_static = 15000
-max_steps_moving = 30000
-compute_height = 256
-target_fps = 60
-early_exit_distance = 5e+12
-gravity_enabled = true
-
-[graphics]
-render_api = "OpenGL"
-vsync_enabled = true
-enable_anti_aliasing = true
-show_fps = true
-show_performance_metrics = true
-show_debug_info = false
-selected_theme = "Dark"
-```
-
-## Simulation Parameters
-
-### Ray Tracing Settings
-
-#### Max Steps (Static)
-- **Description**: Maximum number of integration steps when camera is stationary
-- **Range**: 1,000 - 30,000
-- **Default**: 15,000
-- **Impact**: Higher values = better accuracy, lower performance
-
-```toml
-max_steps_static = 15000
-```
-
-#### Max Steps (Moving)
-- **Description**: Maximum number of integration steps when camera is moving
-- **Range**: 1,000 - 60,000
-- **Default**: 30,000
-- **Impact**: Higher values = smoother motion, lower performance
-
-```toml
-max_steps_moving = 30000
-```
-
-#### Early Exit Distance
-- **Description**: Distance at which ray marching stops to improve performance
-- **Range**: 1×10¹¹ - 1×10¹³ meters
-- **Default**: 5×10¹² meters
-- **Impact**: Lower values = faster rendering, may miss distant objects
-
-```toml
-early_exit_distance = 5e+12
-```
-
-### Performance Settings
-
-#### Target FPS
-- **Description**: Target frame rate for the application
-- **Range**: 30 - 120 FPS
-- **Default**: 60 FPS
-- **Impact**: Higher values = smoother animation, higher CPU usage
-
-```toml
-target_fps = 60
-```
-
-#### Compute Height
-- **Description**: Resolution of the compute shader (height component)
-- **Range**: 64 - 2,048 pixels
-- **Default**: 256 pixels
-- **Impact**: Higher values = better quality, lower performance
-
-```toml
-compute_height = 256
-```
-
-### Physics Settings
-
-#### Gravity Enabled
-- **Description**: Enable/disable gravitational interactions between objects
-- **Type**: Boolean
-- **Default**: true
-- **Impact**: Affects object motion and orbital dynamics
-
-```toml
-gravity_enabled = true
-```
-
-## Graphics Settings
-
-### Rendering API
-
-#### Render API
-- **Description**: Graphics API to use for rendering
-- **Options**: "OpenGL", "Vulkan"
-- **Default**: "OpenGL"
-- **Impact**: Affects performance and feature availability
-
-```toml
-render_api = "OpenGL"
-```
-
-### Display Settings
-
-#### V-Sync Enabled
-- **Description**: Enable vertical synchronization
-- **Type**: Boolean
-- **Default**: true
-- **Impact**: Prevents screen tearing, may limit frame rate
-
-```toml
-vsync_enabled = true
-```
-
-#### Enable Anti-Aliasing
-- **Description**: Enable anti-aliasing for smoother edges
-- **Type**: Boolean
-- **Default**: true
-- **Impact**: Better visual quality, slight performance cost
-
-```toml
-enable_anti_aliasing = true
-```
-
-### UI Settings
-
-#### Show FPS
-- **Description**: Display frame rate counter
-- **Type**: Boolean
-- **Default**: true
-- **Impact**: Performance monitoring, minimal overhead
-
-```toml
-show_fps = true
-```
-
-#### Show Performance Metrics
-- **Description**: Display detailed performance information
-- **Type**: Boolean
-- **Default**: true
-- **Impact**: Debug information, minimal overhead
-
-```toml
-show_performance_metrics = true
-```
-
-#### Show Debug Info
-- **Description**: Display debug information
-- **Type**: Boolean
-- **Default**: false
-- **Impact**: Development information, may impact performance
-
-```toml
-show_debug_info = false
-```
-
-#### Selected Theme
-- **Description**: UI theme selection
-- **Options**: "Dark", "Light"
-- **Default**: "Dark"
-- **Impact**: Visual appearance only
-
-```toml
-selected_theme = "Dark"
-```
-
-## Performance Tuning
-
-### Preset-Performance
-
-The configuration system allows users to balance quality and performance:
-
-#### High Quality Settings
-```toml
-[simulation]
-max_steps_static = 30000
-max_steps_moving = 60000
-compute_height = 1024
-early_exit_distance = 1e+13
-```
-
-#### Balanced Settings
-```toml
-[simulation]
-max_steps_static = 15000
-max_steps_moving = 30000
-compute_height = 512
-early_exit_distance = 5e+12
-```
-
-#### Performance Settings
-```toml
-[simulation]
-max_steps_static = 5000
-max_steps_moving = 10000
-compute_height = 256
-early_exit_distance = 2e+12
-```
-
-### Adaptive Performance
-
-The application automatically adjusts performance based on conditions:
-
-```glsl
-// Reduce steps for distant cameras
-float cameraDistance = length(cam.camPos);
-if (cameraDistance > 2e12)
- maxSteps = maxSteps / 2;
-else if (cameraDistance > 1e12)
- maxSteps = int(maxSteps * 0.75);
-
-// Reduce steps for escaping rays
-float initialEscapeVelocity = sqrt(2.0 * SagA_rs / ray.r);
-if (ray.dr > initialEscapeVelocity * 0.95 && ray.r > SagA_rs * 200.0)
- maxSteps = maxSteps / 2;
-```
-
-## Configuration Interface
-
-### GUI Configuration
-
-The application provides a graphical interface for configuration:
-
-```cpp
-void ConfigState::OnImGuiRender()
-{
- ImGui::Begin("Configuration");
-
- // Simulation settings
- ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Simulation");
- ImGui::Separator();
-
- ImGui::SliderInt("Max Steps (Static)", &m_MaxStepsStatic, 1000, 30000, "%d");
- ImGui::SliderInt("Max Steps (Moving)", &m_MaxStepsMoving, 1000, 60000, "%d");
- ImGui::SliderFloat("Early Exit Distance", &m_EarlyExitDistance, 1e11f, 1e13f, "%.2e");
- ImGui::SliderInt("Compute Height", &m_ComputeHeight, 64, 2048, "%d px");
- ImGui::SliderInt("Target FPS", &m_TargetFPS, 30, 120, "%d");
-
- // Physics settings
- ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Physics");
- ImGui::Separator();
-
- ImGui::Checkbox("Enable Gravity", &m_GravityEnabled);
-
- // Graphics settings
- ImGui::TextColored(ImVec4(0.9f, 0.9f, 1.0f, 1.0f), "Graphics");
- ImGui::Separator();
-
- ImGui::Checkbox("V-Sync", &m_VSyncEnabled);
- ImGui::Checkbox("Anti-Aliasing", &m_AntiAliasingEnabled);
- ImGui::Checkbox("Show FPS", &m_ShowFPS);
- ImGui::Checkbox("Performance Metrics", &m_ShowPerformanceMetrics);
-
- ImGui::End();
-}
-```
-
-
-## Default Configurations
-
-### Preset Configurations
-
-The application includes several preset configurations:
-
-#### Ultra Quality
-```toml
-[simulation]
-max_steps_static = 50000
-max_steps_moving = 100000
-compute_height = 2048
-early_exit_distance = 1e+13
-target_fps = 30
-```
-
-#### High Quality
-```toml
-[simulation]
-max_steps_static = 30000
-max_steps_moving = 60000
-compute_height = 1024
-early_exit_distance = 8e+12
-target_fps = 60
-```
-
-#### Balanced
-```toml
-[simulation]
-max_steps_static = 15000
-max_steps_moving = 30000
-compute_height = 512
-early_exit_distance = 5e+12
-target_fps = 60
-```
-
-#### Performance
-```toml
-[simulation]
-max_steps_static = 5000
-max_steps_moving = 10000
-compute_height = 256
-early_exit_distance = 2e+12
-target_fps = 120
-```
-
-## Troubleshooting
-
-### Common Issues
-
-#### Performance Problems
-- **Symptom**: Low frame rate, stuttering
-- **Solution**: Reduce `max_steps_moving`, `max_steps_static`, or `compute_height`
-- **Alternative**: Increase `early_exit_distance`
-
-#### Quality Issues
-- **Symptom**: Poor image quality, artifacts
-- **Solution**: Increase `compute_height` and step counts
-- **Alternative**: Reduce `early_exit_distance`
-
-#### Configuration Errors
-- **Symptom**: Application crashes on startup
-- **Solution**: Delete configuration file to reset to defaults
-- **Alternative**: Check TOML syntax in settings file \ No newline at end of file
diff --git a/docs/mathematical-theory.md b/docs/mathematical-theory.md
deleted file mode 100644
index 4c73425..0000000
--- a/docs/mathematical-theory.md
+++ /dev/null
@@ -1,169 +0,0 @@
-# Mathematical Theory of Black Hole Geodesics
-
-### Einstein’s Field Equations
-
-General Relativity describes gravity not as a force, but as the curvature of spacetime caused by mass and energy. This curvature is captured by **Einstein’s field equations**:
-
-$$
-G_{\mu\nu} = \frac{8\pi G}{c^4} T_{\mu\nu}
-$$
-
-Here:
-
-* $G_{\mu\nu}$ is the **Einstein tensor**, describing spacetime curvature.
-* $T_{\mu\nu}$ is the **stress-energy tensor**, representing matter and energy.
-* $G$ is Newton’s gravitational constant, and $c$ is the speed of light.
-
-### Spacetime Metric
-
-Distances in spacetime are described using the **metric tensor** $g_{\mu\nu}$:
-
-$$
-ds^2 = g_{\mu\nu} dx^\mu dx^\nu
-$$
-
-where $ds^2$ is the spacetime interval between two events.
-
-## Schwarzschild Metric
-
-For a **spherically symmetric, non-rotating mass** (like a static black hole), the Schwarzschild solution gives the spacetime geometry:
-
-$$
-ds^2 = -\left(1 - \frac{2GM}{c^2 r}\right) dt^2 + \left(1 - \frac{2GM}{c^2 r}\right)^{-1} dr^2 + r^2 (d\theta^2 + \sin^2\theta \, d\phi^2)
-$$
-
-* $M$ = mass of the black hole
-* $r, \theta, \phi$ = spherical coordinates
-* $t$ = time coordinate
-
-The **Schwarzschild radius** $r_s$ marks the event horizon:
-
-$$
-r_s = \frac{2GM}{c^2}
-$$
-
-Inside $r_s$, not even light can escape.
-
-We often write the metric using the **lapse function** $f(r)$:
-
-$$
-ds^2 = -f(r) dt^2 + f(r)^{-1} dr^2 + r^2 (d\theta^2 + \sin^2\theta \, d\phi^2), \quad f(r) = 1 - \frac{r_s}{r}
-$$
-
-## Geodesics: Paths of Free-Falling Particles and Light
-
-A **geodesic** is the path that a particle follows when moving under gravity alone. For light rays, $ds^2 = 0$ (null geodesics).
-
-### Lagrangian Formulation
-
-We can derive the geodesic equations from a Lagrangian:
-
-$$
-L = \frac{1}{2} g_{\mu\nu} \dot{x}^\mu \dot{x}^\nu, \quad \dot{x}^\mu = \frac{dx^\mu}{d\lambda}
-$$
-
-where $\lambda$ is an affine parameter along the geodesic.
-
-### Conserved Quantities
-
-Because the Schwarzschild metric is **time-independent** and **spherically symmetric**, we have two key conserved quantities:
-
-1. **Energy** (from time translation symmetry):
-
-$$
-E = - g_{tt} \frac{dt}{d\lambda} = f(r) \frac{dt}{d\lambda}
-$$
-
-2. **Angular Momentum** (from rotational symmetry):
-
-$$
-L = g_{\phi\phi} \frac{d\phi}{d\lambda} = r^2 \sin^2 \theta \frac{d\phi}{d\lambda}
-$$
-
-### Derivation of the Geodesic Equations
-
-Geodesics satisfy the **Euler-Lagrange equations**:
-
-$$
-\frac{d}{d\lambda} \left(\frac{\partial L}{\partial \dot{x}^\mu}\right) - \frac{\partial L}{\partial x^\mu} = 0
-$$
-
-#### 1. Radial Motion
-
-For the Schwarzschild metric:
-
-$$
-L = \frac{1}{2} \left[-f(r) \dot{t}^2 + f(r)^{-1} \dot{r}^2 + r^2 (\dot{\theta}^2 + \sin^2\theta \, \dot{\phi}^2)\right]
-$$
-
-The radial Euler-Lagrange equation becomes:
-
-$$
-\ddot{r} = -\frac{GM}{r^2} (\dot{t})^2 + \frac{GM}{r^2 f(r)} (\dot{r})^2 + r f(r) \left(\dot{\theta}^2 + \sin^2\theta \, \dot{\phi}^2\right)
-$$
-
-#### 2. Angular Motion
-
-$$
-\ddot{\theta} = -\frac{2}{r} \dot{r} \dot{\theta} + \sin\theta \cos\theta \, \dot{\phi}^2
-$$
-
-$$
-\ddot{\phi} = -\frac{2}{r} \dot{r} \dot{\phi} - 2 \cot\theta \, \dot{\theta} \dot{\phi}
-$$
-
-Here, $\dot{}$ denotes derivative with respect to $\lambda$.
-
-These equations fully describe how light or particles move around a Schwarzschild black hole.
-
-### Numerical Implementation
-
-In a shader or simulation, we integrate these equations using:
-
-```glsl
-void GeodesicRHS(Ray ray, out vec3 d1, out vec3 d2)
-{
- float r = ray.r;
- float theta = ray.theta;
- float dr = ray.dr;
- float dtheta = ray.dtheta;
- float dphi = ray.dphi;
- float f = 1.0 - SagA_rs / r;
- float dt_dL = ray.E / f;
-
- d1 = vec3(dr, dtheta, dphi);
- d2.x = - (SagA_rs / (2.0 * r*r)) * f * dt_dL * dt_dL
- + (SagA_rs / (2.0 * r*r * f)) * dr * dr
- + r * (dtheta*dtheta + sin(theta)*sin(theta)*dphi*dphi);
- d2.y = -2.0*dr*dtheta/r + sin(theta)*cos(theta)*dphi*dphi;
- d2.z = -2.0*dr*dphi/r - 2.0*cos(theta)/(sin(theta)) * dtheta * dphi;
-}
-```
-
-### Conserved Quantities in Code
-
-```glsl
-ray.E = f * dt_dL; // Energy
-ray.L = ray.r * ray.r * sin(ray.theta) * ray.dphi; // Angular momentum
-```
-
-### Effective Potential
-
-The **radial motion** can be described using an effective potential:
-
-$$
-V_\text{eff}(r) = \left(1 - \frac{r_s}{r}\right) \frac{L^2}{r^2}
-$$
-
-This potential defines the possible orbits of light or particles.
-
-### Relativistic Effects Around Black Holes
-
-* **Gravitational Lensing:** Light bends around the black hole, producing Einstein rings, multiple images, or distorted images.
-* **Event Horizon:** Located at $r = r_s$, where nothing escapes.
-* **Photon Sphere:** At $r = 1.5 r_s$, light can orbit in unstable circular paths.
-
-### Numerical Considerations
-
-* **Event Horizon:** Integration becomes singular at $r = r_s$. Use adaptive step sizes or terminate integration near the horizon.
-* **Coordinate Poles:** Spherical coordinates have singularities at $\theta = 0, \pi$. Avoid direct integration through these points or use transformations.
diff --git a/docs/numerical-methods.md b/docs/numerical-methods.md
deleted file mode 100644
index 4e102e6..0000000
--- a/docs/numerical-methods.md
+++ /dev/null
@@ -1,50 +0,0 @@
-## Runge-Kutta 4 (RK4) Integration — Explained
-
-When we talk about geodesics in curved spacetime, we’re dealing with a system of differential equations that describe how a particle—or in our case, a ray of light—moves. These equations are usually too complicated to solve exactly, so we turn to numerical methods. One of the most popular choices is the **fourth-order Runge-Kutta method (RK4)**.
-
-Think of RK4 like taking careful steps along a winding mountain trail. At each step, instead of just looking straight ahead, RK4 takes a few “sneak peeks” along the way to estimate the path more accurately.
-
-### The Idea in Simple Terms
-
-Suppose you know where you are at a particular moment and you know the slope of your path (the derivative). A naive method like **Euler’s method** would take a single step using that slope and call it a day. But if the slope changes a lot along your step, Euler can easily go off-track.
-
-RK4 improves on this by taking **four evaluations** of the slope at carefully chosen points:
-
-1. **Start of the step** — check the slope right where you are (`k1`).
-2. **Halfway in, using the first slope** — imagine taking a mid-step to see if the slope changes (`k2`).
-3. **Halfway in, using the second slope** — another mid-step with a slightly better estimate (`k3`).
-4. **End of the step** — take a peek at the slope at the far end of your step (`k4`).
-
-Then RK4 combines all these slopes in a weighted average:
-
-$$
-y_{n+1} = y_n + \frac{h}{6} (k_1 + 2 k_2 + 2 k_3 + k_4)
-$$
-
-This weighted combination gives a very accurate estimate of where you should be at the next step.
-
-### Why RK4 Works Well for Geodesics
-
-In the context of geodesics:
-
-* Each ray has six “pieces of information”: position `(r, θ, φ)` and velocity `(dr/dλ, dθ/dλ, dφ/dλ)`.
-* The RK4 method allows us to update all six components **simultaneously**, while keeping the accumulated error small.
-* Because spacetime curvature can change dramatically near a black hole, RK4 is especially helpful: it’s stable enough to handle strong curvature without requiring tiny steps everywhere.
-
-### A Visual Analogy
-
-Imagine you’re rowing a boat down a twisting river:
-
-* **Euler**: You look at the current direction, row a fixed distance, and hope for the best. You’ll likely drift off course if the river bends sharply.
-* **RK4**: You peek ahead four times along your intended path and adjust your stroke accordingly. You stay much closer to the true river path, even around tight bends.
-
-### Accuracy
-
-* RK4 is called **fourth-order** because the error per step scales with $h^5$, and the total accumulated error scales roughly with $h^4$ (where $h$ is your step size).
-* This means you can take reasonably large steps without losing accuracy, which is critical when simulating millions of rays efficiently.
-
-### Connecting to Code
-
-In your code, each `k` evaluation corresponds to calculating how the ray’s position and velocity would change at different “guesses” along the step. The final weighted combination moves the ray forward accurately in spacetime.
-
-By using RK4, we’re essentially giving each ray a **very careful and informed nudge**, instead of blindly pushing it along, which is why the results are both stable and accurate—even near the extreme curvature of a black hole. \ No newline at end of file
diff --git a/docs/ray-tracing-implementation.md b/docs/ray-tracing-implementation.md
deleted file mode 100644
index 89778b7..0000000
--- a/docs/ray-tracing-implementation.md
+++ /dev/null
@@ -1,258 +0,0 @@
-# Ray Tracing in Curved Spacetime: A Detailed Overview
-
-This ray tracer simulates how light behaves near a black hole, including the effects of curved spacetime and interactions with objects like stars and an accretion disk. The implementation follows a step-by-step approach, which includes initializing rays, tracing their paths through spacetime, detecting intersections with objects, and finally rendering the scene.
-
-## 1. Ray Initialization
-
-The first step in ray tracing is to create rays originating from the camera that will eventually traverse through spacetime. Each ray represents a possible path of light.
-
-### Camera Setup
-
-The camera is positioned in three-dimensional space and is defined by its orientation and field of view. It has the following parameters:
-
-```glsl
-layout(std140, binding = 1) uniform Camera
-{
- vec3 camPos; float _pad0;
- vec3 camRight; float _pad1;
- vec3 camUp; float _pad2;
- vec3 camForward; float _pad3;
- float tanHalfFov; // Field of view
- float aspect; // Aspect ratio
- bool moving; // Whether the camera is moving
- int _pad4;
-} cam;
-```
-
-- `camPos`: The 3D position of the camera.
-- `camRight`, `camUp`, `camForward`: Orthonormal vectors defining the camera's orientation.
-- `tanHalfFov` and `aspect`: Determine the camera’s field of view and the shape of the image plane.
-
-### Ray Generation per Pixel
-
-For each pixel on the image, we calculate the corresponding direction in world space and generate a ray pointing in that direction:
-
-```glsl
-float u = (2.0 * (pix.x + 0.5) / WIDTH - 1.0) * cam.aspect * cam.tanHalfFov;
-float v = (1.0 - 2.0 * (pix.y + 0.5) / HEIGHT) * cam.tanHalfFov;
-vec3 dir = normalize(u * cam.camRight - v * cam.camUp + cam.camForward);
-Ray ray = InitRay(cam.camPos, dir);
-```
-
-Here, `u` and `v` are normalized coordinates on the image plane. The `InitRay` function takes the camera position and the computed direction to create a ray in both Cartesian and spherical coordinates.
-
-### Ray Structure
-
-Each ray contains not only the standard 3D Cartesian position but also spherical coordinates and velocity components, which are necessary for simulating curved spacetime:
-
-```glsl
-struct Ray
-{
- float x, y, z; // Cartesian coordinates
- float r, theta, phi; // Spherical coordinates
- float dr, dtheta, dphi; // Radial and angular velocities
- float E, L; // Conserved quantities in Schwarzschild geometry
-};
-```
-
-### Converting Cartesian to Spherical Coordinates
-
-The `InitRay` function converts the position and direction of the ray into spherical coordinates and computes initial velocities:
-
-```glsl
-Ray InitRay(vec3 pos, vec3 dir)
-{
- Ray ray;
- ray.x = pos.x;
- ray.y = pos.y;
- ray.z = pos.z;
-
- // Spherical coordinates
- ray.r = length(pos);
- ray.theta = acos(pos.z / ray.r);
- ray.phi = atan(pos.y, pos.x);
-
- // Convert direction vector to spherical velocities
- float dx = dir.x;
- float dy = dir.y;
- float dz = dir.z;
-
- ray.dr = sin(ray.theta)*cos(ray.phi)*dx + sin(ray.theta)*sin(ray.phi)*dy + cos(ray.theta)*dz;
- ray.dtheta = (cos(ray.theta)*cos(ray.phi)*dx + cos(ray.theta)*sin(ray.phi)*dy - sin(ray.theta)*dz) / ray.r;
- ray.dphi = (-sin(ray.phi)*dx + cos(ray.phi)*dy) / (ray.r * sin(ray.theta));
-
- // Calculate conserved quantities (energy E and angular momentum L)
- ray.L = ray.r * ray.r * sin(ray.theta) * ray.dphi;
- float f = 1.0 - SagA_rs / ray.r;
- float dt_dL = sqrt((ray.dr*ray.dr)/f + ray.r*ray.r*(ray.dtheta*ray.dtheta + sin(ray.theta)*sin(ray.theta)*ray.dphi*ray.dphi));
- ray.E = f * dt_dL;
-
- return ray;
-}
-```
-
-## 2. Geodesic Integration
-
-Once the ray is initialized, we trace its path through curved spacetime using the Schwarzschild metric. This requires solving the geodesic equations for the ray.
-
-### Integration Loop
-
-The ray is advanced step by step using a numerical integrator (Runge-Kutta 4th order). The loop continues until the ray either escapes the scene, falls into the black hole, or intersects an object.
-
-```glsl
-for (int i = 0; i < maxSteps; ++i)
-{
- if (ray.r > exitDistance) break;
- if (ray.r > ESCAPE_R) break;
- if (Intercept(ray, SagA_rs)) { hitBlackHole = true; break; }
-
- currentStepSize = CalculateAdaptiveStepSize(ray, D_LAMBDA);
- RK4Step(ray, currentStepSize);
- lambda += currentStepSize;
-
- vec3 newPos = vec3(ray.x, ray.y, ray.z);
- if (CrossesEquatorialPlane(prevPos, newPos)) { hitDisk = true; break; }
- if (i % objectCheckInterval == 0 && InterceptObject(ray)) { hitObject = true; break; }
-
- prevPos = newPos;
-}
-```
-
-### Runge-Kutta 4 (RK4)
-
-The RK4 integrator provides high accuracy by computing intermediate slopes and averaging them to advance the ray:
-
-```glsl
-void RK4Step(inout Ray ray, float dL)
-{
- vec3 k1a, k1b;
- GeodesicRHS(ray, k1a, k1b);
-
- ray.r += dL * k1a.x;
- ray.theta += dL * k1a.y;
- ray.phi += dL * k1a.z;
- ray.dr += dL * k1b.x;
- ray.dtheta += dL * k1b.y;
- ray.dphi += dL * k1b.z;
-
- // Update Cartesian coordinates
- ray.x = ray.r * sin(ray.theta) * cos(ray.phi);
- ray.y = ray.r * sin(ray.theta) * sin(ray.phi);
- ray.z = ray.r * cos(ray.theta);
-}
-```
-
-### Geodesic Derivatives
-
-The function `GeodesicRHS` computes the derivatives needed for integration:
-
-```glsl
-void GeodesicRHS(Ray ray, out vec3 d1, out vec3 d2)
-{
- float r = ray.r;
- float theta = ray.theta;
- float dr = ray.dr;
- float dtheta = ray.dtheta;
- float dphi = ray.dphi;
- float f = 1.0 - SagA_rs / r;
- float dt_dL = ray.E / f;
-
- d1 = vec3(dr, dtheta, dphi);
-
- d2.x = - (SagA_rs / (2.0 * r*r)) * f * dt_dL * dt_dL
- + (SagA_rs / (2.0 * r*r * f)) * dr * dr
- + r * (dtheta*dtheta + sin(theta)*sin(theta)*dphi*dphi);
- d2.y = -2.0*dr*dtheta/r + sin(theta)*cos(theta)*dphi*dphi;
- d2.z = -2.0*dr*dphi/r - 2.0*cos(theta)/(sin(theta)) * dtheta * dphi;
-}
-```
-
-## 3. Intersection Testing
-
-Rays can intersect three types of entities: the black hole, spherical objects, and the accretion disk.
-
-### Black Hole Intersection
-
-A ray hitting the event horizon is considered absorbed:
-
-```glsl
-bool Intercept(Ray ray, float rs)
-{
- return ray.r <= rs;
-}
-```
-
-### Object Intersection
-
-The scene can contain multiple spherical objects such as stars or planets:
-
-```glsl
-bool InterceptObject(Ray ray)
-{
- vec3 P = vec3(ray.x, ray.y, ray.z);
-
- for (int i = 0; i < numObjects; ++i)
- {
- vec3 center = objPosRadius[i].xyz;
- float radius = objPosRadius[i].w;
-
- float distSq = dot(P - center, P - center);
- if (distSq > radius * radius * 4.0) continue;
- if (distSq <= radius * radius)
- {
- objectColor = objColor[i];
- hitCenter = center;
- hitRadius = radius;
- return true;
- }
- }
- return false;
-}
-```
-
-### Accretion Disk Intersection
-
-The accretion disk lies in the equatorial plane and is checked by detecting if the ray crosses this plane:
-
-```glsl
-bool CrossesEquatorialPlane(vec3 oldPos, vec3 newPos)
-{
- bool crossed = (oldPos.y * newPos.y <0.0);
- if (crossed) { diskIntersection = newPos; }
- return crossed;
-}
-```
-
-## 4. Shading and Color Computation
-
-Once an intersection is found, we compute the color of the pixel based on the object hit and relativistic effects such as gravitational redshift and Doppler shift.
-
-```glsl
-vec3 ComputeColor(Ray ray)
-{
- if (hitBlackHole) return vec3(0.0); // Black hole is black
- if (hitDisk) return SampleDiskTexture(diskIntersection);
- if (hitObject) return ApplyLighting(ray, objectColor, hitCenter, hitRadius);
-
- return SampleBackground(ray); // Background stars, etc.
-}
-````
-
-This ensures that each pixel reflects both the geometrical position and relativistic effects along the ray.
-
-## 5. Rendering Loop
-
-Finally, the main rendering loop iterates over every pixel on the screen, traces a ray, and stores the computed color:
-
-```glsl
-for (int y = 0; y < HEIGHT; ++y)
-{
- for (int x = 0; x < WIDTH; ++x)
- {
- Ray ray = InitRayForPixel(x, y);
- TraceRay(ray);
- vec3 color = ComputeColor(ray);
- framebuffer[y*WIDTH + x] = vec4(color, 1.0);
- }
-}
-``` \ No newline at end of file