#include #include #include #include #include #include #include #include #include "shader.h" #include const float g = 9.81f; const float airResistance = 0.1f; const int windowWidth = 1200; const int windowHeight = 800; float startTime; const float delay = 2.0f; // 2-sekundowe opóźnienie struct Ball { float x, y, z; float vx, vy, vz; float r, g, b; }; std::vector balls(10); // Wektor przechowujący 10 kul GLuint shaderProgram; GLuint VAO, VBO; void initializeBalls() { srand(static_cast(time(0))); // Inicjalizujemy generator liczb losowych for (int i = 0; i < 10; ++i) { float angle = 15.0f + static_cast(rand() % 60); // Losowy kąt między 15 a 75 stopni float speed = 5.0f + static_cast(rand() % 20); // Losowa prędkość między 5 a 25 balls[i] = { .x = 0.0f, .y = 2.0f * i, // Ustawienie kul na tej samej wysokości początkowej .z = 0.0f, .vx = static_cast(speed * cos(angle * M_PI / 180.0f)), .vy = static_cast(speed * sin(angle * M_PI / 180.0f)), .vz = 0.0f, .r = static_cast(rand()) / RAND_MAX, .g = static_cast(rand()) / RAND_MAX, .b = static_cast(rand()) / RAND_MAX }; } startTime = glfwGetTime(); // Ustawienie początkowego czasu symulacji } void compileShaders(){ Shader shader("circle_vs.glsl", "circle_fs.glsl"); shaderProgram = shader.programID(); } // Funkcja do integracji Rungego-Kutty void rungeKuttaStep(Ball &ball, float dt) { float k1vx = -airResistance * ball.vx; float k1vy = -g - airResistance * ball.vy; float k2vx = -airResistance * (ball.vx + 0.5f * dt * k1vx); float k2vy = -g - airResistance * (ball.vy + 0.5f * dt * k1vy); float k3vx = -airResistance * (ball.vx + 0.5f * dt * k2vx); float k3vy = -g - airResistance * (ball.vy + 0.5f * dt * k2vy); float k4vx = -airResistance * (ball.vx + dt * k3vx); float k4vy = -g - airResistance * (ball.vy + dt * k3vy); ball.vx += (dt / 6.0f) * (k1vx + 2.0f * k2vx + 2.0f * k3vx + k4vx); ball.vy += (dt / 6.0f) * (k1vy + 2.0f * k2vy + 2.0f * k3vy + k4vy); ball.x += ball.vx * dt; ball.y += ball.vy * dt; } void setupSphereBuffers() { float radius = 0.5f; int slices = 20; int stacks = 20; std::vector vertices; for (int i = 0; i <= stacks; ++i) { float V = i / (float) stacks; float phi = V * M_PI; for (int j = 0; j <= slices; ++j) { float U = j / (float) slices; float theta = U * (M_PI * 2); float x = cosf(theta) * sinf(phi); float y = cosf(phi); float z = sinf(theta) * sinf(phi); vertices.push_back(x * radius); vertices.push_back(y * radius); vertices.push_back(z * radius); } } glGenVertexArrays(1, &VAO); glGenBuffers(1, &VBO); glBindVertexArray(VAO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, vertices.size() * sizeof(float), vertices.data(), GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); glBindVertexArray(0); } void drawSphere() { glBindVertexArray(VAO); glDrawArrays(GL_TRIANGLE_STRIP, 0, (20 + 1) * (20 + 1)); glBindVertexArray(0); } void display() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(shaderProgram); // Ustawienie widoku kamery glm::mat4 view = glm::lookAt(glm::vec3(20, 20, 30), glm::vec3(0, 10, 0), glm::vec3(0, 1, 0)); glm::mat4 projection = glm::perspective(glm::radians(45.0f), (float)windowWidth / (float)windowHeight, 0.1f, 100.0f); // Renderowanie każdej z 10 kul for (int i = 0; i < 10; ++i) { Ball &ball = balls[i]; // Uzyskanie dostępu do danej kuli glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(ball.x, ball.y, ball.z)); // Ustawienie macierzy modelu, widoku i projekcji w shaderze GLint modelLoc = glGetUniformLocation(shaderProgram, "model"); GLint viewLoc = glGetUniformLocation(shaderProgram, "view"); GLint projLoc = glGetUniformLocation(shaderProgram, "projection"); glUniformMatrix4fv(modelLoc, 1, GL_FALSE, glm::value_ptr(model)); glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); glUniformMatrix4fv(projLoc, 1, GL_FALSE, glm::value_ptr(projection)); // Ustawienie koloru kuli w shaderze GLint colorLoc = glGetUniformLocation(shaderProgram, "color"); glUniform3f(colorLoc, ball.r, ball.g, ball.b); drawSphere(); // Rysowanie kuli } glfwSwapBuffers(glfwGetCurrentContext()); // Przełączanie buforów } void update() { float currentTime = glfwGetTime(); float dt = 0.01f; if (currentTime - startTime >= delay) { for (auto &ball : balls) { rungeKuttaStep(ball, dt); } } } void setupOpenGL() { compileShaders(); setupSphereBuffers(); glEnable(GL_DEPTH_TEST); glClearColor(0.1f, 0.1f, 0.1f, 1.0f); } void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) { if (action == GLFW_PRESS) { switch (key) { case GLFW_KEY_ESCAPE: glfwSetWindowShouldClose(window, GLFW_TRUE); break; } } } int main() { if (!glfwInit()) { std::cerr << "Failed to initialize 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(windowWidth, windowHeight, "Animacja 10 kul - Rzut ukośny", nullptr, nullptr); if (!window) { std::cerr << "Failed to create GLFW window" << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glfwSetKeyCallback(window, keyCallback); // Rejestracja callbacku klawiatury glewExperimental = GL_TRUE; if (glewInit() != GLEW_OK) { std::cerr << "Failed to initialize GLEW" << std::endl; return -1; } initializeBalls(); setupOpenGL(); while (!glfwWindowShouldClose(window)) { display(); update(); glfwPollEvents(); } glDeleteVertexArrays(1, &VAO); glDeleteBuffers(1, &VBO); glDeleteProgram(shaderProgram); glfwDestroyWindow(window); glfwTerminate(); return 0; }