Compare commits

18 Commits
Author SHA1 Message Date
Quinta a03b8f45cc Merge remote-tracking branch 'origin/master' 2024-07-12 23:05:05 +02:00
Quinta 2baf55f798 Little things 2024-07-12 23:04:53 +02:00
Quinta 9e6ab91ab5 Create LICENSE 2024-07-12 19:50:41 +02:00
Quinta 769bd1a6ea Im loosing my fucking mind
:^)
2024-07-12 18:15:04 +02:00
Quinta 432bb3614f Im loosing my fucking mind
:^)
2024-07-12 18:01:54 +02:00
Quinta 796c34e9a0 TRying to make docker worky worky 2024-07-12 17:42:54 +02:00
Quinta 46d37ab529 Delete .github/workflows directory 2024-07-12 17:06:45 +02:00
Quinta cffec6061c Create build.yml 2024-07-12 17:05:36 +02:00
Quinta 0a5392e0bd Delete .github directory 2024-07-12 17:04:39 +02:00
Quinta 3dedc36cb0 Create workflows 2024-07-12 17:04:01 +02:00
Quinta 328a85feb1 Fixed wonky WASD movement 2024-07-12 16:58:21 +02:00
Quinta b3772ae0ac Removed useless comments 2024-07-12 16:19:04 +02:00
Quinta bae641845d Update README.md 2024-07-12 16:17:26 +02:00
Quinta 1d3ec737d3 Update README.md 2024-07-12 16:13:49 +02:00
Quinta 2afc695aba Resolved that annoying gravity bug and added trajectories, a grid, keyboard navigation and logarithimic scale 2024-07-12 16:07:49 +02:00
Quinta a93080b371 nothing just changed a name 2024-07-12 03:29:47 +02:00
Quinta 65998707ef Gave up on that fucking bug for today 2024-07-12 03:23:45 +02:00
Quinta 0528cfb93e Gave up on that fucking bug for today 2024-07-12 03:22:10 +02:00
18 changed files with 912 additions and 1 deletions
+3
View File
@@ -0,0 +1,3 @@
/cmake-build-debug/
/vcpkg_installed/
/build/
+8
View File
@@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
+2
View File
@@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakePythonSetting">
<option name="pythonIntegrationState" value="YES" />
</component>
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>
+8
View File
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/gravity.iml" filepath="$PROJECT_DIR$/.idea/gravity.iml" />
</modules>
</component>
</project>
Generated
+7
View File
@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/vcpkg" vcs="Git" />
</component>
</project>
+42
View File
@@ -0,0 +1,42 @@
cmake_minimum_required(VERSION 3.28)
project(gravity)
set(CMAKE_CXX_STANDARD 17)
# Use vcpkg
if(DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE)
set(CMAKE_TOOLCHAIN_FILE "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
CACHE STRING "Vcpkg toolchain file")
endif()
# Find packages
find_package(OpenGL REQUIRED)
find_package(GLEW REQUIRED)
find_package(glfw3 CONFIG REQUIRED)
find_package(glm CONFIG REQUIRED)
# Add executable
add_executable(gravity
main.cpp
CelestialBody.cpp
Simulator.cpp
Renderer.cpp
)
# Include directories
target_include_directories(gravity PRIVATE
${OPENGL_INCLUDE_DIRS}
${GLEW_INCLUDE_DIRS}
)
# Link libraries
target_link_libraries(gravity PRIVATE
${OPENGL_LIBRARIES}
GLEW::GLEW
glfw
glm::glm
)
if(UNIX AND NOT APPLE)
target_link_libraries(gravity PRIVATE GL)
endif()
+48
View File
@@ -0,0 +1,48 @@
//
// Created by Quinta on 7/12/2024.
//
#include "CelestialBody.h"
#include <iostream>
#include <sstream>
// Helper function to convert glm::vec3 to string
std::string vec3_to_string(const glm::vec3& v) {
std::stringstream ss;
ss << "(" << v.x << ", " << v.y << ", " << v.z << ")";
return ss.str();
}
CelestialBody::CelestialBody(double mass, const glm::dvec3& position, const glm::dvec3& velocity, double radius)
: mass(mass), position(position), velocity(velocity), acceleration(0.0f) {}
void CelestialBody::update(double dt) {
// Runge-Kutta 4th order method
glm::dvec3 k1v = acceleration * dt;
glm::dvec3 k1r = velocity * dt;
glm::dvec3 k2v = acceleration * dt;
glm::dvec3 k2r = (velocity + k1v * 0.5) * dt;
glm::dvec3 k3v = acceleration * dt;
glm::dvec3 k3r = (velocity + k2v * 0.5) * dt;
glm::dvec3 k4v = acceleration * dt;
glm::dvec3 k4r = (velocity + k3v) * dt;
velocity += (k1v + 2.0 * k2v + 2.0 * k3v + k4v) / 6.0;
position += (k1r + 2.0 * k2r + 2.0 * k3r + k4r) / 6.0;
acceleration = glm::dvec3(0.0);
}
void CelestialBody::applyForce(const glm::dvec3& force) {
acceleration += force / mass;
}
void CelestialBody::addToTrajectory(const glm::dvec3& position) {
trajectory.push_back(position);
if (trajectory.size() > MAX_TRAJECTORY_POINTS) {
trajectory.erase(trajectory.begin());
}
}
+35
View File
@@ -0,0 +1,35 @@
//
// Created by Quinta on 7/12/2024.
//
#ifndef GRAVITY_CELESTIALBODY_H
#define GRAVITY_CELESTIALBODY_H
#pragma once
#include <glm/glm.hpp>
#include <string>
#include <vector>
class CelestialBody {
public:
CelestialBody(double mass, const glm::dvec3& position, const glm::dvec3& velocity, double radius);
void update(double dt);
void applyForce(const glm::dvec3& force);
[[nodiscard]] double getMass() const { return mass; }
[[nodiscard]] glm::dvec3 getPosition() const { return position; }
[[nodiscard]] glm::dvec3 getVelocity() const { return velocity; }
void addToTrajectory(const glm::dvec3& position);
const std::vector<glm::dvec3>& getTrajectory() const { return trajectory; }
double getRadius() const { return radius; }
private:
double mass;
glm::dvec3 position;
glm::dvec3 velocity;
glm::dvec3 acceleration;
std::vector<glm::dvec3> trajectory;
static const size_t MAX_TRAJECTORY_POINTS = 1000;
double radius;
};
#endif //GRAVITY_CELESTIALBODY_H
+111 -1
View File
@@ -1 +1,111 @@
# gravity
# 3D Gravity Simulato
![image.png](image.png)
## Overview
This 3D Gravity Simulator is a C++ program that visualizes the gravitational interactions between celestial bodies in a simplified solar system model. It uses OpenGL for rendering and GLFW for window management and user input.
## Program Structure
The simulator consists of several key components:
1. `Simulator`: Handles the physics calculations and updates the positions of celestial bodies.
2. `Renderer`: Manages the 3D rendering of the celestial bodies, trajectories, and grid.
3. `CelestialBody`: Represents individual celestial bodies with properties like mass, position, and velocity.
## Physics Implementation
### Gravitational Force
The simulator uses Newton's law of universal gravitation to calculate the forces between celestial bodies. The gravitational force between two bodies is given by:
$$
F = G \frac{m_1 m_2}{r^2}
$$
Where:
- $F$ is the gravitational force between the two bodies
- $G$ is the gravitational constant ($6.67430 \times 10^{-11} \, \text{N} \cdot \text{m}^2 / \text{kg}^2$)
- $m_1$ and $m_2$ are the masses of the two bodies
- $r$ is the distance between the centers of the two bodies
### Motion Update
The motion of each celestial body is updated using numerical integration. We use a simple Euler method for updating positions and velocities:
1. Calculate the net force on each body
2. Calculate acceleration:
```math
$$ \vec{a} = \frac{\vec{F}}{m} $$
```
3. Update velocity:
```math
$$ \vec{v}_{new} = \vec{v}_{old} + \vec{a} \Delta t $$
```
4. Update position:
```math
$$ \vec{x}_{new} = \vec{x}_{old} + \vec{v}_{new} \Delta t $$
```
Where $\Delta t$ is the time step of the simulation.
## Rendering
The program uses OpenGL to render the 3D scene:
- Celestial bodies are represented as spheres with sizes proportional to their masses (using a logarithmic scale).
- A grid is drawn to provide a reference plane.
- Trajectories of the bodies are drawn as lines, fading out over time.
- The camera can be controlled using WASD keys for movement and the mouse for orientation.
## Limitations and Simplifications
1. The simulation uses a fixed time step, which can lead to inaccuracies in long-term simulations.
2. The Euler method for numerical integration is simple but can accumulate errors over time.
3. The scale of the celestial bodies and their distances are not to true scale to make visualization easier.
4. Relativistic effects are not considered; the simulation uses classical Newtonian mechanics.
# How to Use & Installation
## Prerequisites
- C++ compiler with C++17 support
- CMake (version 3.28 or higher)
- OpenGL libraries
- GLFW3
- GLM (OpenGL Mathematics)
- vcpkg (for managing dependencies)
### Building from Source
1. Clone the repository:
```bash
git clone https://github.com/Quinta0/gravity.git
cd gravity
```
2. Install vcpkg:
```bash
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh # On Windows, use bootstrap-vcpkg.bat
./vcpkg integrate install
cd ..
```
3. Install dependencies using vcpkg:
```bash
./vcpkg/vcpkg install freeglut glew glm vcpkg-cmake opengl glfw3
```
4. Create a build directory and run CMake:
```bash
mkdir build
cd build
cmake -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake ..
cmake --build .
```
5. Run the simulator:
```bash
./gravity
```
+361
View File
@@ -0,0 +1,361 @@
//
// Created by Quinta on 7/12/2024.
//
#include "Renderer.h"
#include <vector>
#include <cmath>
#include <stdexcept>
Renderer::Renderer(int width, int height)
: cameraPos(3e11f, 2e11f, 3e11f),
cameraFront(glm::normalize(glm::vec3(0.0f) - glm::vec3(3e11f, 2e11f, 3e11f))),
cameraUp(0.0f, 1.0f, 0.0f),
cameraSpeed(1e9f),
mouseSensitivity(0.05f),
yaw(-45.0f),
pitch(-30.0f),
mousePressed(false),
lastMouseX(width / 2.0),
lastMouseY(height / 2.0)
{
if (!glfwInit()) {
throw std::runtime_error("Failed to initialize GLFW");
}
window = glfwCreateWindow(width, height, "3D Gravity Simulator", nullptr, nullptr);
if (!window) {
glfwTerminate();
throw std::runtime_error("Failed to create GLFW window");
}
glfwMakeContextCurrent(window);
if (glewInit() != GLEW_OK) {
throw std::runtime_error("Failed to initialize GLEW");
}
glEnable(GL_DEPTH_TEST);
glDisable(GL_LIGHTING);
glDisable(GL_LIGHT0);
glEnable(GL_COLOR_MATERIAL);
createSphereMesh(1.0f, 20, 20);
// Set up camera
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
glfwSetWindowUserPointer(window, this);
glfwSetCursorPosCallback(window, cursorPosCallback);
glfwSetMouseButtonCallback(window, mouseButtonCallback);
}
Renderer::~Renderer() {
glDeleteVertexArrays(1, &sphereVAO);
glDeleteBuffers(1, &sphereVBO);
glDeleteBuffers(1, &sphereEBO);
glfwDestroyWindow(window);
glfwTerminate();
}
void Renderer::render(const Simulator& simulator) {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glClearColor(0.0f, 0.0f, 0.1f, 1.0f);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, 1600.0 / 1200.0, 1e8, 1e14);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glm::vec3 center = glm::vec3(0, 0, 0); // Look at the center of the system
gluLookAt(cameraPos.x, cameraPos.y, cameraPos.z,
center.x, center.y, center.z,
cameraUp.x, cameraUp.y, cameraUp.z);
drawGrid(simulator);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
drawTrajectories(simulator.getBodies());
glDisable(GL_BLEND);
const auto& bodies = simulator.getBodies();
double maxMass = 0;
double minMass = std::numeric_limits<double>::max();
// Find the maximum and minimum masses
for (const auto& body : bodies) {
maxMass = std::max(maxMass, body.getMass());
minMass = std::min(minMass, body.getMass());
}
for (size_t i = 0; i < bodies.size(); ++i) {
const auto& body = bodies[i];
glm::dvec3 pos = body.getPosition();
}
// Calculate the log range
double logMinMass = std::log10(minMass);
double logMaxMass = std::log10(maxMass);
double logRange = logMaxMass - logMinMass;
for (size_t i = 0; i < bodies.size(); ++i) {
const auto& body = bodies[i];
// Calculate the scale factor based on mass
double logMass = std::log10(body.getMass());
double normalizedLogMass = (logMass - logMinMass) / logRange;
float minScale = 5e9f; // Minimum scale to ensure visibility
float maxScale = 5e10f; // Maximum scale to prevent overly large objects
float scaleFactor = minScale + static_cast<float>(normalizedLogMass) * (maxScale - minScale);
glm::dvec3 pos = body.getPosition();
glm::vec3 renderPos(static_cast<float>(pos.x), static_cast<float>(pos.y), static_cast<float>(pos.z));
// Set color based on body index
switch(i) {
case 0: glColor3f(1.0f, 1.0f, 0.0f); break; // Sun: Yellow
case 1: glColor3f(0.5f, 0.5f, 0.5f); break; // Mercury: Gray
case 2: glColor3f(0.9f, 0.7f, 0.4f); break; // Venus: Light Orange
case 3: glColor3f(0.0f, 0.5f, 1.0f); break; // Earth: Blue
case 4: glColor3f(1.0f, 0.0f, 0.0f); break; // Mars: Red
case 5: glColor3f(0.8f, 0.6f, 0.2f); break; // Jupiter: Light Brown
case 6: glColor3f(0.9f, 0.9f, 0.7f); break; // Saturn: Light Yellow
case 7: glColor3f(0.0f, 0.5f, 0.5f); break; // Uranus: Cyan
case 8: glColor3f(0.0f, 0.0f, 1.0f); break; // Neptune: Dark Blue
case 9: glColor3f(0.5f, 0.5f, 0.5f); break; // Pluto: Gray
default: glColor3f(1.0f, 1.0f, 1.0f); break; // White for any additional bodies
}
drawSphere(renderPos, scaleFactor);
}
}
bool Renderer::shouldClose() {
return glfwWindowShouldClose(window);
}
void Renderer::swapBuffers() {
glfwSwapBuffers(window);
glfwPollEvents();
}
void Renderer::drawSphere(const glm::vec3& position, float radius) {
glPushMatrix();
glTranslatef(position.x, position.y, position.z);
glScalef(radius, radius, radius);
glBindVertexArray(sphereVAO);
glDrawElements(GL_TRIANGLES, sphereIndexCount, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
glPopMatrix();
}
void Renderer::createSphereMesh(float radius, int sectors, int stacks) {
std::vector<GLfloat> vertices;
std::vector<GLuint> indices;
float x, y, z, xy;
float nx, ny, nz, lengthInv = 1.0f / radius;
float s, t;
float sectorStep = 2 * M_PI / sectors;
float stackStep = M_PI / stacks;
float sectorAngle, stackAngle;
for (int i = 0; i <= stacks; ++i) {
stackAngle = M_PI / 2 - i * stackStep;
xy = radius * cosf(stackAngle);
z = radius * sinf(stackAngle);
for (int j = 0; j <= sectors; ++j) {
sectorAngle = j * sectorStep;
x = xy * cosf(sectorAngle);
y = xy * sinf(sectorAngle);
nx = x * lengthInv;
ny = y * lengthInv;
nz = z * lengthInv;
vertices.push_back(x);
vertices.push_back(y);
vertices.push_back(z);
}
}
for (int i = 0; i < stacks; ++i) {
int k1 = i * (sectors + 1);
int k2 = k1 + sectors + 1;
for (int j = 0; j < sectors; ++j, ++k1, ++k2) {
if (i != 0) {
indices.push_back(k1);
indices.push_back(k2);
indices.push_back(k1 + 1);
}
if (i != (stacks - 1)) {
indices.push_back(k1 + 1);
indices.push_back(k2);
indices.push_back(k2 + 1);
}
}
}
glGenVertexArrays(1, &sphereVAO);
glGenBuffers(1, &sphereVBO);
glGenBuffers(1, &sphereEBO);
glBindVertexArray(sphereVAO);
glBindBuffer(GL_ARRAY_BUFFER, sphereVBO);
glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(GLfloat), vertices.data(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, sphereEBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLuint), indices.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (void*)0);
glBindVertexArray(0);
sphereVertexCount = vertices.size() / 3;
sphereIndexCount = indices.size();
}
void Renderer::drawDebugTriangle() {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-1, 1, -1, 1, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
gluLookAt(4e11, 3e11, 4e11, 0, 0, 0, 0, 1, 0);
glBegin(GL_TRIANGLES);
glColor3f(1.0f, 0.0f, 0.0f);
glVertex3f(-0.5f, -0.5f, 0.0f);
glColor3f(0.0f, 1.0f, 0.0f);
glVertex3f(0.5f, -0.5f, 0.0f);
glColor3f(0.0f, 0.0f, 1.0f);
glVertex3f(0.0f, 0.5f, 0.0f);
glEnd();
}
float Renderer::calculateGravityFieldStrength(const glm::vec3& point, const std::vector<CelestialBody>& bodies) {
float fieldStrength = 0.0f;
const float G = 6.67430e-11f; // Gravitational constant
const float scalingFactor = 1e20f; // Greatly increased scaling factor
for (const auto& body : bodies) {
glm::dvec3 bodyPos = body.getPosition();
float distance = glm::length(glm::vec3(bodyPos) - point);
if (distance < 1e9f) distance = 1e9f; // Prevent division by zero
fieldStrength += scalingFactor * G * static_cast<float>(body.getMass()) / (distance * distance);
}
return fieldStrength;
}
void Renderer::drawGrid(const Simulator& simulator) {
const float gridSize = 5e13f;
const int gridLines = 80;
const float lineSpacing = gridSize / gridLines;
glBegin(GL_LINES);
glColor3f(0.2f, 0.2f, 0.2f); // Lighter gray for better visibility
for (int i = -gridLines/2; i <= gridLines/2; ++i) {
float pos = i * lineSpacing;
glVertex3f(-gridSize/2, 0, pos);
glVertex3f(gridSize/2, 0, pos);
glVertex3f(pos, 0, -gridSize/2);
glVertex3f(pos, 0, gridSize/2);
}
glEnd();
}
void Renderer::drawTrajectories(const std::vector<CelestialBody>& bodies) {
glBegin(GL_LINES);
for (const auto& body : bodies) {
const auto& trajectory = body.getTrajectory();
if (trajectory.size() < 2) continue;
for (size_t i = 1; i < trajectory.size(); ++i) {
glm::vec3 p1(trajectory[i-1]);
glm::vec3 p2(trajectory[i]);
// Fade out older parts of the trajectory
float alpha = static_cast<float>(i) / trajectory.size();
glColor4f(1.0f, 1.0f, 1.0f, alpha * 0.5f);
glVertex3f(p1.x, p1.y, p1.z);
glVertex3f(p2.x, p2.y, p2.z);
}
}
glEnd();
}
void Renderer::processInput() {
float cameraSpeed = this->cameraSpeed * 1e1f;
glm::vec3 front(cameraFront.x, 0, cameraFront.z);
front = glm::normalize(front);
glm::vec3 right = glm::normalize(glm::cross(front, cameraUp));
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
cameraPos += front * cameraSpeed;
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
cameraPos -= front * cameraSpeed;
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
cameraPos -= right * cameraSpeed;
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
cameraPos += right * cameraSpeed;
if (glfwGetKey(window, GLFW_KEY_ESCAPE) == GLFW_PRESS)
glfwSetWindowShouldClose(window, true);
}
void Renderer::cursorPosCallback(GLFWwindow* window, double xpos, double ypos) {
Renderer* renderer = static_cast<Renderer*>(glfwGetWindowUserPointer(window));
renderer->handleMouseMove(xpos, ypos);
}
void Renderer::mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) {
Renderer* renderer = static_cast<Renderer*>(glfwGetWindowUserPointer(window));
if (button == GLFW_MOUSE_BUTTON_LEFT) {
if (action == GLFW_PRESS) {
renderer->mousePressed = true;
glfwGetCursorPos(window, &renderer->lastMouseX, &renderer->lastMouseY);
} else if (action == GLFW_RELEASE) {
renderer->mousePressed = false;
}
}
}
void Renderer::handleMouseMove(double xpos, double ypos) {
if (!mousePressed) return;
float xoffset = xpos - lastMouseX;
float yoffset = lastMouseY - ypos;
lastMouseX = xpos;
lastMouseY = ypos;
xoffset *= mouseSensitivity;
yoffset *= mouseSensitivity;
yaw += xoffset;
pitch += yoffset;
if (pitch > 89.0f) pitch = 89.0f;
if (pitch < -89.0f) pitch = -89.0f;
updateCameraVectors();
}
void Renderer::updateCameraVectors() {
glm::vec3 front;
front.x = cos(glm::radians(yaw)) * cos(glm::radians(pitch));
front.y = sin(glm::radians(pitch));
front.z = sin(glm::radians(yaw)) * cos(glm::radians(pitch));
cameraFront = glm::normalize(front);
}
+52
View File
@@ -0,0 +1,52 @@
//
// Created by Quinta on 7/12/2024.
//
#ifndef GRAVITY_RENDERER_H
#define GRAVITY_RENDERER_H
#pragma once
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <glm/glm.hpp>
#include "Simulator.h"
class Renderer {
public:
Renderer(int width, int height);
~Renderer();
void render(const Simulator& simulator);
bool shouldClose();
void swapBuffers();
void processInput();
static void cursorPosCallback(GLFWwindow* window, double xpos, double ypos);
static void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
private:
GLFWwindow* window;
void drawSphere(const glm::vec3& position, float radius);
void createSphereMesh(float radius, int sectors, int stacks);
void drawDebugTriangle();
GLuint sphereVAO, sphereVBO, sphereEBO;
int sphereVertexCount, sphereIndexCount;
void drawGrid(const Simulator& simulator);
float calculateGravityFieldStrength(const glm::vec3& point, const std::vector<CelestialBody>& bodies);
void drawTrajectories(const std::vector<CelestialBody>& bodies);
glm::vec3 cameraPos;
glm::vec3 cameraFront;
glm::vec3 cameraUp;
float cameraSpeed;
float mouseSensitivity;
float yaw;
float pitch;
bool mousePressed;
double lastMouseX, lastMouseY;
void updateCameraVectors();
void handleMouseMove(double xpos, double ypos);
};
#endif //GRAVITY_RENDERER_H
+103
View File
@@ -0,0 +1,103 @@
//
// Created by Quinta on 7/12/2024.
//
#include "Simulator.h"
#include <glm/glm.hpp>
#include <iostream>
#include <algorithm>
Simulator::Simulator() {}
void Simulator::addBody(const CelestialBody& body) {
bodies.push_back(body);
}
void Simulator::update(double dt) {
// Sort bodies by mass (descending order)
std::sort(bodies.begin(), bodies.end(), [](const CelestialBody& a, const CelestialBody& b) {
return a.getMass() > b.getMass();
});
// Calculate and apply gravitational forces
for (size_t i = 0; i < bodies.size(); ++i) {
glm::vec3 totalForce(0.0f);
for (size_t j = 0; j < bodies.size(); ++j) {
if (i != j) {
glm::vec3 force = calculateGravitationalForce(bodies[i], bodies[j]);
totalForce += force;
}
}
bodies[i].applyForce(totalForce);
}
// Update positions and velocities
for (size_t i = 1; i < bodies.size(); ++i) { // Start from 1 to skip the Sun
bodies[i].update(dt);
bodies[i].addToTrajectory(bodies[i].getPosition());
}
// Check for collisions
checkCollisions();
}
glm::dvec3 Simulator::calculateGravitationalForce(const CelestialBody& body1, const CelestialBody& body2) {
glm::dvec3 direction = body2.getPosition() - body1.getPosition();
double distance = glm::length(direction);
// Avoid division by zero and unrealistic forces at very small distances
if (distance < 1e9) {
std::cout << "Warning: Bodies too close, using minimum distance" << std::endl;
distance = 1e9;
}
// Use the actual G value
const double G = 6.67430e-11;
double forceMagnitude = G * (body1.getMass() * body2.getMass()) / (distance * distance);
if (std::isnan(forceMagnitude) || std::isinf(forceMagnitude)) {
return glm::dvec3(0.0);
}
return glm::normalize(direction) * forceMagnitude;
}
void Simulator::handleCollision(CelestialBody& body1, CelestialBody& body2) {
double totalMass = body1.getMass() + body2.getMass();
// Calculate center of mass position
glm::dvec3 newPosition = (body1.getPosition() * body1.getMass() + body2.getPosition() * body2.getMass()) / totalMass;
// Calculate new velocity (momentum conservation)
glm::dvec3 newVelocity = (body1.getVelocity() * body1.getMass() + body2.getVelocity() * body2.getMass()) / totalMass;
// Calculate new radius (assuming constant density)
double newRadius = std::pow(std::pow(body1.getRadius(), 3) + std::pow(body2.getRadius(), 3), 1.0/3.0);
// Create new body
CelestialBody newBody(totalMass, newPosition, newVelocity, newRadius);
// Replace body1 with the new body
body1 = newBody;
// Remove body2
auto it = std::find_if(bodies.begin(), bodies.end(), [&body2](const CelestialBody& b) {
return &b == &body2;
});
if (it != bodies.end()) {
bodies.erase(it);
}
}
void Simulator::checkCollisions() {
for (size_t i = 0; i < bodies.size(); ++i) {
for (size_t j = i + 1; j < bodies.size(); ++j) {
CelestialBody& body1 = bodies[i];
CelestialBody& body2 = bodies[j];
glm::dvec3 distanceVec = body1.getPosition() - body2.getPosition();
double distance = glm::length(distanceVec);
if (distance < (body1.getRadius() + body2.getRadius())) {
handleCollision(body1, body2);
}
}
}
}
+27
View File
@@ -0,0 +1,27 @@
//
// Created by Quinta on 7/12/2024.
//
#ifndef GRAVITY_SIMULATOR_H
#define GRAVITY_SIMULATOR_H
#pragma once
#include <vector>
#include "CelestialBody.h"
class Simulator {
public:
Simulator();
void addBody(const CelestialBody& body);
void update(double dt);
const std::vector<CelestialBody>& getBodies() const { return bodies; }
glm::dvec3 calculateGravitationalForce(const CelestialBody& body1, const CelestialBody& body2);
private:
std::vector<CelestialBody> bodies;
const float G = 6.67430e-11f; // Gravitational constant
void checkCollisions();
void handleCollision(CelestialBody& body1, CelestialBody& body2);
};
#endif //GRAVITY_SIMULATOR_H
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

+74
View File
@@ -0,0 +1,74 @@
//
// Created by Quinta on 7/12/2024.
//
#include "Simulator.h"
#include "Renderer.h"
#include <chrono>
#include <thread>
glm::dvec3 calculateOrbitalVelocity(double centralMass, double distance) {
const double G = 6.67430e-11;
double speed = std::sqrt(G * centralMass / distance);
return glm::dvec3(0, speed, 0); // Assuming orbit in the XZ plane
}
int main() {
Simulator simulator;
Renderer renderer(1600, 1200);
double sunMass = 1.989e30;
// Sun (at the center)
simulator.addBody(CelestialBody(sunMass, glm::dvec3(0, 0, 0), glm::dvec3(0, 0, 0), 6.96e8));
// Mercury
double mercuryDist = 57.9e9;
simulator.addBody(CelestialBody(3.285e23, glm::dvec3(mercuryDist, 0, 0), calculateOrbitalVelocity(sunMass, mercuryDist), 2.44e6));
// Venus
double venusDist = 108.2e9;
simulator.addBody(CelestialBody(4.867e24, glm::dvec3(venusDist, 0, 0), calculateOrbitalVelocity(sunMass, venusDist), 6.05e6));
// Earth
double earthDist = 149.6e9;
simulator.addBody(CelestialBody(5.972e24, glm::dvec3(earthDist, 0, 0), calculateOrbitalVelocity(sunMass, earthDist), 6.37e6));
// Mars
double marsDist = 227.9e9;
simulator.addBody(CelestialBody(6.39e23, glm::dvec3(marsDist, 0, 0), calculateOrbitalVelocity(sunMass, marsDist), 3.39e6));
// Jupiter
double jupiterDist = 778.5e9;
simulator.addBody(CelestialBody(1.898e27, glm::dvec3(jupiterDist, 0, 0), calculateOrbitalVelocity(sunMass, jupiterDist), 69.91e6));
// Saturn
double saturnDist = 1.429e12;
simulator.addBody(CelestialBody(5.683e26, glm::dvec3(saturnDist, 0, 0), calculateOrbitalVelocity(sunMass, saturnDist), 58.23e6));
// Uranus
double uranusDist = 2.871e12;
simulator.addBody(CelestialBody(8.681e25, glm::dvec3(uranusDist, 0, 0), calculateOrbitalVelocity(sunMass, uranusDist ), 25.36e6));
// Neptune
double neptuneDist = 4.495e12;
simulator.addBody(CelestialBody(1.024e26, glm::dvec3(neptuneDist, 0, 0), calculateOrbitalVelocity(sunMass, neptuneDist), 24.62e6));
// Pluto
double plutoDist = 5.906e12;
simulator.addBody(CelestialBody(1.309e22, glm::dvec3(plutoDist, 0, 0), calculateOrbitalVelocity(sunMass, plutoDist), 1.18e6));
const float dt = 3600.0f; // Time step of 1 hour
while (!renderer.shouldClose()) {
renderer.processInput();
simulator.update(dt);
renderer.render(simulator);
renderer.swapBuffers();
std::this_thread::sleep_for(std::chrono::milliseconds(16));
}
return 0;
}
+14
View File
@@ -0,0 +1,14 @@
{
"default-registry": {
"kind": "git",
"baseline": "3f530d4827b064f5894e94a8946473d40999826e",
"repository": "https://github.com/microsoft/vcpkg"
},
"registries": [
{
"kind": "artifact",
"location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip",
"name": "microsoft"
}
]
}
+10
View File
@@ -0,0 +1,10 @@
{
"dependencies": [
"freeglut",
"glew",
"glfw3",
"glm",
"opengl",
"vcpkg-cmake"
]
}