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);