akwk/zadanie-1/main.cpp

188 lines
4.3 KiB
C++

#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <cmath>
#include <iostream>
#include <vector>
#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);
}
float f(float theta){
return -(g / r) * sin(theta);
}
// Metoda Eulera
void updateEuler()
{
float alpha = f(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 = f(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()
{
float k1_theta = omega;
float k1_omega = f(theta);
float k2_theta = omega + 0.5f * dt * k1_omega;
float k2_omega = f(theta + 0.5f * dt * k1_theta);
float k3_theta = omega + 0.5f * dt * k2_omega;
float k3_omega = f(theta + 0.5f * dt * k2_theta);
float k4_theta = omega + dt * k3_omega;
float k4_omega = f(theta + dt * k3_theta);
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;
}