#include #include #include #include #include #include "shader.h" // Konstante const float g = 9.81f; // przyspieszenie ziemskie const float r = 0.6f; // długość nici const float dt = 0.01f; // krok czasowy // Zmienne globalne float theta = 0.5f; // początkowy kąt float omega = 0.0f; // początkowa prędkość kątowa GLuint VBO, VAO, EBO, shaderProgram; void compileShaders(){ Shader shader("pendulum_vs.glsl", "pendulum_fs.glsl"); shaderProgram = shader.programID(); } void initOpenGL() { compileShaders(); // Setup Vertex Array Object and Vertex Buffer Object glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 4, nullptr, GL_DYNAMIC_DRAW); // Pozycja glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } // Metoda Eulera void updateEuler() { float alpha = -(g / r) * sin(theta); // przyspieszenie kątowe omega += alpha * dt; // aktualizacja prędkości kątowej theta += omega * dt; // aktualizacja kąta } // Metoda Verleta void updateVerlet() { static float prev_theta = theta; float alpha = -(g / r) * sin(theta); // przyspieszenie kątowe float new_theta = 2 * theta - prev_theta + alpha * dt * dt; // aktualizacja kąta prev_theta = theta; theta = new_theta; } // Metoda Rungego-Kutty rzędu 4 void updateRungeKutta() { auto f = [](float theta, float omega) { return -(g / r) * sin(theta); }; float k1_theta = omega; float k1_omega = f(theta, omega); float k2_theta = omega + 0.5f * dt * k1_omega; float k2_omega = f(theta + 0.5f * dt * k1_theta, omega + 0.5f * dt * k1_omega); float k3_theta = omega + 0.5f * dt * k2_omega; float k3_omega = f(theta + 0.5f * dt * k2_theta, omega + 0.5f * dt * k2_omega); float k4_theta = omega + dt * k3_omega; float k4_omega = f(theta + dt * k3_theta, omega + dt * k3_omega); theta += (dt / 6.0f) * (k1_theta + 2.0f * k2_theta + 2.0f * k3_theta + k4_theta); omega += (dt / 6.0f) * (k1_omega + 2.0f * k2_omega + 2.0f * k3_omega + k4_omega); } void drawPendulum() { float x = r * sin(theta); float y = -r * cos(theta); float vertices[] = { 0.0f, 0.0f, // Punkt zaczepienia x, y // Punkt masy }; glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); glBindBuffer(GL_ARRAY_BUFFER, 0); glClear(GL_COLOR_BUFFER_BIT); glUseProgram(shaderProgram); glBindVertexArray(VAO); glDrawArrays(GL_LINES, 0, 2); glDrawArrays(GL_POINTS, 1, 1); glBindVertexArray(0); } int main() { if (!glfwInit()) { std::cerr << "Nie można zainicjalizować GLFW" << std::endl; return -1; } glfwWindowHint(GLFW_SAMPLES, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); GLFWwindow* window = glfwCreateWindow(800, 600, "Wahadło Matematyczne", NULL, NULL); if (!window) { std::cerr << "Nie można utworzyć okna GLFW" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glewExperimental = GL_TRUE; if (glewInit() != GLEW_OK) { std::cerr << "Nie można zainicjalizować GLEW" << std::endl; return -1; } glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-2, 2, -2, 2, -1, 1); glMatrixMode(GL_MODELVIEW); glPointSize(10.0f); initOpenGL(); int method = 1; // Domyślnie metoda Eulera std::cout << "Wybierz metodę: (1) Euler, (2) Verlet, (3) Runge-Kutta: "; std::cin >> method; while (!glfwWindowShouldClose(window)) { switch (method) { case 1: updateEuler(); break; case 2: updateVerlet(); break; case 3: updateRungeKutta(); break; default: updateEuler(); break; } drawPendulum(); glfwSwapBuffers(window); glfwPollEvents(); } glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); glfwDestroyWindow(window); glfwTerminate(); return 0; }