#include #include #include #include #include #include #include const char* vertexShaderSource = R"glsl( #version 330 core layout(location=0) in vec3 aPos; uniform mat4 model; uniform mat4 view; uniform mat4 projection; out float lightIntensity; void main() { gl_Position = projection * view * model * vec4(aPos, 1.0); vec3 worldPos = (model * vec4(aPos, 1.0)).xyz; vec3 normal = normalize(aPos); vec3 dirToCenter = normalize(-worldPos); lightIntensity = max(dot(normal, dirToCenter), 0.15);})glsl"; const char* fragmentShaderSource = R"glsl( #version 330 core in float lightIntensity; out vec4 FragColor; uniform vec4 objectColor; uniform bool isGrid; // Add this uniform uniform bool GLOW; void main() { if (isGrid) { // If it's the grid, use the original color without lighting FragColor = objectColor; } else if(GLOW){ FragColor = vec4(objectColor.rgb * 100000, objectColor.a); }else { // If it's an object, apply the lighting effect float fade = smoothstep(0.0, 10.0, lightIntensity*10); FragColor = vec4(objectColor.rgb * fade, objectColor.a); }})glsl"; bool running = true; bool pause = true; glm::vec3 cameraPos = glm::vec3(0.0f, 0.0f, 1.0f); glm::vec3 cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); glm::vec3 cameraUp = glm::vec3(0.0f, 1.0f, 0.0f); float lastX = 400.0, lastY = 300.0; float yaw = -90; float pitch =0.0; float deltaTime = 0.0; float lastFrame = 0.0; const double G = 6.6743e-11; // m^3 kg^-1 s^-2 const float c = 299792458.0; float initMass = float(pow(10, 22)); float sizeRatio = 30000.0f; GLFWwindow* StartGLU(); GLuint CreateShaderProgram(const char* vertexSource, const char* fragmentSource); void CreateVBOVAO(GLuint& VAO, GLuint& VBO, const float* vertices, size_t vertexCount); void UpdateCam(GLuint shaderProgram, glm::vec3 cameraPos); void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods); void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods); void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); void mouse_callback(GLFWwindow* window, double xpos, double ypos); glm::vec3 sphericalToCartesian(float r, float theta, float phi); void DrawGrid(GLuint shaderProgram, GLuint gridVAO, size_t vertexCount); class Object { public: GLuint VAO, VBO; glm::vec3 position = glm::vec3(400, 300, 0); glm::vec3 velocity = glm::vec3(0, 0, 0); size_t vertexCount; glm::vec4 color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f); bool Initalizing = false; bool Launched = false; bool target = false; float mass; float density; // kg / m^3 HYDROGEN float radius; glm::vec3 LastPos = position; bool glow; Object(glm::vec3 initPosition, glm::vec3 initVelocity, float mass, float density = 3344, glm::vec4 color = glm::vec4(1.0f, 0.0f, 0.0f, 1.0f), bool Glow = false) { this->position = initPosition; this->velocity = initVelocity; this->mass = mass; this->density = density; this->radius = pow(((3 * this->mass/this->density)/(4 * 3.14159265359)), (1.0f/3.0f)) / sizeRatio; this->color = color; this->glow = Glow; // generate vertices (centered at origin) std::vector vertices = Draw(); vertexCount = vertices.size(); CreateVBOVAO(VAO, VBO, vertices.data(), vertexCount); } std::vector Draw() { std::vector vertices; int stacks = 10; int sectors = 10; // generate circumference points using integer steps for(float i = 0.0f; i <= stacks; ++i){ float theta1 = (i / stacks) * glm::pi(); float theta2 = (i+1) / stacks * glm::pi(); for (float j = 0.0f; j < sectors; ++j){ float phi1 = j / sectors * 2 * glm::pi(); float phi2 = (j+1) / sectors * 2 * glm::pi(); glm::vec3 v1 = sphericalToCartesian(this->radius, theta1, phi1); glm::vec3 v2 = sphericalToCartesian(this->radius, theta1, phi2); glm::vec3 v3 = sphericalToCartesian(this->radius, theta2, phi1); glm::vec3 v4 = sphericalToCartesian(this->radius, theta2, phi2); // Triangle 1: v1-v2-v3 vertices.insert(vertices.end(), {v1.x, v1.y, v1.z}); // /| vertices.insert(vertices.end(), {v2.x, v2.y, v2.z}); // / | vertices.insert(vertices.end(), {v3.x, v3.y, v3.z}); // /__| // Triangle 2: v2-v4-v3 vertices.insert(vertices.end(), {v2.x, v2.y, v2.z}); vertices.insert(vertices.end(), {v4.x, v4.y, v4.z}); vertices.insert(vertices.end(), {v3.x, v3.y, v3.z}); } } return vertices; } void UpdatePos(){ this->position[0] += this->velocity[0] / 94; this->position[1] += this->velocity[1] / 94; this->position[2] += this->velocity[2] / 94; this->radius = pow(((3 * this->mass/this->density)/(4 * 3.14159265359)), (1.0f/3.0f)) / sizeRatio; } void UpdateVertices() { // generate new vertices with current radius std::vector vertices = Draw(); // update VBO with new vertex data glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW); } glm::vec3 GetPos() const { return this->position; } void accelerate(float x, float y, float z){ this->velocity[0] += x / 96; this->velocity[1] += y / 96; this->velocity[2] += z / 96; } float CheckCollision(const Object& other) { float dx = other.position[0] - this->position[0]; float dy = other.position[1] - this->position[1]; float dz = other.position[2] - this->position[2]; float distance = std::pow(dx*dx + dy*dy + dz*dz, (1.0f/2.0f)); if (other.radius + this->radius > distance){ return -0.2f; } return 1.0f; } }; std::vector objs = {}; std::vector CreateGridVertices(float size, int divisions, const std::vector& objs); std::vector UpdateGridVertices(std::vector vertices, const std::vector& objs); GLuint gridVAO, gridVBO; int main() { GLFWwindow* window = StartGLU(); GLuint shaderProgram = CreateShaderProgram(vertexShaderSource, fragmentShaderSource); GLint modelLoc = glGetUniformLocation(shaderProgram, "model"); GLint objectColorLoc = glGetUniformLocation(shaderProgram, "objectColor"); glUseProgram(shaderProgram); glfwSetCursorPosCallback(window, mouse_callback); glfwSetScrollCallback(window, scroll_callback); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); //projection matrix glm::mat4 projection = glm::perspective(glm::radians(45.0f), 800.0f / 600.0f, 0.1f, 750000.0f); GLint projectionLoc = glGetUniformLocation(shaderProgram, "projection"); glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection)); cameraPos = glm::vec3(0.0f, 1000.0f, 5000.0f); objs = { //Object(glm::vec3(3844, 0, 0), glm::vec3(0, 0, 228), 7.34767309*pow(10, 22), 3344), //Object(glm::vec3(0, 0, 0), glm::vec3(0, 0, 0), 1.989 * pow(10, 30), 5515, glm::vec4(1.0f, 0.929f, 0.176f, 1.0f)), //Object(glm::vec3(0, 0, 0), glm::vec3(0, 0, 0), 5.97219*pow(10, 24), 5515, glm::vec4(0.0f, 1.0f, 1.0f, 1.0f)), Object(glm::vec3(-5000, 650, -350), glm::vec3(0, 0, 1500), 5.97219*pow(10, 22), 5515, glm::vec4(0.0f, 1.0f, 1.0f, 1.0f)), Object(glm::vec3(5000, 650, -350), glm::vec3(0, 0, -1500), 5.97219*pow(10, 22), 5515, glm::vec4(0.0f, 1.0f, 1.0f, 1.0f)), Object(glm::vec3(0, 0, -350), glm::vec3(0, 0, 0), 1.989 * pow(10, 25), 5515, glm::vec4(1.0f, 0.929f, 0.176f, 1.0f), true), }; std::vector gridVertices = CreateGridVertices(20000.0f, 25, objs); CreateVBOVAO(gridVAO, gridVBO, gridVertices.data(), gridVertices.size()); while (!glfwWindowShouldClose(window) && running == true) { float currentFrame = glfwGetTime(); deltaTime = currentFrame - lastFrame; lastFrame = currentFrame; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glfwSetKeyCallback(window, keyCallback); glfwSetMouseButtonCallback(window, mouseButtonCallback); UpdateCam(shaderProgram, cameraPos); if (!objs.empty() && objs.back().Initalizing) { if (glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_RIGHT) == GLFW_PRESS) { // increase mass by 1% per second objs.back().mass *= 1.0 + 1.0 * deltaTime; // update radius based on new mass objs.back().radius = pow( (3 * objs.back().mass / objs.back().density) / (4 * 3.14159265359f), 1.0f/3.0f ) / sizeRatio; // update vertex data objs.back().UpdateVertices(); } } // Draw the grid glUseProgram(shaderProgram); glUniform4f(objectColorLoc, 1.0f, 1.0f, 1.0f, 0.25f); glUniform1i(glGetUniformLocation(shaderProgram, "isGrid"), 1); glUniform1i(glGetUniformLocation(shaderProgram, "GLOW"), 0); gridVertices = UpdateGridVertices(gridVertices, objs); glBindBuffer(GL_ARRAY_BUFFER, gridVBO); glBufferData(GL_ARRAY_BUFFER, gridVertices.size() * sizeof(float), gridVertices.data(), GL_DYNAMIC_DRAW); DrawGrid(shaderProgram, gridVAO, gridVertices.size()); // Draw the triangles / sphere for(auto& obj : objs) { glUniform4f(objectColorLoc, obj.color.r, obj.color.g, obj.color.b, obj.color.a); for(auto& obj2 : objs){ if(&obj2 != &obj && !obj.Initalizing && !obj2.Initalizing){ float dx = obj2.GetPos()[0] - obj.GetPos()[0]; float dy = obj2.GetPos()[1] - obj.GetPos()[1]; float dz = obj2.GetPos()[2] - obj.GetPos()[2]; float distance = sqrt(dx * dx + dy * dy + dz * dz); if (distance > 0) { std::vector direction = {dx / distance, dy / distance, dz / distance}; distance *= 1000; double Gforce = (G * obj.mass * obj2.mass) / (distance * distance); float acc1 = Gforce / obj.mass; std::vector acc = {direction[0] * acc1, direction[1]*acc1, direction[2]*acc1}; if(!pause){ obj.accelerate(acc[0], acc[1], acc[2]); } //collision obj.velocity *= obj.CheckCollision(obj2); std::cout<<"radius: "< 89.0f) pitch = 89.0f; if(pitch < -89.0f) pitch = -89.0f; 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); } void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods){ if (button == GLFW_MOUSE_BUTTON_LEFT){ if (action == GLFW_PRESS){ objs.emplace_back(glm::vec3(0.0, 0.0, 0.0), glm::vec3(0.0f, 0.0f, 0.0f), initMass); objs[objs.size()-1].Initalizing = true; }; if (action == GLFW_RELEASE){ objs[objs.size()-1].Initalizing = false; objs[objs.size()-1].Launched = true; }; }; if (!objs.empty() && button == GLFW_MOUSE_BUTTON_RIGHT && objs[objs.size()-1].Initalizing) { if (action == GLFW_PRESS || action == GLFW_REPEAT) { objs[objs.size()-1].mass *= 1.2;} std::cout<<"MASS: "<0){ cameraPos += cameraSpeed * cameraFront; } else if(yoffset<0){ cameraPos -= cameraSpeed * cameraFront; } } glm::vec3 sphericalToCartesian(float r, float theta, float phi){ float x = r * sin(theta) * cos(phi); float y = r * cos(theta); float z = r * sin(theta) * sin(phi); return glm::vec3(x, y, z); }; void DrawGrid(GLuint shaderProgram, GLuint gridVAO, size_t vertexCount) { glUseProgram(shaderProgram); glm::mat4 model = glm::mat4(1.0f); // Identity matrix for the grid GLint modelLoc = glGetUniformLocation(shaderProgram, "model"); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); glBindVertexArray(gridVAO); glPointSize(5.0f); glDrawArrays(GL_LINES, 0, vertexCount / 3); glBindVertexArray(0); } std::vector CreateGridVertices(float size, int divisions, const std::vector& objs) { std::vector vertices; float step = size / divisions; float halfSize = size / 2.0f; // x axis for (int yStep = 3; yStep <= 3; ++yStep) { float y = -halfSize*0.3f + yStep * step; for (int zStep = 0; zStep <= divisions; ++zStep) { float z = -halfSize + zStep * step; for (int xStep = 0; xStep < divisions; ++xStep) { float xStart = -halfSize + xStep * step; float xEnd = xStart + step; vertices.push_back(xStart); vertices.push_back(y); vertices.push_back(z); vertices.push_back(xEnd); vertices.push_back(y); vertices.push_back(z); } } } // zaxis for (int xStep = 0; xStep <= divisions; ++xStep) { float x = -halfSize + xStep * step; for (int yStep = 3; yStep <= 3; ++yStep) { float y = -halfSize*0.3f + yStep * step; for (int zStep = 0; zStep < divisions; ++zStep) { float zStart = -halfSize + zStep * step; float zEnd = zStart + step; vertices.push_back(x); vertices.push_back(y); vertices.push_back(zStart); vertices.push_back(x); vertices.push_back(y); vertices.push_back(zEnd); } } } return vertices; } std::vector UpdateGridVertices(std::vector vertices, const std::vector& objs){ // centre of mass calc float totalMass = 0.0f; float comY = 0.0f; for (const auto& obj : objs) { if (obj.Initalizing) continue; comY += obj.mass * obj.position.y; totalMass += obj.mass; } if (totalMass > 0) comY /= totalMass; float originalMaxY = -std::numeric_limits::infinity(); for (int i = 0; i < vertices.size(); i += 3) { originalMaxY = std::max(originalMaxY, vertices[i+1]); } float verticalShift = comY - originalMaxY; std::cout<<"vertical shift: "<