From 9bff8a1d0dcc8070273381d0c47b95f9cf914d19 Mon Sep 17 00:00:00 2001 From: Jakub-Prus <68164819+Jakub-Prus@users.noreply.github.com> Date: Mon, 13 Feb 2023 08:02:41 +0100 Subject: [PATCH] boids --- cw 9/grk-cw9.vcxproj | 1 + cw 9/grk-cw9.vcxproj.filters | 35 ++++--- cw 9/src/Fish.cpp | 70 +++++++++++++ cw 9/src/Fish.h | 21 ++++ cw 9/src/Predator.h | 13 +++ cw 9/src/Rectangle.h | 13 +++ cw 9/src/Texture1.h | 14 +++ cw 9/src/boids.h | 130 ++++++++++++++++++++++++ cw 9/src/ex_9_1.hpp | 190 ++++++++++++++++++++++++++++++++++- cw 9/src/main.cpp | 3 +- 10 files changed, 471 insertions(+), 19 deletions(-) create mode 100644 cw 9/src/Fish.cpp create mode 100644 cw 9/src/Fish.h create mode 100644 cw 9/src/Predator.h create mode 100644 cw 9/src/Rectangle.h create mode 100644 cw 9/src/Texture1.h create mode 100644 cw 9/src/boids.h diff --git a/cw 9/grk-cw9.vcxproj b/cw 9/grk-cw9.vcxproj index fa1ef85..7e6a998 100644 --- a/cw 9/grk-cw9.vcxproj +++ b/cw 9/grk-cw9.vcxproj @@ -23,6 +23,7 @@ + diff --git a/cw 9/grk-cw9.vcxproj.filters b/cw 9/grk-cw9.vcxproj.filters index c2d95e4..36ba1b6 100644 --- a/cw 9/grk-cw9.vcxproj.filters +++ b/cw 9/grk-cw9.vcxproj.filters @@ -53,21 +53,6 @@ - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - Source Files\SOIL @@ -86,8 +71,26 @@ Source Files\SOIL + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + - Source Files + Header Files + + + Header Files diff --git a/cw 9/src/Fish.cpp b/cw 9/src/Fish.cpp new file mode 100644 index 0000000..412cca1 --- /dev/null +++ b/cw 9/src/Fish.cpp @@ -0,0 +1,70 @@ +#include "Fish.h" +#include "Texture1.h" +#include "Rectangle.h" +#include "glm.hpp" +#include "glew.h" +#include + +Fish::Fish(const glm::vec3& position, const glm::vec3& velocity, Texture* texture) + : m_position(position), m_velocity(velocity), m_texture(texture), m_bounds() {} + + + +void Fish::Update(const std::vector& neighbors, const glm::vec3& target, float dt) { + // W tej funkcji należy zaimplementować algorytm boid. + // neighbors jest wektorem sąsiadujących ryb. + // target jest pozycją drapieżnika, dt jest różnicą czasu między aktualnym i poprzednim klatkami. + + // Pozycja ryby jest aktualizowana na podstawie algorytmu boid. + + glm::vec3 average_position(0.0f, 0.0f, 0.0f); + glm::vec3 average_velocity(0.0f, 0.0f, 0.0f); + int count = 0; + + for (const Fish& neighbor : neighbors) { + if (&neighbor == this) { + continue; + } + + average_position += neighbor.m_position; + average_velocity += neighbor.m_velocity; + ++count; + } + + if (count > 0) { + average_position /= count; + average_velocity /= count; + } + + glm::vec3 center = m_bounds.m_min + (m_bounds.m_max - m_bounds.m_min) * 0.5f; + glm::vec3 avoid = m_position - center; + + m_velocity += (average_position - m_position) * 0.05f + + (average_velocity - m_velocity) * 0.05f + + avoid * 0.05f; + + if (target != glm::vec3(0.0f, 0.0f, 0.0f)) { + m_velocity += (target - m_position) * 0.05f; + } + + m_velocity = glm::normalize(m_velocity); + m_position += m_velocity * dt; + + // Ograniczenie pozycji ryby do prostokąta. + m_position.x = glm::clamp(m_position.x, m_bounds.m_min.x, m_bounds.m_max.x); + m_position.y = glm::clamp(m_position.y, m_bounds.m_min.y, m_bounds.m_max.y); + m_position.z = glm::clamp(m_position.z, m_bounds.m_min.z, m_bounds.m_max.z); +} + +void Fish::Render() const { // W tej funkcji należy zrenderować teksturę ryby w odpowiedniej pozycji. // Można to zrobić na przykład za pomocą biblioteki OpenGL. + + glm::mat4 model(1.0f); model = glm::translate(model, m_position); + + GLuint model_location = glGetUniformLocation(m_shader_program, "model"); glUniformMatrix4fv(model_location, 1, GL_FALSE, &model[0][0]); + + GLuint texture_location = glGetUniformLocation(m_shader_program, "texture_sampler"); glUniform1i(texture_location, 0); + + glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_texture.m_id); + + glBindVertexArray(m_vao); glDrawArrays(GL_TRIANGLES, 0, m_vertex_count); glBindVertexArray(0); +} \ No newline at end of file diff --git a/cw 9/src/Fish.h b/cw 9/src/Fish.h new file mode 100644 index 0000000..5217271 --- /dev/null +++ b/cw 9/src/Fish.h @@ -0,0 +1,21 @@ +#pragma once + +#include "glm.hpp" +#include + +class Texture; + +class Fish { +public: + Fish::Fish(const glm::vec3& position, const glm::vec3& velocity, Texture* texture); + + + void Update(const std::vector& neighbors, const glm::vec3& target, float dt); + void Render(); + +private: + glm::vec3 m_position; + glm::vec3 m_velocity; + Texture* m_texture; + Rectangle m_bounds; +}; \ No newline at end of file diff --git a/cw 9/src/Predator.h b/cw 9/src/Predator.h new file mode 100644 index 0000000..f2b7671 --- /dev/null +++ b/cw 9/src/Predator.h @@ -0,0 +1,13 @@ +#pragma once + +#include "glm.hpp" + +class Predator { +public: + Predator(const glm::vec3& position); + + void Render(); + +private: + glm::vec3 m_position; +}; \ No newline at end of file diff --git a/cw 9/src/Rectangle.h b/cw 9/src/Rectangle.h new file mode 100644 index 0000000..58a2597 --- /dev/null +++ b/cw 9/src/Rectangle.h @@ -0,0 +1,13 @@ +#pragma once + +#include "glm.hpp" + +class Rectangle { +public: + Rectangle(const glm::vec3& min = glm::vec3(0), const glm::vec3& max = glm::vec3(1)); + + bool Contains(const glm::vec3& point) const; + + glm::vec3 m_min; + glm::vec3 m_max; +}; \ No newline at end of file diff --git a/cw 9/src/Texture1.h b/cw 9/src/Texture1.h new file mode 100644 index 0000000..c9baecc --- /dev/null +++ b/cw 9/src/Texture1.h @@ -0,0 +1,14 @@ +#pragma once + +#include "glm.hpp" + +class Rectangle { +public: + Rectangle(const glm::vec3& min, const glm::vec3& max); + + bool Contains(const glm::vec3& point) const; + +private: + glm::vec3 m_min; + glm::vec3 m_max; +}; \ No newline at end of file diff --git a/cw 9/src/boids.h b/cw 9/src/boids.h new file mode 100644 index 0000000..8c547f3 --- /dev/null +++ b/cw 9/src/boids.h @@ -0,0 +1,130 @@ +/*#include +#include +#include + + +//const int WIDTH = 500; +//const int HEIGHT = 500; +const int DEPTH = 600; +const int NUM_BOIDS = 100; +const float BOID_SPEED = 0.01f; +const float BOID_SIZE = 0.50f; + +struct Boid +{ + float x, y, z; + float dx, dy, dz; +}; + +std::vector boids; + +void init() +{ + for (int i = 0; i < NUM_BOIDS; i++) + { + Boid b; + b.x = float(rand()) / RAND_MAX * 2 - 1; + b.y = float(rand()) / RAND_MAX * 2 - 1; + b.z = float(rand()) / RAND_MAX * 2 - 1; + b.dx = float(rand()) / RAND_MAX * BOID_SPEED - BOID_SPEED / 2; + b.dy = float(rand()) / RAND_MAX * BOID_SPEED - BOID_SPEED / 2; + b.dz = float(rand()) / RAND_MAX * BOID_SPEED - BOID_SPEED / 2; + boids.push_back(b); + } +} + +void updateBoids() +{ + for (int i = 0; i < NUM_BOIDS; i++) + { + Boid& b1 = boids[i]; + float avgX = 0; + float avgY = 0; + float avgZ = 0; + int count = 0; + for (int j = 0; j < NUM_BOIDS; j++) + { + if (i == j) + continue; + + Boid& b2 = boids[j]; + float dx = b2.x - b1.x; + float dy = b2.y - b1.y; + float dz = b2.z - b1.z; + float distance = sqrt(dx * dx + dy * dy + dz * dz); + if (distance < BOID_SIZE) + { + b1.dx -= dx / NUM_BOIDS; + b1.dy -= dy / NUM_BOIDS; + b1.dz -= dz / NUM_BOIDS; + } + avgX += b2.dx; + avgY += b2.dy; + avgZ += b2.dz; + count++; + } + avgX /= count; + avgY /= count; + avgZ /= count; + b1.dx += avgX / NUM_BOIDS; + b1.dy += avgY / NUM_BOIDS; + b1.dz += avgZ / NUM_BOIDS; + + b1.x += b1.dx; + b1.y += b1.dy; + b1.z += b1.dz; + + if (b1.x < 0 || b1.x > 1) + b1.dx *= -1; + if (b1.y < 0 || b1.y > 1) + b1.dy *= -1; + if (b1.z < 0 || b1.z > 1) + b1.dz *= -1; + } +} + + +void renderBoids() +{ + for (int i = 0; i < NUM_BOIDS; i++) + { + glBegin(GL_POINTS); + glVertex3f(boids[i].x, boids[i].y, boids[i].z); + glEnd(); + } +} +/* +void display() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glLoadIdentity(); + gluLookAt(0, 0, 1, 0, 0, 0, 0, 1, 0); + updateBoids(); + renderBoids(); + glutSwapBuffers(); +} + +void reshape(int width, int height) +{ + glViewport(0, 0, width, height); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(60, float(width) / height, 1, 100); + glMatrixMode(GL_MODELVIEW); +} + + +int main(int argc, char** argv) +{ + glutInit(&argc, argv); + glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); + glutInitWindowSize(WIDTH, HEIGHT); + glutCreateWindow("Boids"); + glutDisplayFunc(display); + glutReshapeFunc(reshape); + glutIdleFunc(display); + init(); + glutMainLoop(); + return 0; +} +*/ \ No newline at end of file diff --git a/cw 9/src/ex_9_1.hpp b/cw 9/src/ex_9_1.hpp index a67ee34..0341494 100644 --- a/cw 9/src/ex_9_1.hpp +++ b/cw 9/src/ex_9_1.hpp @@ -15,6 +15,19 @@ #include #include #include +#include +#include +#include + + +const int DEPTH = 100; +const int NUM_BOIDS = 20; +const float BOID_SIZE = 0.05f; +const float MAX_SPEED = 0.02f; +const float NEIGHBOR_RADIUS = 0.1f; +const float SEPARATION_WEIGHT = 1.0f; +const float ALIGNMENT_WEIGHT = 1.0f; +const float COHESION_WEIGHT = 1.0f; //const unsigned int SHADOW_WIDTH = 16384, SHADOW_HEIGHT = 16384; const unsigned int SHADOW_WIDTH = 2048, SHADOW_HEIGHT = 2048; @@ -220,6 +233,8 @@ bool animal_in_aquarium = false; float lastTime = -1.f; float deltaTime = 0.f; + + void updateDeltaTime(float time) { if (lastTime < 0) { lastTime = time; @@ -230,6 +245,136 @@ void updateDeltaTime(float time) { if (deltaTime > 0.1) deltaTime = 0.1; lastTime = time; } + + + +struct Boid +{ + float x, y, z; + float vx, vy, vz; +}; + +std::vector boids; + +void initBoids() +{ + for (int i = 0; i < NUM_BOIDS; i++) + { + Boid b; + //b.x = float(rand()) / RAND_MAX * 2 - 1; + b.x = 12; + b.y = 1; + b.z = 4; + b.vx = ((float)rand() / RAND_MAX) * MAX_SPEED * 2.0f - MAX_SPEED; + b.vy = ((float)rand() / RAND_MAX) * MAX_SPEED * 2.0f - MAX_SPEED; + b.vz = ((float)rand() / RAND_MAX) * MAX_SPEED * 2.0f - MAX_SPEED; + boids.push_back(b); + } +} +void updateBoid(Boid& b) { + float separationX = 0.0f, separationY = 0.0f, separationZ = 0.0f; + float alignmentX = 0.0f, alignmentY = 0.0f, alignmentZ = 0.0f; + float cohesionX = 0.0f, cohesionY = 0.0f, cohesionZ = 0.0f; + int numNeighbors = 0; + for (int i = 0; i < NUM_BOIDS; i++) { + Boid b2 = boids[i]; + float dx = b.x - b2.x; + float dy = b.y - b2.y; + float dz = b.z - b2.z; + float dist = sqrt(dx * dx + dy * dy + dz * dz); + if (dist > 0.0f && dist < NEIGHBOR_RADIUS) { + numNeighbors++; + separationX += dx / dist; + separationY += dy / dist; + separationZ += dz / dist; + alignmentX += b2.vx; + alignmentY += b2.vy; + alignmentZ += b2.vz; + cohesionX += b2.x; + cohesionY += b2.y; + cohesionZ += b2.z; + } + } + if (numNeighbors > 0) { + separationX /= (float)numNeighbors; + separationY /= (float)numNeighbors; + separationZ /= (float)numNeighbors; + alignmentX /= (float)numNeighbors; + alignmentY /= (float)numNeighbors; + alignmentZ /= (float)numNeighbors; + cohesionX /= (float)numNeighbors; + cohesionY /= (float)numNeighbors; + cohesionZ /= (float)numNeighbors; + separationX = separationX * SEPARATION_WEIGHT; + separationY = separationY * SEPARATION_WEIGHT; + separationZ = separationZ * SEPARATION_WEIGHT; + alignmentX = alignmentX * ALIGNMENT_WEIGHT; + alignmentY = alignmentY * ALIGNMENT_WEIGHT; + alignmentZ = alignmentZ * ALIGNMENT_WEIGHT; + cohesionX = (cohesionX / (float)numNeighbors - b.x) * COHESION_WEIGHT; + cohesionY = (cohesionY / (float)numNeighbors - b.y) * COHESION_WEIGHT; + cohesionZ = (cohesionZ / (float)numNeighbors - b.z) * COHESION_WEIGHT; + + b.vx += separationX + alignmentX + cohesionX; + b.vy += separationY + alignmentY + cohesionY; + b.vz += separationZ + alignmentZ + cohesionZ; + + float speed = sqrt(b.vx * b.vx + b.vy * b.vy + b.vz * b.vz); + if (speed > MAX_SPEED) { + b.vx = b.vx / speed * MAX_SPEED; + b.vy = b.vy / speed * MAX_SPEED; + b.vz = b.vz / speed * MAX_SPEED; + } + } + + b.x += b.vx; + b.y += b.vy; + b.z += b.vz; + + if (b.x < -1.0f) { + b.vx = abs(b.vx); + } + if (b.x > 4.0f) { + b.vx = -abs(b.vx); + } + if (b.y < -1.0f) { + b.vy = abs(b.vy); + } + if (b.y > 4.0f) { + b.vy = -abs(b.vy); + } + if (b.z < -1.0f) { + b.vz = abs(b.vz); + } + if (b.z > 5.0f) { + b.vz = -abs(b.vz); + } + +} + + +/* +void renderBoids() +{ + float time = glfwGetTime(); + for (int i = 0; i < NUM_BOIDS; i++) + { + + float x = boids[i].x; + float y = boids[i].y; + float z = boids[i].z; + + drawObjectPBRWithTexture(models::fish2Context, + glm::translate(glm::vec3(3.f, 1.0f, 0.45f)) + * glm::rotate(glm::radians(sin(time / 2) * 5.0f), glm::vec3(1.0f, 0.0f, 0.0f)) + * glm::eulerAngleY(time - 12) * glm::translate(glm::vec3(1.2f, 0, 0)) + * glm::scale(glm::vec3(0.2f)) * glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(0, 1, 0)), + texture::fishBlueTexture, + 0.5f, 0.0f, 0); + } +}*/ + + glm::mat4 createCameraMatrix() { glm::vec3 cameraSide = glm::normalize(glm::cross(cameraDir,glm::vec3(0.f,1.f,0.f))); @@ -446,8 +591,24 @@ void renderShadowapSun(GLuint depthMapFBO, glm::mat4 lightVP) { * glm::eulerAngleY(time - 11) * glm::translate(glm::vec3(1.2f, 0, 0)) * glm::scale(glm::vec3(0.2f)) * glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(0, 1, 0)) ); + + for (int i = 0; i < NUM_BOIDS; i++) + { + + float x = boids[i].x; + float y = boids[i].y; + float z = boids[i].z; + + drawObjectDepth(models::fish2Context, lightVP, + glm::translate(glm::vec3(x, y, z)) + //*glm::rotate(glm::radians(sin(time / 2 + 23) * 5.0f), glm::vec3(1.0f, 0.0f, 0.0f)) + //* glm::eulerAngleY(time - 11)* glm::translate(glm::vec3(1.2f, 0, 0)) + //* glm::scale(glm::vec3(0.2f))* glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(0, 1, 0)) + ); + } ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// glBindFramebuffer(GL_FRAMEBUFFER, 0); + glViewport(0, 0, WIDTH, HEIGHT); } @@ -682,13 +843,29 @@ void renderScene(GLFWwindow* window) drawObjectPBRWithTexture(models::aquariumContext, glm::mat4(), texture::aquariumTexture, 0.8f, 0.0f, 5); drawObjectPBRWithTexture(models::glassWindowContext, glm::mat4(), texture::glassWallTexture, 0.5f, 0.0f, 5); + for (int i = 0; i < NUM_BOIDS; i++) + { + float x = boids[i].x; + float y = boids[i].y; + float z = boids[i].z; - + drawObjectPBRWithTexture(models::fish2Context, + glm::translate(glm::vec3(x, y, z)), + //* glm::rotate(glm::radians(sin(time / 2) * 5.0f), glm::vec3(1.0f, 0.0f, 0.0f)) + //* glm::eulerAngleY(time - 12) * glm::translate(glm::vec3(1.2f, 0, 0)) + //* glm::scale(glm::vec3(0.2f)) * glm::rotate(glm::mat4(1.0f), glm::radians(180.0f), glm::vec3(0, 1, 0)), + texture::fishGreenTexture, + 0.5f, 0.0f, 0); + } + for (int i = 0; i < NUM_BOIDS; i++) { + updateBoid(boids[i]); + } //Terraingen(); + //test depth buffer /*glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glUseProgram(programTest); @@ -700,6 +877,8 @@ void renderScene(GLFWwindow* window) glfwSwapBuffers(window); } + + void framebuffer_size_callback(GLFWwindow* window, int width, int height) { aspectRatio = width / float(height); @@ -985,9 +1164,18 @@ void processInput(GLFWwindow* window) void renderLoop(GLFWwindow* window) { while (!glfwWindowShouldClose(window)) { + //glClear(GL_COLOR_BUFFER_BIT); + + //updateBoids(); + //renderBoids(); + + //glfwSwapBuffers(window); processInput(window); renderScene(window); glfwPollEvents(); + + } + } //} \ No newline at end of file diff --git a/cw 9/src/main.cpp b/cw 9/src/main.cpp index 5a7fdc4..31fbe68 100644 --- a/cw 9/src/main.cpp +++ b/cw 9/src/main.cpp @@ -39,9 +39,8 @@ int main(int argc, char** argv) glViewport(0, 0, 500, 500); init(window); - + initBoids(); // uruchomienie glownej petli - renderLoop(window); shutdown(window);