185 lines
4.5 KiB
C++
185 lines
4.5 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);
|
|
}
|
|
|
|
// 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;
|
|
}
|